小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

CTF-sql-group by報(bào)錯(cuò)注入

 丹楓無(wú)跡 2021-11-19

本文章主要涉及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ù):

如下圖:

注意:
當(dāng)以某個(gè)整數(shù)值作為參數(shù)來(lái)調(diào)用的時(shí)候,rand() 會(huì)將該值作為隨機(jī)數(shù)發(fā)生器的種子。對(duì)于每一個(gè)給定的種子,rand() 函數(shù)都會(huì)產(chǎn)生一列【可以復(fù)現(xiàn)】的數(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ǔ)句,從中我們可以得知什么:

1、select username,count(*) from user group by username;
2、select username,count(*) from user group by "username";
3、select username,count(*) from user group by userna;

運(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é)果:

1、select count(*) from information_schema.tables group by concat(database(),floor(rand(0)*2));
2、select count(*) from information_schema.tables group by concat(database(),floor(rand()*2));

可以看到,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));
首先我們知道

  • floor(rand(0)*2) 產(chǎn)生的隨機(jī)數(shù)的前六位 一定是 “011011”(上面已經(jīng)提到過(guò)了),
  • concat()函數(shù)用于將前后兩個(gè)字符串相連
  • database ()函數(shù)由于返回當(dāng)前使用數(shù)據(jù)庫(kù)的名稱。
  • concat(database(),floor(rand(0)*2))生成由'database()+'0’’和'database()+'1’’組成的隨機(jī)數(shù)列,則前六個(gè)數(shù)列一定依次是:
    • 'database()+'0''
    • 'database()+'1''
    • 'database()+'1''
    • 'database()+'0''
    • 'database()+'1''
    • 'database()+'1''

報(bào)錯(cuò)的過(guò)程:

  • 查詢前默認(rèn)會(huì)建立空的虛擬表
  • 取第一條記錄,執(zhí)行concat(database(),floor(rand(0)*2))(第一次執(zhí)行),計(jì)算結(jié)果為'database()+'0'',查詢虛擬表,發(fā)現(xiàn)'database()+'0''主鍵值不存在,則會(huì)執(zhí)行插入命令,此時(shí)又會(huì)再次執(zhí)行一次concat(database(),floor(rand(0)*2))(第二次執(zhí)行),計(jì)算結(jié)果為'database()+'1'',然后插入該值。(即:雖然查詢比對(duì)的是'database()+'0'',但是真正插入的是執(zhí)行第二次的結(jié)果'database()+'1'',這個(gè)過(guò)程,concat(database(),floor(rand(0)*2))執(zhí)行了兩次,查詢比對(duì)時(shí)執(zhí)行了一次,插入時(shí)執(zhí)行了一次)。
  • 取第二條記錄,執(zhí)行concat(database(),floor(rand(0)*2))(第三次執(zhí)行),計(jì)算結(jié)果為'database()+'1'',查詢虛擬表,發(fā)現(xiàn)'database()+'1''主鍵值存在,所以不再執(zhí)行插入指令,也就不會(huì)執(zhí)行第二次concat(database(),floor(rand(0)*2)),count(*) 直接加1,(即,查詢?yōu)?database()+'1'',直接加1,這個(gè)過(guò)程,concat(database(),floor(rand(0)*2))執(zhí)行了一次)。
  • 取第三條記錄,執(zhí)行concat(database(),floor(rand(0)*2))(第四次執(zhí)行),計(jì)算結(jié)果為'database()+'0'',查詢虛擬表,發(fā)現(xiàn)'database()+'0''主鍵值不存在,則會(huì)執(zhí)行插入命令,此時(shí)又會(huì)再次執(zhí)行一次concat(database(),floor(rand(0)*2))(第五次執(zhí)行),計(jì)算結(jié)果為'database()+'1''將其作為主鍵值,但是'database()+'1''這個(gè)主鍵值已經(jīng)存在于虛擬表中了,由于主鍵值必需唯一,所以會(huì)發(fā)生報(bào)錯(cuò)。而報(bào)錯(cuò)的結(jié)果就是 'database()+'1''即 'test1',從而得出數(shù)據(jù)庫(kù)的名稱 test。%e6%b5%85%e6%98%93%e6%b7%b1

由以上過(guò)程發(fā)現(xiàn),總共取了三條記錄(所以表中的記錄數(shù)至少為三條),floor(rand(0)*2)執(zhí)行了五次。

五、總結(jié)

現(xiàn)在,解釋了group by報(bào)錯(cuò)注入的原理,想必大家已經(jīng)知道為什么:

  • select count(*) from information_schema.tables group by concat(database(),floor(rand(0)*2));一定可以注入成功(要成功注入,前提表中的記錄數(shù)至少為三條)
  • 而select count(*) from information_schema.tables group by concat(database(),floor(rand()*2));卻不一定了吧。(要成功注入,前提表中的記錄數(shù)至少為兩條)

沒錯(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)明出處,謝謝!

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購(gòu)買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多