Mysql error injection principle analysis (count(), rand(), group by)

Mysql error injection principle analysis (count(), rand(), group by)

0x00 Question


I have been using the mysql database error injection method, but why does it report an error?

 

Baidu and Google know about it, (official website: www.fhadmin.org) and found that everyone sends a screenshot of the conclusion of the official website, and then executes the sql statement to prove the conclusion, but no one has studied in depth why rand cannot be combined with order by It does not fully explain the principle of using the three at the same time to report errors.

 

0x01 Location problem?


select count(*),(floor(rand(0)*2))x from information_schema.tables group by x; This is the most common statement on the Internet. In the online sql injection tutorial I saw at the current location, the floor is directly placed in count (*) Later, in order to eliminate interference, we directly compared the two error statements, as shown below

 

From the above picture, (official website: www.fhadmin.org) you can know that the error has nothing to do with the location.

0x02 Absolute error or relative error?


Is it true that the error statement must report an error with floor(rand(0)*2) and several other conditions? In fact, this is not the case. Let's build a table first and add a new record to see, as shown below:

 

After confirming that there is only one record in the table, execute the error statement to see, as shown below:

 

No errors were found in multiple executions.

Then we add a new record.

 

Then test the error statement again

 

Executed multiple times without error

OK, let's add one more

 

Execute the error statement

 

ok successful error

It can be proved that the floor(rand(0)*2) error report is conditional. (Official website: www.fhadmin.org) There must be more than 3 records, and more than 3 records must be reported. Why? please watch the following part.

0x03 Whether the random factor has the right to decide (rand() and rand(0))


In order to explain the reason for the error more thoroughly, just remove the random factor and look again. When looking at a record first, it is as follows:

 

If a record is executed, no error will be reported no matter how many times it is executed.

Then add a record.

If there are two records, the result becomes uncertain.

 

 

 

An error occurs randomly.

and then insert a

After three records, random errors are also reported as with two records.

由此可见报错和随机因子是有关联的,但有什么关联呢,为什么直接使用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条(官网:www.fhadmin.org)

与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次,(官网:www.fhadmin.org)所以这就是为什么数据表中需要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,三者缺一不可。

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326115700&siteId=291194637