mysql的count报错_Mysql报错注入原理分析(count()、rand()、group by)

2ff34e647e2e3cdfd8dca593e17d9b0a.png

0x00 疑问

一直在用mysql数据库报错注入方法,但为何会报错?

6.png

百度谷歌知乎了一番,发现大家都是把官网的结论发一下截图,然后执行sql语句证明一下结论,但是没有人去深入研究为什么rand不能和order by一起使用,也没彻底说明三者同时使用报错的原理。

0x01 位置问题?

select count(*),(floor(rand(0)2))x from information_schema.tables group by x; 这是网上最常见的语句,目前位置看到的网上sql注入教程,floor 都是直接放count() 后面,为了排除干扰,我们直接对比了两个报错语句,如下图

7.png

由上面的图片,可以知道报错跟位置无关。

0x02 绝对报错还是相对报错?

是不是报错语句有了floor(rand(0)*2)以及其他几个条件就一定报错?其实并不是如此,我们先建建个表,新增一条记录看看,如下图:

8.png

9.png

确认表中只有一条记录后,再执行报错语句看看,如下图:

10.png

多次执行均未发现报错。

然后我们新增一条记录。

11.png

然后再测试下报错语句

12.png

多次执行并没有报错

OK 那我们再增加一条

13.png

执行报错语句

14.png

ok 成功报错

由此可证明floor(rand(0)*2)报错是有条件的,记录必须3条以上,而且在3条以上必定报错,到底为何?请继续往下看。

0x03 随机因子具有决定权么(rand()和rand(0))

为了更彻底的说明报错原因,直接把随机因子去掉,再来一遍看看,先看一条记录的时候,如下图:

15.png

一条记录的话 无论执行多少次也不报错

然后增加一条记录。

两条记录的话 结果就变成不确定性了

16.png

17.png

18.png

随机出现报错。然后再插入一条,三条记录之后,也和2条记录一样进行随机报错。

由此可见报错和随机因子是有关联的,但有什么关联呢,为什么直接使用rand(),有两条记录的情况下就会报错,而且是有时候报错,有时候不报错,而rand(0)

的时候在两条的时候不报错,在三条以上就绝对报错?我们继续往下看。

0x04不确定性与确定性

前面说过,floor(rand(0)2)报错的原理是恰恰是由于它的确定性,这到底是为什么呢?从0x03我们大致可以猜想到,因为floor(rand()2)不加随机因子的时候是随机出错的,而在3条记录以上用floor(rand(0)2)就一定报错,由此可猜想floor(rand()2)是比较随机的,不具备确定性因素,而floor(rand(0)2)具备某方面的确定性。

为了证明我们猜想,分别对floor(rand()2)和floor(rand(0)2)在多记录表中执行多次(记录选择10条以上),在有12条记录表中执行结果如下图:

19.png

连续3次查询,毫无规则,接下来看看select floor(rand(0)2) from T-Safe;,如下图:

20.png

可以看到floor(rand(0)*2)是有规律的,而且是固定的,这个就是上面提到的由于是确定性才导致的报错,那为何会报错呢,我们接着往下看。

0x05 count与group by的虚拟表

使用select count() from T-Safe group by x;这种语句的时候我们经常可以看到下面类似的结果:

21.png

可以看出 test12的记录有5条与count()的结果相符合,那么mysql在遇到select count() from TSafe group by x;这语句的时候到底做了哪些操作呢,我们果断猜测mysql遇到该语句时会建立一个虚拟表(实际上就是会建立虚拟表),那整个工作流程就会如下图所示:

1.先建立虚拟表,如下图(其中key是主键,不可重复):

22.png

2.开始查询数据,取数据库数据,然后查看虚拟表存在不,不存在则插入新记录,存在则count()字段直接加1,如下图:

23.png

3.由此看到 如果key存在的话就+1, 不存在的话就新建一个key。

那这个和报错有啥内在联系,我们直接往下来,其实到这里,结合前面的内容大家也能猜个一二了。

0x06 floor(rand(0)*2)报错

其实mysql官方有给过提示,就是查询的时候如果使用rand()的话,该值会被计算多次,那这个”被计算多次”到底是什么意思,就是在使用group by的时候,floor(rand(0)*

2)会被执行一次,如果虚表不存在记录,插入虚表的时候会再被执行一次,我们来看下floor(rand(0)2)报错的过程就知道了,从0x04可以看到在一次多记录的查询过程中floor(rand(0)2)的值是定性的,为011011…(记住这个顺序很重要),报错实际上就是floor(rand(0)2)被计算多次导致的,具体看看select count() from TSafe group by floor(rand(0)2);的查询过程:

1.查询前默认会建立空虚拟表如下图:

25.png

2.取第一条记录,执行floor(rand(0)2),发现结果为0(第一次计算),查询虚拟表,发现0的键值不存在,则floor(rand(0)2)会被再计算一次,结果为1(第二次计算),插入虚表,这时第一条记录查询完毕,如下图:

26.png

3.查询第二条记录,再次计算floor(rand(0)*2),发现结果为1(第三次计算),查询虚表,发现1的键值存在,所以floor(rand(0)2)不会被计算第二次,直接count()加1,第二条记录查询完毕,结果如下:

27.png

