sql注入之双查询注入

在另外一篇文章中,用到了双查询注入,特在此详细讲解一下双查询注入。

另一篇文章传送门:sql注入那些事儿——如何优雅地进行SQL注入(3)

先大概说明一下双查询注入的原理和会用到的函数。

原理:简单的一句话原理就是有研究人员发现,当在一个聚合函数,比如count函数后面如果使用分组语句就会把查询的一部分以错误的形式显示出来。

函数说明:
rand()是一个生成随机数的函数,他会返回0到1之间到一个值。
floor()是取整函数了,童鞋们应该都很熟悉了。
count()是一个聚合函数,用户返回符合条件的记录数量。

然后大概说一下他的固定套路:

select count(*),concat_ws(':',([子查询],floor(rand()*2))) as a form [table_name] group by a;

这边我们直接在数据库上实验一下,首先将刚才说明的三个函数实验一下:


图片.png

图片.png

图片.png

其中,值得一说的是floor(rand())结果必为0,为什么?因为正如前面提到的,rand()只会返回0-1之间的数,而floor()是干嘛的,就是向下取整,所以就很好理解了,0-1之间的数,向下取整都为0。那么我们在双查询注入中的floor(rand()*2)也就很好猜他的值了。他的值不是0就是1。为0时什么时候,是rand()的值小于0.5的时候,为1也就是随机数大于0.5的时候。
为了让童鞋们更直观地感受,我们一部分一部分往里面加代码,目前是select floor(rand()*2)了。那么我们继续加,这边因为下面展示的时候的美观,我们给查询结果列一个别名a:

select concat_ws(':',(select database()),floor(rand()*2)) as a;

图片.png

图片.png

实验次数达到一定的时候,童鞋们会发现,大概会以百分之50的概率分别出现上面两图的结果。
接着,我们把count函数也加上,这时候需要注意,要从一张表中查询结果,具体从什么表没关系,但是一定要确保有这个表,所以比较好的选择方案就是information_schema中的表,比如tables:

select count(*),concat_ws(':',(select database()),floor(rand()*2)) as a from information_schema.tables;

图片.png

图片.png

结果也出来了,一样是百分之50的概率。
好了,接下来就是见证奇迹的时刻,我们把整个sql语句放进去执行:

select count(*),concat_ws(':',(select database()),floor(rand()*2)) as a from information_schema.tables group by a;

由于在navicat中,这个错误未被显示出来,于是Sunny用控制台远程连接了数据库,以一定概率出现了如下报错。


图片.png

好了,整个演示就差不多结束了。另外经过Sunny的不懈努力,终于在网上找到了有大佬发现的双查询注入报错的深层次原因。

深层次的原因:
通过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,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。

附上这位大佬的原文地址。感兴趣的朋友可以去看看。

至此,本篇文章到此结束,喜欢的童鞋可以点个赞,对sql注入感兴趣的童鞋可以关注我,我会持续发布sql注入文章。童鞋们如果有疑问或者想和我交流的话有两种方式:

第一种

评论留言

第二种

邮箱联系:zsunny@yeah.net

推荐阅读更多精彩内容