Mysql报错注入原理分析(count()、rand()、group by)

Mysql报错注入原理分析(count()、rand()、group by)

0x00 疑问


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

百度谷歌知乎了一番,发现你们都是把官网的结论发一下截图,而后执行sql语句证实一下结论,可是没有人去深刻研究为何rand不能和order by一块儿使用,也没完全说明三者同时使用报错的原理。java

0x01 位置问题?


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

由上面的图片,能够知道报错跟位置无关。sql

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


是否是报错语句有了floor(rand(0)*2)以及其余几个条件就必定报错?其实并非如此,咱们先建建个表,新增一条记录看看,以下图:数据库

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

屡次执行均未发现报错。this

而后咱们新增一条记录。3d

而后再测试下报错语句orm

屡次执行并无报错blog

OK 那咱们再增长一条

执行报错语句

ok 成功报错

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

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


为了更完全的说明报错缘由,直接把随机因子去掉,再来一遍看看,先看一条记录的时候,以下图:

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

而后增长一条记录。

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

随机出现报错。

而后再插入一条

三条记录以后,也和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条记录表中执行结果以下图:

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

   

能够看到floor(rand(0)*2)是有规律的,并且是固定的,这个就是上面提到的因为是肯定性才致使的报错,那为什么会报错呢,咱们接着往下看。

0x05 count与group by的虚拟表


使用select count(*) from `T-Safe` group by x;这种语句的时候咱们常常能够看到下面相似的结果:

能够看出 test12的记录有5条

与count(*)的结果相符合,那么mysql在遇到select count(*) from TSafe group by x;这语句的时候到底作了哪些操做呢,咱们果断猜想mysql遇到该语句时会创建一个虚拟表(实际上就是会创建虚拟表),那整个工做流程就会以下图所示:

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

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

由此看到 若是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.查询前默认会创建空虚拟表以下图:

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

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

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)是不可测的,所以在两条数据的时候,只要出现下面状况,便可报错,以下图:

最重要的是前面几条记录查询后不能让虚表存在0,1键值,若是存在了,那不管多少条记录,也都没办法报错,由于floor(rand()*2)不会再被计算作为虚表的键值,这也就是为何不加随机因子有时候会报错,有时候不会报错的缘由。如图:

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

在前两条记录查询后,虚拟表已经存在0和1两个键值了,因此后面再怎么弄仍是不会报错。

总之报错须要count(*),rand()、group by,三者缺一不可。

上一页