函数说明
实验所用核心函数:
rand():是一个生成随机数的函数,他会返回0到1之间到一个值。
floor():是取整函数。
count():是一个聚合函数,用户返回符合条件的记录数量。
查询相关函数:
concat_ws():使用语法为:CONCAT_WS(separator,str1,str2,…)
CONCAT_WS() 代表 CONCAT With Separator ,是CONCAT()的特殊形式。第一个参数是其它参数的分隔符。分隔符的位置放在要连接的两个字符串之间。分隔符可以是一个字符串,也可以是其它参数。如果分隔符为 NULL,则结果为 NULL。函数会忽略任何分隔符参数后的 NULL 值。但是CONCAT_WS()不会忽略任何空字符串。 (然而会忽略所有的 NULL)。
注入原理及过程演示
我们先在数据库上测试一下上述的三种函数。
在这里我们要注意 select floor(rand())
的结果必然为零。为什么呢?因为 rand() 函数返回一个大小在0和1之间的随机数,而 floor() 的功能是向下取整。
现在我们来扩充一下我们的语句:
select concat_ws(':',(select database()),floor(rand()*2)) as a;
这里对 rand() 函数返回值进行乘2操作保证取整前的数字在 0~1 之间,从而在向下取整后得到 0或1 这两个值。而 a 为我们取得别名。
实验次数达到一定的时候,我们会发现,大概会以百分之50的概率分别出现上面图中的两种结果。
接着,我们把count函数也加上,这时候需要注意,要从一张表中查询结果,具体从什么表没关系,但是一定要确保有这个表,所以比较好的选择方案就是 information_schema 中的表,比如tables:
select count(*),concat_ws(':',(select database()),floor(rand()*2)) as a from information_schema.tables;
最后让我们来测试一下终极语句:
select count(*),concat_ws(':',(select database()),floor(rand()*2)) as a from information_schema.tables group by a;
原理:
通过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,就会导致插入时冲突而报错。即检测时和插入时两次计算了随机数的值。
结论是:当与临时表里面的值进行比较,如果不同,就插入,但是插入的时候又计算了一次,所以如果插入时计算的值与直接比较的值不一样,则报错!
试验结果
127.0.0.1/sqli/less-5/?id=0' union select 1,count(*),concat((select database()),floor(rand()*2)) as a from information_schema group by a --+
这里利用一个不存在的表名来爆出数据库的名字。