首先在drops上搜索下sqlmap相關的文章:
介紹的比較全了,但是對于sqlmap的腳本擴展部分沒有提及,例如自定義payload,自定義繞過腳本等等。
我們先寫一個比較全的select語句:
#!sql
select * from users where user_id in(1,2,3,[4]) and first_name like '%[t]%' and second_name=[’b’] group by [first_name] order by [1] [desc] limit [1]
語句中[]中的內容都是查詢中可能存在的注入點。
那么問題來了:
1):這些注入點里面哪些是sqlmap在默認level下就能夠識別的?
2):不能夠在默認級別下識別的注入點,sqlmap在level=多少的時候能否識別?
3):sqlmap識別不了的時候怎么辦?
以order by類型的注入來看,order by [1][1]
這個參數在設置level=3的時候會被sqlmap檢測出來(這里需要注意的在01_boolean_blind.xml
文件中,如果level字段設置的是2,在測試的時候需要設置比level高的才可以被識別,如rlike order by
注入設置的level值為2,我在命令行使用sqlmap參數的時候需要設置level=3)
但是order by 1 [desc]
,在設置level=3的時候也無法識別,也許你會說添加suffix和prefix就可以了,確實是這樣,但是現在的選手一般都會選擇開web代理,然后調用sqlmap接口去檢查,因此這里對于sqlmap的要求就高了.
第一:sqlmap要能夠檢測出url的參數存在注入點;
第二:測試的效率要高[不能夠將level設置的很高];設置level高的情況下,會有更多的請求。
現在看來自己將payload編寫為sqlmap可用的payload即可。
Sqlmap在運行之后會加載讀取xml文件,并且將結果保存到conf.tests中,如下圖:
這部分payload會在會在checkSqlInjection中使用:
接下來只要知道如何使用這部分payload以及xml中各個字段是什么意思即可。
首先詳細看一下payload中字段:
title字段:payload test起的名字; 譬如我們給自己的payload起的名字為:
#!sql
MySQL boolean-based blind - WHERE, HAVING, ORDER BY or GROUP BY clause (desc-mayikissu)
style字段:sql注入的類型sql注入分了如下類型:
類型1:盲注 我們order by類型屬于盲注,因此我們添加stype的值為1.
類型2:錯誤類型注入
類型3:內聯注入
類型4:多語句查詢注入
類型5:時間注入
類型6:聯合查詢注入
level字段:sqlmap對于每一個payload都有一個level級別,level級別越高表示檢查的payload個數就越多。 譬如我們自定義個level設計的為2,因此只有在使用在命令行使用level》2的時候,才會使用我們的payload進行檢測。
risk字段:風險等級,有多大幾率獲取破壞數據。值有1,2,3,分別表示低中高。默認的risk為1,默認檢測所有風險級別的payload。 該字段影響不大。
clause字段:payload在哪個語句里生效,差不多意思就是這個payload用在sql語句的哪個位置。可用的值:
0: Always
1: WHERE / HAVING
2: GROUP BY
3: ORDER BY
4: LIMIT
5: OFFSET
6: TOP
7: Table name
8: Column name
我們這里測試的是order by,此處clause的字段設置為3,經過測試這里的值可以混用的,關鍵看sql語法。
where字段:
where字段我理解的意思是,以什么樣的方式將我們的payload添加進去。
1:表示將我們的payload直接添加在值得后面[此處指的應該是檢測的參數的值] 如我們寫的參數是id=1,設置<where>
值為1的話,會出現1后面跟payload
2:表示將檢測的參數的值更換為一個整數,然后將payload添加在這個整數的后面。 如我們寫的參數是id=1,設置<where>
值為2的話,會出現[數字]
后面跟payload
3:表示將檢測的參數的值直接更換成我們的payload。 如我們寫的參數是id=1,設置<where>
值為3的話,會出現值1直接被替換成了我們的payload。
我們的場景是order by 1 [desc]
,此處我們直接將desc更換成我們的payload即可。
vector字段: vector字段表示的是payload向量,類似于一個模型的感覺。
#!sql
,IF([INFERENCE],[ORIGVALUE],(select 1 from information_schema.tables))
此處為我設置的vector,INFERENCE為條件,ORIGVALUE為參數原始的值,如我傳入的id=1或者desc,1和desc即為原始值,此處無所謂,在我的場景里只要為一個值即可。
request和response理解為請求的時候payload值,以及請求的值與什么樣的值進行對比。 請求的payload為:
#!sql
,IF([RANDNUM]=[RANDNUM],[ORIGVALUE],(select 1 from information_schema.tables))
響應的對比payload為:
#!sql
,IF([RANDNUM]=[RANDNUM1],[ORIGVALUE],(select 1 from information_schema.tables))
大致理解就是對比if條件不等和相等,如此來進行盲注。
了解這些參數之后,接下來我們需要知道sqlmap如何將這樣自定義的payload組合起來即可。于是我們跟蹤一下checksqlinjection這個函數,即可知道sqlmap是如何將payload組合起來的了。
在函數中有一個重要的參數,boundary參數,這個參數是從xml目錄下的boundaries.xml文件中讀取出來的。每個boundary的格式如下圖內容:
其中level,clause以及where表達的意思和payload中相關標簽表達的意思是一樣的。 標簽ptype表示參數的類型,prefix表示添加內容的前綴,suffix表示添加內容的后綴。
核心的部分是獲取payloads.xml中的每一個payload,然后獲取payload中的參數與boundary.xml中獲取的參數進行比較。大致流程如下:
獲取payload.xml文件中的每一個payload。
獲取boundary.xml文件中的每一個boundary。
比較判斷payload中的clause是否包含在boundary的clause中,如果有就繼續,如果沒有就直接跳出。
比較判斷payload中的where是否包含在boundary的clause中,如果有就繼續,如果沒有就直接跳出。
將prefix和suffix與payload中的request標簽的內容拼接起來保存到boundpayload中。
最后就是發送請求,然后將結果進行比較了。
Ps.因此我們在設計自定義腳本的時候需要注意的幾個地方,payload中的clause標簽,level標簽,where標簽,vector標簽以及reqeust和response標簽。基本上理解并設計好這些標簽,就能夠自定義腳本了。
Sqlmap的相關payload在目錄./sqmap/xml/payloads/目錄下,新版目錄下會有一個payloads的目錄,里面有各種類型的sql注入的payload,選取盲注的xml,在其中編寫一個test節點,內容如下圖:
(相關參數的解釋在后面描述)
然后自己創建一個存在order by 1 [desc]
這種類型sql注入的php頁面:
這時候用我們修改過的sqlmap去發送,查看結果:
在./sqlmap/tamper目錄下,設計了很多的腳本,這些腳本是用來對于請求的payload進行修改的,但是往往有一些情況這些預定義的腳本不能夠滿足我們的需求,例如有一些waf對于逗號進行了過濾,又如有時候我們需要使用%a0去替換payload中的空白等等情況。這時候就需要我們自己添加腳本來完成工作了。
要知道如何添加自定義腳本,我們需要了解的是
第一:tamper腳本是什么時候被sqlmap載入的;
第二:tamper腳本是什么時候被sqlmap調用的;
第三:tamper腳本的里的內容有什么樣的規范;
我們去看一下sqlmap的源碼,大致邏輯是這樣
main()->init()->_setTamperingFunctions()
在_setTamperingFunctions
函數中加載了我們配置的tamper函數。然后會把tamper函數添加到了kb.tamperFunctions
里面以被后續使用。
這樣看來要自定義的話這個腳本中得有個tamper函數,然后就是編寫tamper函數的內
tamper腳本在queryPage函數中被調用,queryPage函數是用來請求頁面內容,在每次發送請求之前,先會將payload進行tamper函數處理。下圖為調用between.py的腳本。
我們隨機選擇一個腳本,該腳本為base64encode.py,查看腳本中的tamper內容:
可以看到內容非常簡單,將payload的內容內容做了base64編碼然后直接返回。Tamper有兩個參數第一個參數payload即為傳入的實際要操作的payload,第二個參數**kwargs為相關httpheader。譬如你想插入或則修改header的時候可以用到。
邏輯流程弄清楚之后,很容易編寫自己的tamper腳本了。
以使用%a0替換空格的腳本為例,在tamper目錄下創建space2ao.py腳本,稍微修改下腳本:
使用sqlmap發送請求,去查看下web日志:
Ps.感覺很容易的樣子,這里不演示如何bypass逗號的情況,下面換一個方式來使sqlmap bypass逗號被過濾的情況。
在做測試的時候往往還會有一些情況,如mid函數被過濾了,逗號被過濾了等等。Sqlmap是機器操作,如果被過濾了一些函數,腳本肯定就無法走后面的流程了。此時我們可以直接修改相關的querystring(xml中的相關內容),如我們可以將substr(expression,start,length)
替換成substr(expression from start for length)
。
這些內容在sqlmap/xml
目錄下的queries.xml目錄中。截圖下mysql標簽中的一些內容:
這個inference看起來就是用來猜字段用的,而且之前我們在第一篇自定義過這個[inference字段的],是不是我們將
ord(mid((%s),%d,1))>%d
更換為
ord(mid((%s) from %d for1))>%d
就可以了呢。
我們修改之后,跟蹤下payload的值是否更改了:
查看下是否能夠爆出密碼:
查看下web日志,是否是發送的那樣,解碼之后結果可以看到mid的逗號已經被修改。
這樣我們就可以讓mid函數沒有逗號了。其他的可以參考去修改queries中的相關內容就可以了。
經過一番折騰,sqlmap可以比想象中更厲害了呢,目前為止很多選手都會用著sqlmap的插件,或者是原版的sqlmap,亦或是修過過的sqlmap。如何防御sqlmap呢:
1):大眾的防御方法,sqlmap在發送請求的時候,http的user-agent都會自帶sqlmap的,可以做協議解析之后,獲取user-agent,然后來判斷。不過很多測試選手都會使用sqlmap的參數對其進行修改。
2):之前調試程序的時候看到過如下內容(之前在zone里發表過):
http://127.0.0.1?id=1..]"')[.]"?
于是就跑去看了看sqlmap的源碼:
發現在checks.py的文件里面有一個函數名稱為heuristicCheckSqlInjection() 里面有段代碼:
#!python
while '\'' not in randStr:
randStr = randomStr(length=10, alphabet=HEURISTIC_CHECK_ALPHABET)
然后我們去查看randomStr,此函數在common.py下,相關代碼如下:
#!python
def randomStr(length=4, lowercase=False, alphabet=None):
"""
Returns random string value with provided number of characters
>>> random.seed(0)
>>> randomStr(6)
'RNvnAv'
"""
if alphabet:
retVal = "".join(random.choice(alphabet) for _ in xrange(0, length))
elif lowercase:
retVal = "".join(random.choice(string.ascii_lowercase) for _ in xrange(0, length))
else:
retVal = "".join(random.choice(string.ascii_letters) for _ in xrange(0, length))
return retVal
然后去查看了HEURISTIC_CHECK_ALPHABET
,值為('"', "'", ')', '(', '[', ']', ',', '.')
因此得到這樣的結論,這串randStr的值為一個十個隨機字符的長度字符串,其中至少包含',隨機字符串的內容在('"', "'", ')', '(', '[', ']', ',', '.')
里。
這樣的規律是可以使用正則表達式寫出規則的,而且重復的概率應該不高,可以起到一定的防御效果。
文章主要是對于最近學習的一個總結,用過之后感覺sqlmap的強大之處。對于現在自動化掃描的工具越來越多,sql自動掃描肯定也是被重視的地方。一來如何能夠識別更多的url,二來如何提高sql的識別準確率和效率,這些都是必須要考慮的地方。Sqlmap是個很厲害的工具,我們需要更好的使用它。