mysql的floor()報錯注入方法詳細分析


剛開始學習sql注入,遇見了 select count(*) from table group by floor(rand(0)*2); 這么條語句。在此做個總結。
(更好的閱讀體驗可訪問 這里 )

首先,只要該語句明白了,那么類似select count(*),(floor(rand(0)*2))x from table group by x;這樣的變形語句基本上都可以變通(這里只是起了個別名)。
基本的查詢 select 不必多說,剩下的幾個關鍵字有 count 、group by 、floor、rand。

幾個關鍵函數的說明

rand(0)*2

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

可見,每次產生的都不一樣。當我們提供一個種子參數 0 后,再次查看:

可以發現,每次產生的值都是一樣的。也可以稱之為偽隨機(產生的數據都是可預知的)。
查看多個數據看一下。( test 是我之前創建的一個擁有9條數據的表)

發現第一條數據與剛才查看的單個數據相符合,其它的數據也完全一樣。
為什么要乘以 2 呢?這就要配合 floor 函數來說了。

floor(rand(0)*2)

floor() 返回小於等於該值的最大整數。
之前我們了解到,rand() 是返回 0 到 1 之間的隨機數,那么乘 2 后自然是返回 0 到 2 之間的隨機數,再配合 floor() 就可以產生確定的兩個數了。也就是 0 和 1。

為什么需要這兩個數呢?

group by 與 count(*)

group by 主要用來對數據進行分組(相同的分為一組),這里與count() 結合使用。舉個例子就一目了然了。

可以觀察到,這里對重復性數據進行了整合,然后計數。

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

報錯分析

rand()的特殊性

select count(*) from test group by floor(rand(0)*2);

而又因為 rand 函數的特殊性(如果使用rand()的話,該值會被計算多次)。
在這里的意思就是,group by 進行分組時,floor(rand(0)*2)執行一次(查看分組是否存在),如果虛擬表中不存在該分組,那么在插入新分組的時候 floor(rand(0)*2) 就又計算了一次。(其實在上述 rand(0) 產生多個數據的時候,也能觀察出來。只要 rand(0) 被調用,一定會產生新值)。

這樣,所有的理論細節就全部明朗了。

報錯

還記得我們之前產生的疑問,為什么要用 floor(rand(0)*2 產生 0 和 1 這兩個數嗎?

當 group by 對其進行分組的時候,首先遇到第一個值 0 ,發現 0 不存在,於是需要插入分組,就在這時,floor(rand(0)*2)再次被觸發,生成第二個值 1 ,因此最終插入虛擬表的也就是第二個值 1 ;然后遇到第三個值 1 ,因為已經存在分組 1 了,就直接計數加1(這時1的計數變為2);遇到第四個值 0 的時候,發現 0 不存在,於是又需要插入新分組,然后floor(rand(0)*2)又被觸發,生成第五個值 1 ,因此這時還是往虛擬表里插入分組 1 ,但是,分組 1 已經存在了!所以報錯!

總結

可見,floor(rand(0)*2的作用就是產生預知的數字序列01101,然后再利用 rand() 的特殊性和group by的虛擬表,最終引起了報錯。

參考:Mysql報錯注入原理分析(count()、rand()、group by)


免責聲明!

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



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