这里我使用的是information_schema中的schemata表,因为我的数据库有7个,生成的随机结果中0和1有一定比例,不容易全是0或者全是1,实际使用情况下推荐使用information_schema中的tables或者columns两个表,里面的数据条目较多,容易生成较多的随机值。
例如:
mysql> SELECT count(*), concat((SELECT database()), floor(rand()*2))as a from information_schema.tables group by a;在sqli-labs闯关的第五关中payload如下:
XXX.php/?id=-1' union select 1,count(*), concat((select database()), floor(rand()*2))as a from information_schema.tables group by a --+注意,由于有随机性,可能成功执行了语句所以不会报错,正常的显示页面(即不报错)如下:
这种情况多提交几次就行,理论上每次都有百分之50的可能性
但可以通过修改rand()使用的种子来使其百分百报错,如下将rand()改为rand(1),测试百分之百报错:
XXX.php/?id=-1' union select 1,count(*), concat((select database()), floor(rand(1)*2))as a from information_schema.tables group by a --+ 注入原理以下是学习过程中看到的不同作者对该问题原因的解释:
这个是最初看到的原理,但是个人觉得阐述的不太正确:
当在一个聚合函数后面(比如count)后面使用分组语句,就会把查询的一部分以错误形式显示出来;因为concat函数执行两次,比如select database(),这样就执行了两次select database,与后面的随机函数链接在一起,可能会随机重复,就会报错;
另一个博客中提出的深层次的原因,比较合理:
通过floor报错的方法来爆数据的本质是group by语句的报错。group by语句报错的原因是floor(random(0)*2)的不确定性,即可能为0也可能为1,(group by key的原理是循环读取数据的每一行,将结果保存于临时表中。读取每一行的key时,如果key存在于临时表中,则不在临时表中更新临时表中的数据;如果该key不存在于临时表中,则在临时表中插入key所在行的数据。group by floor(random(0)*2)出错的原因是key是个随机数,检测临时表中key是否存在时计算了一下floor(random(0)*2)可能为0,如果此时临时表只有key为1的行和不存在key为0的行,那么数据库要将该条记录插入临时表,由于是随机数,插时又要计算一下随机值,此时floor(random(0)*2)结果可能为1,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。
但是上述两个理由我看了感觉还是有一些地方不明白,感觉没有说到地方,所以又自己探索了一番,这一篇文章篇幅已经很长了,所以留在下一篇里单独探讨吧。
本文参考链接:
初步了解双查询注入:
https://www.2cto.com/article/201303/192718.html
深入理解:
https://www.cnblogs.com/BloodZero/p/4660971.html
rand()的随机数种子的影响:
https://segmentfault.com/q/1010000000609508