SQLMAP進階使用

wyzsk發表於2020-08-19
作者: MayIKissYou · 2015/03/17 10:34

0x00 背景


首先在drops上搜尋下sqlmap相關的文章:

介紹的比較全了,但是對於sqlmap的指令碼擴充套件部分沒有提及,例如自定義payload,自定義繞過指令碼等等。

0x02 自定義payload指令碼


2.1 需求


我們先寫一個比較全的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即可。

2.2 說明


Sqlmap在執行之後會載入讀取xml檔案,並且將結果儲存到conf.tests中,如下圖:

enter image description here

這部分payload會在會在checkSqlInjection中使用:

enter image description here

接下來只要知道如何使用這部分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的格式如下圖內容:

enter image description here

其中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標籤。基本上理解並設計好這些標籤,就能夠自定義指令碼了。

2.3 實現


Sqlmap的相關payload在目錄./sqmap/xml/payloads/目錄下,新版目錄下會有一個payloads的目錄,裡面有各種型別的sql注入的payload,選取盲注的xml,在其中編寫一個test節點,內容如下圖:

enter image description here

(相關引數的解釋在後面描述)

然後自己建立一個存在order by 1 [desc]這種型別sql注入的php頁面:

enter image description here

這時候用我們修改過的sqlmap去傳送,檢視結果:

enter image description here

0x03 自定義bypass指令碼


3.1 需求


在./sqlmap/tamper目錄下,設計了很多的指令碼,這些指令碼是用來對於請求的payload進行修改的,但是往往有一些情況這些預定義的指令碼不能夠滿足我們的需求,例如有一些waf對於逗號進行了過濾,又如有時候我們需要使用%a0去替換payload中的空白等等情況。這時候就需要我們自己新增指令碼來完成工作了。

3.2 說明


要知道如何新增自定義指令碼,我們需要了解的是

第一:tamper指令碼是什麼時候被sqlmap載入的; 
第二:tamper指令碼是什麼時候被sqlmap呼叫的; 
第三:tamper指令碼的裡的內容有什麼樣的規範;

問題一:tamper指令碼是什麼時候被sqlmap載入的

我們去看一下sqlmap的原始碼,大致邏輯是這樣

main()->init()->_setTamperingFunctions()

_setTamperingFunctions函式中載入了我們配置的tamper函式。然後會把tamper函式新增到了kb.tamperFunctions裡面以被後續使用。

這樣看來要自定義的話這個指令碼中得有個tamper函式,然後就是編寫tamper函式的內

enter image description here

問題二:tamper指令碼是什麼時候被sqlmap呼叫的

tamper指令碼在queryPage函式中被呼叫,queryPage函式是用來請求頁面內容,在每次傳送請求之前,先會將payload進行tamper函式處理。下圖為呼叫between.py的指令碼。

enter image description here

問題三:tamper指令碼的裡的內容有什麼樣的規範

我們隨機選擇一個指令碼,該指令碼為base64encode.py,檢視指令碼中的tamper內容:

enter image description here

可以看到內容非常簡單,將payload的內容內容做了base64編碼然後直接返回。Tamper有兩個引數第一個引數payload即為傳入的實際要操作的payload,第二個引數**kwargs為相關httpheader。譬如你想插入或則修改header的時候可以用到。

邏輯流程弄清楚之後,很容易編寫自己的tamper指令碼了。

3.3 實現


以使用%a0替換空格的指令碼為例,在tamper目錄下建立space2ao.py指令碼,稍微修改下指令碼:

enter image description here

使用sqlmap傳送請求,去檢視下web日誌:

enter image description here

Ps.感覺很容易的樣子,這裡不演示如何bypass逗號的情況,下面換一個方式來使sqlmap bypass逗號被過濾的情況。

0x04 自定義query函式


在做測試的時候往往還會有一些情況,如mid函式被過濾了,逗號被過濾了等等。Sqlmap是機器操作,如果被過濾了一些函式,指令碼肯定就無法走後面的流程了。此時我們可以直接修改相關的querystring(xml中的相關內容),如我們可以將substr(expression,start,length)替換成substr(expression from start for length)

這些內容在sqlmap/xml目錄下的queries.xml目錄中。截圖下mysql標籤中的一些內容:

enter image description here

這個inference看起來就是用來猜欄位用的,而且之前我們在第一篇自定義過這個[inference欄位的],是不是我們將

ord(mid((%s),%d,1))>%d

更換為

ord(mid((%s) from %d for1))>%d

就可以了呢。

我們修改之後,跟蹤下payload的值是否更改了:

enter image description here

檢視下是否能夠爆出密碼:

enter image description here

檢視下web日誌,是否是傳送的那樣,解碼之後結果可以看到mid的逗號已經被修改。

enter image description here

這樣我們就可以讓mid函式沒有逗號了。其他的可以參考去修改queries中的相關內容就可以了。

0x05 防禦sqlmap


經過一番折騰,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的值為一個十個隨機字元的長度字串,其中至少包含',隨機字串的內容在('"', "'", ')', '(', '[', ']', ',', '.')裡。

這樣的規律是可以使用正規表示式寫出規則的,而且重複的機率應該不高,可以起到一定的防禦效果。

0x06 結尾


文章主要是對於最近學習的一個總結,用過之後感覺sqlmap的強大之處。對於現在自動化掃描的工具越來越多,sql自動掃描肯定也是被重視的地方。一來如何能夠識別更多的url,二來如何提高sql的識別準確率和效率,這些都是必須要考慮的地方。Sqlmap是個很厲害的工具,我們需要更好的使用它。

本文章來源於烏雲知識庫,此映象為了方便大家學習研究,文章版權歸烏雲知識庫!

相關文章