4.查询第三条记录,再次计算floor(rand(0)2),发现结果为0(第4次计算),查询虚表,发现键值没有0,则数据库尝试插入一条新的数据,在插入数据时floor(rand(0)2)被再次计算,作为虚表的主键,其值为1(第5次计算

),然而1这个主键已经存在于虚拟表中,而新计算的值也为1(主键键值必须唯一),所以插入的时候就直接报错了。

5.整个查询过程floor(rand(0)*2)被计算了5次,查询原数据表3次,所以这就是为什么数据表中需要3条数据,使用该语句才会报错的原因。

0x07 floor(rand()*2)报错

由0x05我们可以同样推理出不加入随机因子的情况,由于没加入随机因子,所以floor(rand()*2)是不可测的,因此在两条数据的时候,只要出现下面情况,即可报错,如下图:

28.png

最重要的是前面几条记录查询后不能让虚表存在0,1键值,如果存在了,那无论多少条记录,也都没办法报错,因为floor(rand()*

2)不会再被计算做为虚表的键值,这也就是为什么不加随机因子有时候会报错,有时候不会报错的原因。如图:

29.png

当前面记录让虚表长成这样子后,由于不管查询多少条记录,floor(rand()2)的值在虚表中都能找到,所以不会被再次计算,只是简单的增加count()字段的数量,所以不会报错,比如floor(rand(1)*2),如图:

30.png

这里再补充一下知识点

UpdateXml() MYSQL显错注入

在学习之前,需要先了解 UpdateXml() 。

UPDATEXML (XML_document, XPath_string, new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc

第二个参数:XPath_string (Xpath格式的字符串) ,如果不了解Xpath语法,可以在网上查找教程。

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

作用:改变文档中符合条件的节点的值

然后咱们再看看语句:

http://www.XXXIII.com/a.php?id=1 and updatexml(1,concat(0x7e,(SELECT @@version),0x7e),1)

CONCAT(str1,str2,…)

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

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

错误大概会是:

ERROR 1105 (HY000): XPATH syntax error: ’:[email protected]

1、floor函数

因为之前讲双查询语句时,就把floor函数报错也进行了讲解,这里就不再重复。忘记的翻翻我的其他博客(sql分类)

这里贴个sql注入的floor语句公式:

and (select 1 from(select count(),concat(version(),floor(rand(0)2))x from information_schema.tables group by x)a)

这些sql注入的语句公式,都是研究人员经过测试总结出来的。我们需要的则是,了解这个语句公式的含义和了解其背后的逻辑原理,之后收集一些sql

语句注入公式拿来进行fuzz检测即可。简单一句话就是:自己在看懂和明白sql注入的原理基础上,那别人总结出的sql注入语句利用实现就好了。因为很

多sql注入语句都是基于这些sql注入原始公式语句变形而来的,背后的逻辑原理不会改变的。好啦,不吹了,我们继续学习剩下的函数。

2、exp()函数

exp函数相信大家都十分的熟悉,这是一个数学函数,用于计算e的x次方的函数。

exp函数特性:在mysql数据库中,exp()只能计算710之内的数值,一旦超过或者等于710的话,则会进行整形报错溢出。提示:DOUBLE value is out

of range in ‘exp(710)’ double类型超出了exp(710)范围。

31.png

这里顺便在提下~,如果构造利用为 ~0的话,它是代表着按0按位取反就会返回“18446744073709551615”,得到最大的无符号BIGINT值。

32.png

所以利用上述exp和特性,我们可以构造成payload:and (EXP((select * from(select version())a)));

利用环境:mysql>5.5.5

利用它的这个特性,我们可以构造成payload:and (EXP((select * from(select version())a)));

33.png

通过先是通过子查询产生了最大的无符号BIGINT值,之后通过exp()函数形成了DOUBLE报错,从而能够得到我们想要的版本报错信息。

至于后面怎么操作,不要太死板呀。就version()你看看怎么改,换成什么database(),user()…自己慢慢思考下。

在这里有些人可能会有一些问题:就是说为啥exp(数据库版本),就会报错?其实在这里我们可以不用去关注select查询的东西,select在这个语句他只要成功执行就会返回一个0,所以就相当于exp( 0)

3、数据重复报错

利用环境:mysql低版本

payload:select * from (select NAMECONST(version(),1),NAMECONST(version(),1))x

34.png

这里利用了数据库无法识别重复查询数据库版本信息的操作,从而进行报错。

4、Xpath报错(我的博客好像也单独讲过)

数据库环境:mysql 5.1.5

在学习Xpath函数之前,我们先了解下updatexml()函数和extractvalue()函数。

updataxml()函数

UPDATEXML (XMLdocument, XPathstring, new_value);

第一个参数:XML_document是String格式,为XML文档对象的名称,文中为Doc

第二个参数:XPath_string (Xpath格式的字符串)

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

作用:改变文档中符合条件的节点的值(其实简单的说,就是对xml进行查询和修改)

简单分析下,在这里我们先是查询了数据库的版本信息,而后concat函数进行连接字符串信息,然后利用xml语法进行查询和修改。但是我们却使用

0x7e进行拼接,0x7e是啥?这是特殊字符进行十六进制转换的结果。同时updataxml函数是第二位置是拼接xml字符串,而extractvalue是需要xml路

径。至于xml具体语法我就不讲解了,这里0x7e嵌套在里面的话,xml语法是无法识别的,所以会进行报错,从而产生了报错得到我们想要的信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值