mysql的count报错_Mysql报错注入原理分析(count()、rand()、group by)
報錯需要count(*),rand()、group by,三者缺一不可
前提:當行數大于等于3行時才會報錯。
原鏈接:https://www.cnblogs.com/xdans/p/5412468.html
幾個fool()原理解釋:
select
count(*),floor(rand(0)*2) from test group by floor(rand(0)*2)
首先看經典的floor注入語句:
and select 1 from (select
count(*),concat(database(),floor(rand(0)*2))x from information_schema.tables
group by x)a)
第一眼看起來有些懵逼,我們來從最基本的入手,最后在分析這個語句
首先是floor()報錯產生的條件:
select count(*)
,floor(rand(0)*2)x from security.users group by x(自定義數據庫的一張表)
這里解釋一下x是什么意思,可能有些同學不太熟悉sql語句,floor(rand(0)*2)x的x是為floor(rand(0)*2)添加了一個別名,就是x就等于floor(rand(0)*2),這樣做的目的是
讓group by 和 floor(rand(0)*2)相遇(請原諒我這么解釋),
下一步我們在報錯位置處加上我們想要的子查詢,用concat()拼接:
select count(*)
,concat(database(),floor(rand(0)*2))x from security.users group by x
security就是我們想要的數據庫名,1是上一步拼接的。
但現在是不是就可以直接使用了呢?還有幾個步驟,先看直接拼接到and 后會怎樣:
select * from security.users
where id=1 and (select count(*) ,concat(database(),floor(rand(0)*2)x) from
security.users group by x)
報了一個錯,百度一番發現引發這個錯誤的原因很多,這里我是覺得我們構建的select語句的結果是一個結果表,而and 需要一個布爾值,也就是0或非零的值,那我們在嵌套一個查詢,前面說了select 的結果是一個結果表,那我們就可再從這個表執行查詢,只不過這次select的值是非零數字:
select 1 from (select
count(*) ,concat(database(),floor(rand(0)*2))x from security.users group by x)a
再啰嗦一句,最后這個a和之前解釋的x的作用是一樣的,是前面括號內容的別名,
sql語句要求在查詢結果的基礎上再執行查詢時,必須給定一個別名。
嵌套進and后執行
select * from security.users
where id=1 and(select 1 from (select count(*)
,concat(database(),floor(rand(0)*2))x from security.users group by x)a)
大功告成
我們完成了剛開始引入的floo()注入語句
一 隨機因子具有決定權(rand()和rand(0))
隨機因子指的是rand(x)
x是否有。
當插入一條記錄時,不報錯。
增加一條記錄,有時候報錯。
再增加一條記錄也和2條記錄一樣進行隨機報錯。
三條及以上和2條記錄一樣進行隨機報錯。
分別對floor(rand()*2)和floor(rand(0)*2)在多記錄表中執行多次(記錄選擇10條以上),在有12條記錄表中執行結果如下圖:
連續3次查詢,毫無規則,接下來看看select floor(rand(0)*2) from T-Safe;,如下圖:
可以看到floor(rand(0)*2)是有規律的,而且是固定的。
二 count與group by的虛擬表
在使用還有count() 和group by 的查詢語句時,mysql在遇到select count(*) from TSafe group by x;這語句的時候到底做了哪些操作呢,我們果斷猜測mysql遇到該語句時會建立一個虛擬表(實際上就是會建立虛擬表),那整個工作流程就會如下圖所示:
1.先建立虛擬表,如下圖(其中key是主鍵,不可重復):
2.開始查詢數據,取數據庫數據,然后查看虛擬表存在不,不存在則插入新記錄,存在則count(*)字段直接加1,如下圖:
由此看到 如果key存在的話就+1, 不存在的話就新建一個key。
三 floor(rand(0)*2)報錯
1.查詢的時候如果使用rand()的話,該值會被計算多次,就是在使用group by的時候,floor(rand(0)*2)會被執行一次,如果虛表不存在記錄,插入虛表的時候會再被執行一次,以此類推。
注:使用group by,即虛表存儲是按照group by 計算的那一列來從上往下來計算,取一條記錄判斷虛表是否存在時會使函數執行一遍,當存入的時候(即表中key值無此值)會將原函數存入,但是存的內容是最終結果,即原函數會被再次執行結果存入虛表,當表中有此鍵值對,那么只需count+1,不用再存key,所以比較時會計算一次,存入時又會計算一次。
2.在使用count(*)時,如
select count(*) from test group by x;? x=floor(rand(0)*2)
mysql執行此句時會創建一個虛表,虛表一共兩個字段主鍵是x,另外一個字段是count(*)
3.首先知道floor(rand(0)*2)的值為011011...,
4.執行的過程(floor(rand(0)*2)報錯的原因):(插入之前是表面顯示數據,實際比較時和存儲時為表面數據計算之后的結果,這取決于數據庫的一種存儲機制,表面的sql語句會被審查,然后執行存入數據庫,再回顯數據庫中存的內容,即結果)
select count(*) from test group by floor(rand(0)*2) ;
select count(*),floor(rand(0)*2) from test group by floor(rand(0)*2) ;
(這個位置的floor(..))有沒有無所謂用不到
1).查詢前默認會建立空虛擬表如下圖:
2).開始執行,查詢第一條記錄(即數據),在使用group by時 floor(rand(0)*2)執行一次,結果為0,即x=0(第一次執行),然后發現虛表中沒有key=0的鍵值對記錄,則floor(rand(0)*2)會被存入虛表,存入時會被計算為實際的值,即會被再執行一次(第二次執行),結果為1插入虛表,同時count由0變1。
3)取第二條記錄,floor(rand(0)*2)執行一次,結果為1(第三次執行),查詢虛表,發現虛表中有1,則直接count+1,不用再存key,所以floor(rand(0)*2)不會再被計算。
4).取第三條記錄,floor(rand(0)*2)執行一次,結果為0,發現虛表中沒有key=0,那么floor(rand(0)*2)會再次執行并存入虛表,此次計算結果為1(第五次執行),與已有的key沖突了,所以插入時報錯。
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,三者缺一不可
總結
以上是生活随笔為你收集整理的mysql的count报错_Mysql报错注入原理分析(count()、rand()、group by)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 指纹图谱相似度评价软件_不同产地佛手指纹
- 下一篇: 客厅安装路由器 路由器如何移到客厅