Mysql報錯注入之floor報錯詳解


一、簡述

 

利用 select count(*),(floor(rand(0)*2))x from table group by x,導致數據庫報錯,通過 concat 函數,連接注入語句與 floor(rand(0)*2)函數,實現將注入結果與報錯信息回顯的注入方式。

基本的查詢 select 不必多說,剩下的幾個關鍵字有 count 、group by 、floor、rand。

二、關鍵函數說明

 

1.rand函數

rand() 可以產生一個在0和1之間的隨機數。

可見,直接使用rand函數每次產生的數都不同,但是當提供了一個固定的隨機數的種子0之后:

每次產生的值都是一樣的。也可以稱之為偽隨機(產生的數據都是可預知的)。
查看多個數據看一下。(users是一個有6行數據的表)

這樣第一次產生的隨機數和第二次完全一樣,也就是可以預測的。
利用的時候rand(0)*2為什么要乘以 2 呢?這就要配合 floor 函數來說了。

 

2.floor(rand(0)*2)函數

floor() 函數的作用就是返回小於等於括號內該值的最大整數。

而rand() 是返回 0 到 1 之間的隨機數,那么floor(rand(0))產生的數就只是0,這樣就不能實現報錯的:

而rand產生的數乘 2 后自然是返回 0 到 2 之間的隨機數,再配合 floor() 就可以產生確定的兩個數了。也就是 0 和 1:

並且根據固定的隨機數種子0,他每次產生的隨機數列都是相同的0 1 1 0 1 1。

 

3.group by 函數

group by 主要用來對數據進行分組(相同的分為一組)。

還是按照下表進行實驗

首先我們在查詢的時候是可以使用as用其他的名字代替顯示的:

但是在實際中可以缺省as直接查詢,顯示的結果是一樣的:

然后就可以用group by函數進行分組,並按照x進行排序

注意:最后x這列中顯示的每一類只有一次,前面的a的是第一次出現的id值

 

 

4.count(*)函數

count(*)統計結果的記錄數。

這里與group by結合使用看一下:

這里就是對重復性的數據進行了整合,然后計數,后面的x就是每一類的數量。

 

5.綜合使用產生報錯:

select count(*),floor(rand(0)*2) x from users group by x;

根據前面函數,這句話就是統計后面產生隨機數的種類並計算每種數量。

分別產生0 1 1 0 1 1 ,這樣0是2個,1是4個,但是最后卻產生了報錯。

 

三、報錯分析

 

這個整合然后計數的過程中,中間發生了什么我們是必須要明白的。
首先mysql遇到該語句時會建立一個虛擬表。該虛擬表有兩個字段,一個是分組的 key ,一個是計數值 count(*)。也就對應於實驗中的 user_name 和 count(*)。
然后在查詢數據的時候,首先查看該虛擬表中是否存在該分組,如果存在那么計數值加1,不存在則新建該分組。

然后mysql官方有給過提示,就是查詢的時候如果使用rand()的話,該值會被計算多次,那這個"被計算多次"到底是什么意思,就是在使用group by的時候,floor(rand(0)*2)會被執行一次,如果虛表不存在記錄,插入虛表的時候會再被執行一次,我們來看下floor(rand(0)*2)報錯的過程就知道了,從上面的函數使用中可以看到在一次多記錄的查詢過程中floor(rand(0)*2)的值是定性的,為011011 (這個順序很重要),報錯實際上就是floor(rand(0)*2)被計算多次導致的,我們還原一下具體的查詢過程:

 

(1)查詢前默認會建立空虛擬表如下圖:

(2)取第一條記錄,執行floor(rand(0)*2),發現結果為0(第一次計算),

(3)查詢虛擬表,發現0的鍵值不存在,則插入新的鍵值的時候floor(rand(0)*2)會被再計算一次,結果為1(第二次計算),插入虛表,這時第一條記錄查詢完畢,如下圖:

(4)查詢第二條記錄,再次計算floor(rand(0)*2),發現結果為1(第三次計算)

(5)查詢虛表,發現1的鍵值存在,所以floor(rand(0)*2)不會被計算第二次,直接count(*)加1,第二條記錄查詢完畢,結果如下:

(6)查詢第三條記錄,再次計算floor(rand(0)*2),發現結果為0(第4次計算)

(7)查詢虛表,發現鍵值沒有0,則數據庫嘗試插入一條新的數據,在插入數據時floor(rand(0)*2)被再次計算,作為虛表的主鍵,其值為1(第5次計算),

然而1這個主鍵已經存在於虛擬表中,而新計算的值也為1(主鍵鍵值必須唯一),所以插入的時候就直接報錯了。

 

四、總結

 

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

另外,要注意加入隨機數種子的問題,如果沒加入隨機數種子或者加入其他的數,那么floor(rand()*2)產生的序列是不可測的,這樣可能會出現正常插入的情況。最重要的是前面幾條記錄查詢后不能讓虛表存在0,1鍵值,如果存在了,那無論多少條記錄,也都沒辦法報錯,因為floor(rand()*2)不會再被計算做為虛表的鍵值,這也就是為什么不加隨機因子有時候會報錯,有時候不會報錯的原因。

比如下面用1作為隨機數種子,就不會產生報錯:


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM