Mysql报错注入原理分析count、rand、groupby
字数 1424 2025-08-29 08:31:47
MySQL报错注入原理分析:count、rand、group by
0x00 基本概念
MySQL报错注入是一种利用数据库错误信息泄露数据的SQL注入技术。其中,count()、rand()和group by的组合使用可以产生特定的报错,攻击者可以利用这些报错信息获取数据库中的敏感数据。
0x01 核心报错语句
最常见的报错注入语句:
select count(*), (floor(rand(0)*2))x from information_schema.tables group by x;
0x02 报错条件分析
必要条件
- 必须使用
count(*)函数 - 必须使用
rand()函数(特别是rand(0)) - 必须使用
group by子句 - 表中记录数必须≥3条(对于
rand(0))
记录数量影响
-
使用
rand(0)时:- 记录数<3:不会报错
- 记录数≥3:必定报错
-
使用
rand()(无参数)时:- 记录数≥2:可能随机报错
- 报错与否取决于虚表是否已存在0和1键值
0x03 随机因子分析
rand() vs rand(0)
rand():真正的随机函数,每次调用产生不同的随机序列rand(0):伪随机函数,给定相同种子(0)时产生确定性的序列(011011...)
确定性影响
floor(rand(0)*2):产生固定的011011...序列,导致可预测的报错floor(rand()*2):产生随机序列,报错不可预测
0x04 虚拟表工作原理
当执行select count(*) from table group by x时,MySQL会:
-
建立一个虚拟表,包含:
- key:group by的列(主键,不可重复)
- count(*):计数
-
查询流程:
- 取数据库记录
- 计算group by表达式
- 检查虚表是否存在该key:
- 存在:对应count(*)加1
- 不存在:插入新记录(key=表达式值,count(*)=1)
0x05 报错原理详解
以select count(*) from T-Safe group by floor(rand(0)*2);为例:
-
初始空虚拟表:
key | count(*) -
查询第一条记录:
- 计算
floor(rand(0)*2)=0(第一次计算) - 虚表无0键,需插入:
- 再次计算
floor(rand(0)*2)=1(第二次计算) - 插入虚表:
key | count(*) 1 | 1
- 再次计算
- 计算
-
查询第二条记录:
- 计算
floor(rand(0)*2)=1(第三次计算) - 虚表存在1键,直接count(*)加1:
key | count(*) 1 | 2
- 计算
-
查询第三条记录:
- 计算
floor(rand(0)*2)=0(第四次计算) - 虚表无0键,需插入:
- 再次计算
floor(rand(0)*2)=1(第五次计算) - 尝试插入虚表:
key | count(*) 1 | 2 - 但1键已存在,主键冲突导致报错
- 再次计算
- 计算
0x06 关键点总结
-
计算次数:
floor(rand(0)*2)在查询过程中被计算多次- 3条记录时共计算5次(查询3次+插入2次)
-
确定性序列:
rand(0)产生固定序列011011...- 第4次计算=0,第5次计算=1,导致主键冲突
-
记录数要求:
- 需要≥3条记录才能确保
floor(rand(0)*2)在插入时产生冲突
- 需要≥3条记录才能确保
-
无参数rand():
- 随机性导致报错不可预测
- 当虚表未同时包含0和1键时可能报错
0x07 实际应用
在SQL注入中,可以利用此报错机制获取数据:
select count(*), concat((select version()), floor(rand(0)*2))x from information_schema.tables group by x;
这将把数据库版本信息包含在错误消息中返回。
0x08 防御措施
- 使用参数化查询
- 对用户输入进行严格过滤
- 避免直接拼接SQL语句
- 设置数据库错误信息不对外显示