Mysql報錯注入之floor報錯詳解
updatexml extractvalue
floor 是mysql的函數(shù)
groupby+rand+floor+count
一、簡述
利用 select count(*),(floor(rand(0)*2))x from table group by x,導(dǎo)致數(shù)據(jù)庫報錯,通過 concat 函數(shù),連接注入語句與 floor(rand(0)*2)函數(shù),實現(xiàn)將注入結(jié)果與報錯信息回顯的注入方式。
基本的查詢 select 不必多說,剩下的幾個關(guān)鍵字有 count 、group by 、floor、rand。
二、關(guān)鍵函數(shù)說明
1.rand函數(shù)
rand() 可以產(chǎn)生一個在0和1之間的隨機數(shù)。
可見,直接使用rand函數(shù)每次產(chǎn)生的數(shù)都不同,但是當(dāng)提供了一個固定的隨機數(shù)的種子0之后:
每次產(chǎn)生的值都是一樣的。也可以稱之為偽隨機(產(chǎn)生的數(shù)據(jù)都是可預(yù)知的)。
查看多個數(shù)據(jù)看一下。(users是一個有6行數(shù)據(jù)的表)
這樣第一次產(chǎn)生的隨機數(shù)和第二次完全一樣,也就是可以預(yù)測的。
利用的時候rand(0)*2為什么要乘以 2 呢?這就要配合 floor 函數(shù)來說了。
2.floor(rand(0)*2)函數(shù)
floor() 函數(shù)的作用就是返回小于等于括號內(nèi)該值的最大整數(shù)。
而rand() 是返回 0 到 1 之間的隨機數(shù),那么floor(rand(0))產(chǎn)生的數(shù)就只是0,這樣就不能實現(xiàn)報錯的:
而rand產(chǎn)生的數(shù)乘 2 后自然是返回 0 到 2 之間的隨機數(shù),再配合 floor() 就可以產(chǎn)生確定的兩個數(shù)了。也就是 0 和 1:
并且根據(jù)固定的隨機數(shù)種子0,他每次產(chǎn)生的隨機數(shù)列都是相同的0 1 1 0 1 1。
3.group by 函數(shù)
group by 主要用來對數(shù)據(jù)進行分組(相同的分為一組)。
還是按照下表進行實驗
首先我們在查詢的時候是可以使用as用其他的名字代替顯示的:
但是在實際中可以缺省as直接查詢,顯示的結(jié)果是一樣的:
然后就可以用group by函數(shù)進行分組,并按照x進行排序
注意:最后x這列中顯示的每一類只有一次,前面的a的是第一次出現(xiàn)的id值
4.count(*)函數(shù)
count(*)統(tǒng)計結(jié)果的記錄數(shù)。
這里與group by結(jié)合使用看一下:
這里就是對重復(fù)性的數(shù)據(jù)進行了整合,然后計數(shù),后面的x就是每一類的數(shù)量。
5.綜合使用產(chǎn)生報錯:
select count(*),floor(rand(0)*2) x from users group by x;
0 1 1 0 1 1
0 2
1 4
根據(jù)前面函數(shù),這句話就是統(tǒng)計后面產(chǎn)生隨機數(shù)的種類并計算每種數(shù)量。
分別產(chǎn)生0 1 1 0 1 1 ,這樣0是2個,1是4個,但是最后卻產(chǎn)生了報錯。
0 2
1 4
三、報錯分析
這個整合然后計數(shù)的過程中,中間發(fā)生了什么我們是必須要明白的。
首先mysql遇到該語句時會建立一個虛擬表。該虛擬表有兩個字段,一個是分組的 key ,一個是計數(shù)值 count()。也就對應(yīng)于實驗中的 user_name 和 count()。
然后在查詢數(shù)據(jù)的時候,首先查看該虛擬表中是否存在該分組,如果存在那么計數(shù)值加1,不存在則新建該分組。
然后mysql官方有給過提示,就是查詢的時候如果使用rand()的話,該值會被計算多次,那這個"被計算多次"到底是什么意思,就是在使用group by的時候,floor(rand(0)*2)會被執(zhí)行一次,如果虛表不存在記錄,插入虛表的時候會再被執(zhí)行一次,我們來看下floor(rand(0)*2)報錯的過程就知道了,從上面的函數(shù)使用中可以看到在一次多記錄的查詢過程中floor(rand(0)*2)的值是定性的,為011011 (這個順序很重要),報錯實際上就是floor(rand(0)*2)被計算多次導(dǎo)致的,我們還原一下具體的查詢過程:
(1)查詢前默認會建立空虛擬表如下圖:
(2)取第一條記錄,執(zhí)行floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為0(第一次計算), 0 1 1 0 1 1
(3)查詢虛擬表,發(fā)現(xiàn)0的鍵值不存在,則插入新的鍵值的時候floor(rand(0)*2)會被再計算一次,結(jié)果為1(第二次計算),插入虛表,這時第一條記錄查詢完畢,如下圖: 0 1 1 0 1 1
0 1 1 0 1 1 0
0 1 1
(4)查詢第二條記錄,再次計算floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為1(第三次計算)
(5)查詢虛表,發(fā)現(xiàn)1的鍵值存在,所以floor(rand(0)2)不會被計算第二次,直接count()加1,第二條記錄查詢完畢,結(jié)果如下:
(6)查詢第三條記錄,再次計算floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為0(第4次計算)
0 1 1 0
(7)查詢虛表,發(fā)現(xiàn)鍵值沒有0,則數(shù)據(jù)庫嘗試插入一條新的數(shù)據(jù),在插入數(shù)據(jù)時floor(rand(0)*2)被再次計算,1作為虛表的主鍵,其值為1(第5次計算),插入
然而1這個主鍵已經(jīng)存在于虛擬表中,而新計算的值也為1(主鍵鍵值必須唯一),所以插入的時候就直接報錯了。
0 1 1 0 1
四、總結(jié)
select count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables group by x
security1
security1
security1
整個查詢過程floor(rand(0)*2)被計算了5次,查詢原數(shù)據(jù)表3次,所以這就是為什么數(shù)據(jù)表中需要最少3條數(shù)據(jù),使用該語句才會報錯的原因。
另外,要注意加入隨機數(shù)種子的問題,如果沒加入隨機數(shù)種子或者加入其他的數(shù),那么floor(rand()*2)產(chǎn)生的序列是不可測的,這樣可能會出現(xiàn)正常插入的情況。最重要的是前面幾條記錄查詢后不能讓虛表存在0,1鍵值,如果存在了,那無論多少條記錄,也都沒辦法報錯,因為floor(rand()*2)不會再被計算做為虛表的鍵值,這也就是為什么不加隨機因子有時候會報錯,有時候不會報錯的原因。
比如下面用1作為隨機數(shù)種子,就不會產(chǎn)生報錯:
文章來源:http://www.zghlxwxcb.cn/news/detail-832287.html
文章來源地址http://www.zghlxwxcb.cn/news/detail-832287.html
到了這里,關(guān)于sql報錯注入 之 floor 函數(shù)報錯:主鍵重復(fù)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!