本文章主要涉及group by報(bào)錯(cuò)注入的原理講解,如有錯(cuò)誤,望指出。(附有目錄,如需查看請(qǐng)點(diǎn)右下角)一、下圖為本次文章所使用到 user表,該表所在的數(shù)據(jù)庫(kù)為 test
二、首先介紹一下本文章所使用的到的語(yǔ)法:(第5、6條必須看,這涉及到之后的原理講解)1、group by語(yǔ)句:用于結(jié)合合計(jì)函數(shù),根據(jù)一個(gè)或多個(gè)列對(duì)結(jié)果集進(jìn)行分組。如下圖:
2、rand()函數(shù):用于產(chǎn)生一個(gè)0-1之間的隨機(jī)數(shù):如下圖:
注意: 3、floor()函數(shù):向下取整:如下圖:
4、count()函數(shù):返回指定列的值的數(shù)目(NULL 不計(jì)入),count(*):返回表中的記錄數(shù)如下圖
5、floor(rand()*2):rand()*2 函數(shù)生成 0-2之間的數(shù),使用floor()函數(shù)向下取整,得到的值就是【不固定】的 “0” 或 “1”如下圖:
6、floor(rand(0)*2):rand(0)*2 函數(shù)生成 0-2之間的數(shù),使用floor()函數(shù)向下取整,但是得到的值【前6位(包括第六位)是固定的】。(為:011011)如下圖:
三、接下來(lái)我們開始講解group by進(jìn)行分組的原理:(如果你覺得已經(jīng)理解了該原理請(qǐng)直接轉(zhuǎn):四)首先讓我們思考一下下面三個(gè)sql語(yǔ)句,從中我們可以得知什么:
運(yùn)行結(jié)果如下:
結(jié)論:我們發(fā)現(xiàn)group by后面的參數(shù)可以是一個(gè)column_name(字段名),可以是一個(gè)字符串(或返回值為字符串的函數(shù)),不可以是不完整的column_name。這時(shí)你們可能會(huì)想,參數(shù)是column_name我倒是可以理解是怎么分組的,但是參數(shù)是 字符串 是怎么回事?username字段的值中沒有"username"啊?只有"admin","chen"兩個(gè),結(jié)果怎么會(huì)是 7 呢?讓我們接著往下看。 原因:上面sql語(yǔ)句的分組原理(雖然是我的推測(cè),但是這樣說(shuō)明的確可以解釋的通):1、如果參數(shù)是 column_name,即 username,不是字符串("username")。語(yǔ)句執(zhí)行的時(shí)候會(huì)建立一個(gè)虛擬表(里面有兩個(gè)字段,分別是 key 主鍵,count(*)),如果參數(shù)是 column_name,系統(tǒng)便會(huì)在 user 表中【 依次查詢 [相應(yīng)的] 字段的值(即:參數(shù)指明的字段中的值) 】,取username字段第一個(gè)值為 admin,這時(shí)會(huì)在虛擬表的 主鍵key 中查找 admin 這個(gè)字符串,如果存在,就使 count(*) 的值加 1 ;如果不存在就將 admin 這個(gè)字符串插入到 主鍵key 字段中,并且使 count(*) 變?yōu)?1;接著取username字段第二個(gè)值也為 admin ,查找虛擬表中的 主鍵key 中已經(jīng)存在 admin 字符串,就直接將 count(*) 加 1;…… …… ……;到username字段第四個(gè)值為 chen 時(shí),查找虛擬表中的 主鍵key 字段不存在 chen 這個(gè)值,此時(shí)就將 chen 這個(gè)字符串再次插入到 主鍵key 字段中,并且使 count(*) 變?yōu)?1,就這樣一直執(zhí)行下去,直到所有的字段值分組完畢。之后系統(tǒng)就按照虛擬表中的結(jié)果將其顯示出來(lái)。 取完username字段第四個(gè)值(即:chen)時(shí)的 虛擬表 ,如下圖:
2、如果參數(shù)是字符串:"username",而不是字段名:語(yǔ)句執(zhí)行的時(shí)候仍會(huì)建立一個(gè)虛擬表(里面有兩個(gè)字段,分別是 key 主鍵,count(*)),如果參數(shù)是字符串 "username",那系統(tǒng)就不會(huì)去取user表中的字段值了,而是直接取字符串:"username"作為值,然后查找比對(duì)虛擬表中 key 字段的值,發(fā)現(xiàn)沒有字符串 "username",便插入 "username" 這個(gè)字符串,并將count(*) 變?yōu)?;然后執(zhí)行第二次,在虛擬表 key 字段中查找 "username" 這個(gè)字符串,發(fā)現(xiàn)有,便使 count(*) 加 1,就這樣執(zhí)行 7 次,count(*)便變成了 7。 四、理解完上面之后,讓我們進(jìn)入正題,請(qǐng)看下兩條的sql group by報(bào)錯(cuò)注入語(yǔ)句,以及其運(yùn)行結(jié)果:
可以看到,user表所在的 test 數(shù)據(jù)庫(kù)被成功的爆了出來(lái)。但是你們仔細(xì)觀察的話會(huì)發(fā)現(xiàn)第二個(gè)sql語(yǔ)句爆率并不是100%,有時(shí)會(huì)爆不出來(lái),為什么呢?別著急,繼續(xù)往下看: 原因:在我們已經(jīng)有上面的鋪墊之后其實(shí)要理解這個(gè)sql group by報(bào)錯(cuò)注入的原理已經(jīng)不難了:以第一條語(yǔ)句為例:select count(*) from information_schema.tables group by concat(database(),floor(rand(0)*2));
報(bào)錯(cuò)的過(guò)程:
由以上過(guò)程發(fā)現(xiàn),總共取了三條記錄(所以表中的記錄數(shù)至少為三條),floor(rand(0)*2)執(zhí)行了五次。 五、總結(jié)現(xiàn)在,解釋了group by報(bào)錯(cuò)注入的原理,想必大家已經(jīng)知道為什么:
沒錯(cuò)是因?yàn)閒loor(rand()*2)的前幾位隨機(jī)數(shù)順序是不固定的,所以并不能保證一定會(huì)注入成功,但是其只需兩條記錄數(shù)就行了(因?yàn)樗赡軙?huì)產(chǎn)出 “0101” ,這樣只需兩條記錄就可以成功注入,你可以試試推導(dǎo)一下),這也算是它的優(yōu)勢(shì)吧。 文章是博主一字一字打出來(lái)的,轉(zhuǎn)載請(qǐng)標(biāo)明出處,謝謝! |
|
|