SQLMap的前世今生(Part1)
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>
clause與where屬性
這兩個元素的作用是限制boundary所使用的範圍,可以理解成當且僅當某個boundary元素的where節點的值包含test元素的子節點,clause節點的值包含test元素的子節點的時候,該boundary才能和當前的test匹配,從而進一步生成payload。
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 >= 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<result>.*?)[DELIMITER_STOP]</grep>
</response>
<details>
<dbms>MySQL</dbms>
<dbms_version>>= 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<result>.*?)[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
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
如下為返回的頁面資訊
後根據grep中的正規來匹配當前頁面。
#!sql
<grep>[DELIMITER_START](?P<result>.*?)[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掃描工具。
相關文章
- SQLMAP的前世今生Part2 資料庫指紋識別2020-08-19SQL資料庫
- MySQL 的前世今生2020-02-13MySql
- 遊戲的前世今生2019-12-23遊戲
- Mybatis的前世今生2019-04-19MyBatis
- IPD的前世今生2021-09-23
- RabbitMQ的前世今生2018-12-06MQ
- Serverless 的前世今生2022-11-24Server
- JavaScript的前世今生2016-11-27JavaScript
- WebP 的前世今生2017-11-08Web
- RunLoop的前世今生2017-12-19OOP
- Webpack前世今生2020-07-22Web
- Unicode的前世今生2019-02-20Unicode
- HTTP/2.0的前世今生2019-03-14HTTP
- 元件化的前世今生2021-09-09元件化
- React ref 的前世今生2018-07-26React
- 外掛的前世今生2020-12-20
- Https的前世今生2018-01-31HTTP
- React Portal的前世今生2018-03-13React
- Android的前世今生2014-03-07Android
- React Mixin 的前世今生2015-11-23React
- Serverless For Frontend 前世今生2019-08-15Server
- 一、MySQL前世今生2017-07-24MySql
- 資料庫的前世今生2020-04-06資料庫
- iOS Device ID 的前世今生2019-03-01iOSdev
- 前端模組化的前世今生2019-04-03前端
- Redux的前世-今生-來世2019-03-03Redux
- HTTP 協議的前世今生2021-02-19HTTP協議
- JavaScript – 非同步的前世今生2018-08-16JavaScript非同步
- JavaScript 包管理的前世今生2017-08-04JavaScript
- 物聯網的前世今生2014-09-01
- ORACLE ERP 的前世今生2011-04-28Oracle
- LangChain和Hub的前世今生2024-06-26LangChain
- JavaScript 模組化前世今生2019-12-17JavaScript
- 對話系統的前世今生2018-07-17
- Apache Hudi和Presto的前世今生2020-09-22ApacheREST
- SAP UI5 的前世今生2022-03-05UI
- PYTHON編碼的前世今生2016-10-09Python
- 新零售的前世今生2018-07-10