MySQL floor()报错原理分析
字数 1241 2025-08-15 21:31:25
MySQL floor()报错注入原理详解
一、概述
floor()报错注入(也称group报错注入)是一种利用MySQL数据库GROUP BY子句与RAND()函数特性实现的SQL注入技术。通过精心构造的SQL语句,攻击者可以触发数据库报错并泄露敏感信息。
二、测试环境
- MySQL版本:5.5.53
- 测试数据库:security.users(来自sqli-labs)
三、典型报错语句
select count(*) from users group by concat(database(),floor(rand(0)*2));
select count(*),concat(database(),floor(rand(0)*2)) as x from users group by x;
两条语句功能相同,第二条中的as x是前一个表达式的别名。
四、报错信息分析
执行后会报错:
ERROR 1062 (23000): Duplicate entry 'security1' for key 'group_key'
关键点:
- 'security1'中的'security'来自database()函数执行结果
- '1'来自floor(rand(0)*2)的计算结果
- 报错表明临时表中已存在'security1'主键
五、关键函数解析
1. rand()函数
- 返回[0,1)区间的随机浮点数
- 指定种子参数N时(如rand(0)),生成可重复的伪随机序列
- rand(0)*2将范围扩展到[0,2)
2. floor()函数
- 返回不大于x的最大整数
- 示例:floor(3.3)=3,floor(-3.3)=-4
3. concat()函数
- 拼接多个字符串
- 若任一参数为NULL,则返回NULL
六、GROUP BY工作机制
- 执行GROUP BY时,会创建临时表,GROUP BY的列作为临时表主键
- 处理流程:
- 取出查询表中的记录
- 检查临时表是否存在该主键
- 存在:count(*)值加1
- 不存在:将该主键插入临时表(count(*)初始为1)
七、报错原理详解
关键特性:当临时表中没有某主键时,在插入前rand()会再计算一次
具体流程(以rand(0)为例):
-
处理第一条记录:
- 计算group by key应为'security0'
- 发现临时表无此主键,rand()再次计算得到1
- 实际插入的主键变为'security1',count=1
-
处理第二条记录:
- 计算group by key为'security1'
- 临时表已有此主键,count加1变为2
-
处理第三条记录:
- 计算group by key为'security0'
- 发现临时表无此主键,rand()再次计算得到1
- 尝试插入'security1',但主键已存在,导致报错
八、必要条件
- 表中至少需要3条记录(因为需要触发第三次计算)
- 可以通过选择特定种子减少所需记录数:
- 如rand(14)*2的序列为1,0,1,0...
- 这样只需2条记录即可触发报错
九、总结
floor()报错注入的核心原理:
- GROUP BY与RAND()联用时,在插入临时表前RAND()会多次计算
- 这种多次计算导致临时表主键重复
- 报错前CONCAT()中的函数已被执行,结果通过报错信息泄露
十、防御建议
- 对用户输入进行严格过滤和参数化查询
- 避免在SQL语句中直接拼接用户输入
- 使用最小权限原则,限制数据库用户权限
- 及时更新MySQL到最新版本,修复已知漏洞