关于floor()报错注入,你真的懂了吗?
字数 1740 2025-08-15 21:32:56

MySQL Floor()报错注入原理详解

一、概述

Floor报错注入(也称为Group报错注入)是一种利用MySQL数据库特性实现的SQL注入技术。其核心是利用floor()rand()group by等函数的特殊交互行为,通过故意制造主键冲突来触发数据库报错,同时将敏感信息通过错误消息泄露出来。

二、环境要求

  • MySQL版本:5.5.53(其他版本也可能适用)
  • 需要能够执行多行SQL语句的环境
  • 目标表需要包含足够的数据记录(至少2条)

三、基本注入语句

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;

这两个语句功能相同,后者使用了别名x来简化表达式。

四、关键函数解析

1. rand()函数

  • 返回一个随机浮点值,范围在[0,1]之间
  • 当指定整数参数N时(如rand(0)),N作为种子值,产生可重复的随机序列
  • rand(0)*2将范围扩展到[0,2]

2. floor()函数

  • 返回不大于x的最大整数值
  • 示例:
    • floor(3.3) → 3
    • floor(-3.3) → -4
    • floor(rand(0)*2) → 0或1

3. concat()函数

  • 字符串拼接函数
  • 如果任一参数为NULL,则返回NULL
  • 示例:concat('security',floor(rand(0)*2)) → 'security0'或'security1'

4. count()函数

  • 聚合函数,计算行数
  • count(*)计算所有行数,包括NULL值

五、报错原理详解

1. group by的工作机制

当执行group by时,MySQL会:

  1. 创建一个临时表
  2. group by的列作为临时表的主键
  3. 对于每行数据:
    • 如果主键已存在,则计数器加1
    • 如果主键不存在,则插入新记录并将计数器设为1

2. 关键特性

rand()group by中的特殊行为:当临时表中不存在某主键时,在插入前rand()会再计算一次。这意味着:

  1. 第一次计算:决定是否需要在临时表中创建该主键
  2. 第二次计算:决定实际插入的主键值

3. 报错过程分析

select count(*) from users group by concat(database(),floor(rand(0)*2));为例:

  1. 处理第1条记录:

    • 计算floor(rand(0)*2) → 0 → 'security0'
    • 临时表无'security0',准备插入
    • 插入前rand()再次计算 → 1 → 实际插入'security1',计数1
  2. 处理第2条记录:

    • floor(rand(0)*2)继续计算 → 1 → 'security1'
    • 临时表已有'security1',计数加1 → 2
  3. 处理第3条记录:

    • floor(rand(0)*2)计算 → 0 → 'security0'
    • 临时表无'security0',准备插入
    • 插入前rand()再次计算 → 1 → 尝试插入'security1'
    • 但'security1'已存在 → 主键冲突报错

报错信息:ERROR 1062 (23000): Duplicate entry 'security1' for key 'group_key'

六、优化技巧

  1. 减少所需记录数:寻找特定的随机种子,使floor(rand(N)*2)产生0101或1010序列

    • 例如rand(14)产生的序列为101000...
    • 这样只需要2条记录就能触发报错
  2. 测试语句

-- 创建只有两条记录的测试表
create table test(id int);
insert into test values(1),(2);

-- 使用rand(14)进行注入
select count(*) from test group by concat(database(),floor(rand(14)*2));

七、限制条件

  1. 目标表必须包含至少2条记录
  2. 需要能够执行多行SQL语句的环境
  3. 依赖于MySQL特定版本的实现细节

八、防御措施

  1. 使用参数化查询
  2. 对用户输入进行严格过滤
  3. 限制数据库错误信息的显示
  4. 使用最低权限原则设置数据库账户

九、总结

Floor报错注入的本质是:group by在向临时表插入数据时,由于rand()多次计算导致插入的主键与已有主键冲突而报错。报错信息中包含了concat()中函数执行的结果(如database()),从而泄露敏感信息。

理解这一原理有助于安全人员更好地检测和防御此类注入攻击,同时也提醒开发人员注意数据库函数间的交互可能带来的安全隐患。

MySQL Floor()报错注入原理详解 一、概述 Floor报错注入(也称为Group报错注入)是一种利用MySQL数据库特性实现的SQL注入技术。其核心是利用 floor() 、 rand() 和 group by 等函数的特殊交互行为,通过故意制造主键冲突来触发数据库报错,同时将敏感信息通过错误消息泄露出来。 二、环境要求 MySQL版本:5.5.53(其他版本也可能适用) 需要能够执行多行SQL语句的环境 目标表需要包含足够的数据记录(至少2条) 三、基本注入语句 这两个语句功能相同,后者使用了别名 x 来简化表达式。 四、关键函数解析 1. rand()函数 返回一个随机浮点值,范围在[ 0,1 ]之间 当指定整数参数N时(如 rand(0) ),N作为种子值,产生可重复的随机序列 rand(0)*2 将范围扩展到[ 0,2 ] 2. floor()函数 返回不大于x的最大整数值 示例: floor(3.3) → 3 floor(-3.3) → -4 floor(rand(0)*2) → 0或1 3. concat()函数 字符串拼接函数 如果任一参数为NULL,则返回NULL 示例: concat('security',floor(rand(0)*2)) → 'security0'或'security1' 4. count()函数 聚合函数,计算行数 count(*) 计算所有行数,包括NULL值 五、报错原理详解 1. group by的工作机制 当执行 group by 时,MySQL会: 创建一个临时表 group by 的列作为临时表的主键 对于每行数据: 如果主键已存在,则计数器加1 如果主键不存在,则插入新记录并将计数器设为1 2. 关键特性 rand() 在 group by 中的特殊行为 :当临时表中不存在某主键时,在插入前 rand() 会再计算一次。这意味着: 第一次计算:决定是否需要在临时表中创建该主键 第二次计算:决定实际插入的主键值 3. 报错过程分析 以 select count(*) from users group by concat(database(),floor(rand(0)*2)); 为例: 处理第1条记录: 计算 floor(rand(0)*2) → 0 → 'security0' 临时表无'security0',准备插入 插入前 rand() 再次计算 → 1 → 实际插入'security1',计数1 处理第2条记录: floor(rand(0)*2) 继续计算 → 1 → 'security1' 临时表已有'security1',计数加1 → 2 处理第3条记录: floor(rand(0)*2) 计算 → 0 → 'security0' 临时表无'security0',准备插入 插入前 rand() 再次计算 → 1 → 尝试插入'security1' 但'security1'已存在 → 主键冲突报错 报错信息: ERROR 1062 (23000): Duplicate entry 'security1' for key 'group_key' 六、优化技巧 减少所需记录数 :寻找特定的随机种子,使 floor(rand(N)*2) 产生0101或1010序列 例如 rand(14) 产生的序列为101000... 这样只需要2条记录就能触发报错 测试语句 : 七、限制条件 目标表必须包含至少2条记录 需要能够执行多行SQL语句的环境 依赖于MySQL特定版本的实现细节 八、防御措施 使用参数化查询 对用户输入进行严格过滤 限制数据库错误信息的显示 使用最低权限原则设置数据库账户 九、总结 Floor报错注入的本质是: group by 在向临时表插入数据时,由于 rand() 多次计算导致插入的主键与已有主键冲突而报错。报错信息中包含了 concat() 中函数执行的结果(如 database() ),从而泄露敏感信息。 理解这一原理有助于安全人员更好地检测和防御此类注入攻击,同时也提醒开发人员注意数据库函数间的交互可能带来的安全隐患。