乡下人产国偷v产偷v自拍,国产午夜片在线观看,婷婷成人亚洲综合国产麻豆,久久综合给合久久狠狠狠9

  • <output id="e9wm2"></output>
    <s id="e9wm2"><nobr id="e9wm2"><ins id="e9wm2"></ins></nobr></s>

    • 分享

      CTF-sql-group by報錯注入

       丹楓無跡 2021-11-19

      本文章主要涉及group by報錯注入的原理講解,如有錯誤,望指出。(附有目錄,如需查看請點右下角)

      一、下圖為本次文章所使用到 user表,該表所在的數據庫為 test

      二、首先介紹一下本文章所使用的到的語法:(第5、6條必須看,這涉及到之后的原理講解)

      1、group by語句:用于結合合計函數,根據一個或多個列對結果集進行分組。

      如下圖:

      2、rand()函數:用于產生一個0-1之間的隨機數:

      如下圖:

      注意:
      當以某個整數值作為參數來調用的時候,rand() 會將該值作為隨機數發(fā)生器的種子。對于每一個給定的種子,rand() 函數都會產生一列【可以復現】的數字

      3、floor()函數:向下取整:

      如下圖:

      4、count()函數:返回指定列的值的數目(NULL 不計入),count(*):返回表中的記錄數

      如下圖

      5、floor(rand()*2):rand()*2 函數生成 0-2之間的數,使用floor()函數向下取整,得到的值就是【不固定】的 “0” 或 “1”

      如下圖:

      6、floor(rand(0)*2):rand(0)*2 函數生成 0-2之間的數,使用floor()函數向下取整,但是得到的值【前6位(包括第六位)是固定的】。(為:011011)

      如下圖:

      三、接下來我們開始講解group by進行分組的原理:(如果你覺得已經理解了該原理請直接轉:四)

      首先讓我們思考一下下面三個sql語句,從中我們可以得知什么:

      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;
      

      運行結果如下:

      結論:

      我們發(fā)現group by后面的參數可以是一個column_name(字段名),可以是一個字符串(或返回值為字符串的函數),不可以是不完整的column_name。這時你們可能會想,參數是column_name我倒是可以理解是怎么分組的,但是參數是 字符串 是怎么回事?username字段的值中沒有"username"啊?只有"admin","chen"兩個,結果怎么會是 7 呢?讓我們接著往下看。

      原因:上面sql語句的分組原理(雖然是我的推測,但是這樣說明的確可以解釋的通):

      1、如果參數是 column_name,即 username,不是字符串("username")。

      語句執(zhí)行的時候會建立一個虛擬表(里面有兩個字段,分別是 key 主鍵,count(*)),如果參數是 column_name,系統便會在 user 表中【 依次查詢 [相應的] 字段的值(即:參數指明的字段中的值) 】,取username字段第一個值為 admin,這時會在虛擬表的 主鍵key 中查找 admin 這個字符串,如果存在,就使 count(*) 的值加 1 ;如果不存在就將 admin 這個字符串插入到 主鍵key 字段中,并且使 count(*) 變?yōu)?1;接著取username字段第二個值也為 admin ,查找虛擬表中的 主鍵key 中已經存在 admin 字符串,就直接將 count(*) 加 1;…… …… ……;到username字段第四個值為 chen 時,查找虛擬表中的 主鍵key 字段不存在 chen 這個值,此時就將 chen 這個字符串再次插入到 主鍵key 字段中,并且使 count(*) 變?yōu)?1,就這樣一直執(zhí)行下去,直到所有的字段值分組完畢。之后系統就按照虛擬表中的結果將其顯示出來。

      取完username字段第四個值(即:chen)時的 虛擬表 ,如下圖:

      2、如果參數是字符串:"username",而不是字段名:

      語句執(zhí)行的時候仍會建立一個虛擬表(里面有兩個字段,分別是 key 主鍵,count(*)),如果參數是字符串 "username",那系統就不會去取user表中的字段值了,而是直接取字符串:"username"作為值,然后查找比對虛擬表中 key 字段的值,發(fā)現沒有字符串 "username",便插入 "username" 這個字符串,并將count(*) 變?yōu)?;然后執(zhí)行第二次,在虛擬表 key 字段中查找 "username" 這個字符串,發(fā)現有,便使 count(*) 加 1,就這樣執(zhí)行 7 次,count(*)便變成了 7。

      四、理解完上面之后,讓我們進入正題,請看下兩條的sql group by報錯注入語句,以及其運行結果:

      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 數據庫被成功的爆了出來。但是你們仔細觀察的話會發(fā)現第二個sql語句爆率并不是100%,有時會爆不出來,為什么呢?別著急,繼續(xù)往下看:

      原因:在我們已經有上面的鋪墊之后其實要理解這個sql group by報錯注入的原理已經不難了:

      以第一條語句為例:select count(*) from information_schema.tables group by concat(database(),floor(rand(0)*2));
      首先我們知道

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

      報錯的過程:

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

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

      五、總結

      現在,解釋了group by報錯注入的原理,想必大家已經知道為什么:

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

      沒錯是因為floor(rand()*2)的前幾位隨機數順序是不固定的,所以并不能保證一定會注入成功,但是其只需兩條記錄數就行了(因為它可能會產出 “0101” ,這樣只需兩條記錄就可以成功注入,你可以試試推導一下),這也算是它的優(yōu)勢吧。

      文章是博主一字一字打出來的,轉載請標明出處,謝謝!

        本站是提供個人知識管理的網絡存儲空間,所有內容均由用戶發(fā)布,不代表本站觀點。請注意甄別內容中的聯系方式、誘導購買等信息,謹防詐騙。如發(fā)現有害或侵權內容,請點擊一鍵舉報。
        轉藏 分享 獻花(0

        0條評論

        發(fā)表

        請遵守用戶 評論公約

        類似文章 更多