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'

关键点:

  1. 'security1'中的'security'来自database()函数执行结果
  2. '1'来自floor(rand(0)*2)的计算结果
  3. 报错表明临时表中已存在'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工作机制

  1. 执行GROUP BY时,会创建临时表,GROUP BY的列作为临时表主键
  2. 处理流程:
    • 取出查询表中的记录
    • 检查临时表是否存在该主键
      • 存在:count(*)值加1
      • 不存在:将该主键插入临时表(count(*)初始为1)

七、报错原理详解

关键特性:当临时表中没有某主键时,在插入前rand()会再计算一次

具体流程(以rand(0)为例):

  1. 处理第一条记录:

    • 计算group by key应为'security0'
    • 发现临时表无此主键,rand()再次计算得到1
    • 实际插入的主键变为'security1',count=1
  2. 处理第二条记录:

    • 计算group by key为'security1'
    • 临时表已有此主键,count加1变为2
  3. 处理第三条记录:

    • 计算group by key为'security0'
    • 发现临时表无此主键,rand()再次计算得到1
    • 尝试插入'security1',但主键已存在,导致报错

八、必要条件

  1. 表中至少需要3条记录(因为需要触发第三次计算)
  2. 可以通过选择特定种子减少所需记录数:
    • 如rand(14)*2的序列为1,0,1,0...
    • 这样只需2条记录即可触发报错

九、总结

floor()报错注入的核心原理:

  1. GROUP BY与RAND()联用时,在插入临时表前RAND()会多次计算
  2. 这种多次计算导致临时表主键重复
  3. 报错前CONCAT()中的函数已被执行,结果通过报错信息泄露

十、防御建议

  1. 对用户输入进行严格过滤和参数化查询
  2. 避免在SQL语句中直接拼接用户输入
  3. 使用最小权限原则,限制数据库用户权限
  4. 及时更新MySQL到最新版本,修复已知漏洞
MySQL floor()报错注入原理详解 一、概述 floor()报错注入(也称group报错注入)是一种利用MySQL数据库GROUP BY子句与RAND()函数特性实现的SQL注入技术。通过精心构造的SQL语句,攻击者可以触发数据库报错并泄露敏感信息。 二、测试环境 MySQL版本:5.5.53 测试数据库:security.users(来自sqli-labs) 三、典型报错语句 两条语句功能相同,第二条中的 as x 是前一个表达式的别名。 四、报错信息分析 执行后会报错: 关键点: '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到最新版本,修复已知漏洞