<dd id="sga4y"><optgroup id="sga4y"></optgroup></dd>
<nav id="sga4y"><code id="sga4y"></code></nav>
  • <optgroup id="sga4y"></optgroup>

    原文地址:http://drops.wooyun.org/tips/5254

    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是個很厲害的工具,我們需要更好的使用它。

    97av