[红日安全]代码审计Day17 - Raw MD5 Hash引发的注入
字数 1346 2025-08-18 11:37:49

MD5 Raw Hash引发的SQL注入漏洞分析与防御

漏洞原理

背景知识

  1. MD5函数特性

    • PHP中的md5()函数有两个参数:string $strbool $raw_output(默认为false)
    • $raw_output设置为true时,返回16字节长度的原始二进制格式,而不是32字符的十六进制数
  2. 原始二进制格式的特殊性

    • 原始二进制可能包含特殊字符,如单引号(')、反斜杠(\)等
    • 这些特殊字符在SQL查询中可能改变查询语义

漏洞产生条件

  1. 代码中直接使用md5($password, true)的结果拼接SQL语句
  2. 没有对MD5原始输出进行适当的转义或过滤
  3. 使用用户可控的输入作为MD5函数的输入

漏洞分析

示例代码分析

$password = $_POST['password'];
$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";

已知可利用的payload

  1. ffifdyop

    • MD5哈希:276f722736c95d99e921722cf9ed621c
    • 原始二进制:'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c
  2. 129581926211651571912466741651878684928

    • 同样会产生包含'or'的原始二进制结果

注入原理

当使用上述特殊字符串时,SQL查询会变为:

SELECT * FROM admin WHERE username = 'admin' and password = ''or'6\xc9]\x99...'

由于and优先级高于or,查询条件变为:

  1. 先计算username = 'admin' and password = ''(结果为false)
  2. 然后计算false or '6\xc9]\x99...'(非零字符串在布尔上下文中为true)

漏洞验证

测试方法

  1. 使用已知payload:

    • 用户名:任意(或admin)
    • 密码:ffifdyop129581926211651571912466741651878684928
  2. 观察响应:

    • 成功登录或返回管理员权限相关信息

防御措施

代码层面

  1. 避免使用原始MD5输出

    // 不安全
    md5($password, true);
    
    // 安全
    md5($password); // 默认false,返回32字符十六进制
    
  2. 使用参数化查询

    $stmt = $pdo->prepare("SELECT * FROM admin WHERE username = :user AND password = MD5(:pass)");
    $stmt->execute(['user' => $user, 'pass' => $password]);
    
  3. 二次转义处理

    $hashed = addslashes(md5($password, true));
    

架构层面

  1. 使用更安全的哈希算法(如bcrypt、Argon2)替代MD5
  2. 实施最小权限原则,限制数据库用户权限
  3. 部署WAF(Web应用防火墙)检测和阻止SQL注入尝试

实际案例

CTF题目分析

$password=$_POST['password'];
$sql = "SELECT * FROM admin WHERE username = 'admin' and password = '".md5($password,true)."'";
if(mysqli_num_rows($result)>0){
    echo 'you are admin';
}

利用方法

  1. 提交密码为ffifdyop
  2. 生成的SQL条件变为password = ''or'6\xc9]\x99...'
  3. 绕过认证,获取管理员权限

扩展思考

其他可能受影响的场景

  1. 文件操作:当MD5原始输出用于文件名时可能导致路径穿越
  2. 序列化数据:特殊字符可能破坏序列化结构
  3. 日志记录:原始二进制可能破坏日志格式

相关漏洞

  1. 反斜杠逃逸

    • addslashes()处理后的数据与原始二进制结合时,可能产生类似Day13的注入
  2. 字符编码问题

    • 宽字节注入等与字符集相关的注入方式

总结

MD5原始哈希输出引发的SQL注入是一种特殊类型的注入漏洞,它利用了哈希函数的二进制输出特性。防御此类漏洞的关键在于:

  1. 避免使用md5(..., true)的原始二进制输出
  2. 对所有数据库输入进行适当处理
  3. 优先使用参数化查询而非字符串拼接
  4. 定期进行安全审计和代码审查

通过理解这种漏洞的原理和利用方式,开发人员可以更好地编写安全的代码,防止类似安全问题发生。

MD5 Raw Hash引发的SQL注入漏洞分析与防御 漏洞原理 背景知识 MD5函数特性 : PHP中的 md5() 函数有两个参数: string $str 和 bool $raw_output (默认为false) 当 $raw_output 设置为true时,返回16字节长度的原始二进制格式,而不是32字符的十六进制数 原始二进制格式的特殊性 : 原始二进制可能包含特殊字符,如单引号( ' )、反斜杠( \ )等 这些特殊字符在SQL查询中可能改变查询语义 漏洞产生条件 代码中直接使用 md5($password, true) 的结果拼接SQL语句 没有对MD5原始输出进行适当的转义或过滤 使用用户可控的输入作为MD5函数的输入 漏洞分析 示例代码分析 已知可利用的payload ffifdyop : MD5哈希: 276f722736c95d99e921722cf9ed621c 原始二进制: 'or'6\xc9]\x99\xe9!r,\xf9\xedb\x1c 129581926211651571912466741651878684928 : 同样会产生包含 'or' 的原始二进制结果 注入原理 当使用上述特殊字符串时,SQL查询会变为: 由于 and 优先级高于 or ,查询条件变为: 先计算 username = 'admin' and password = '' (结果为false) 然后计算 false or '6\xc9]\x99...' (非零字符串在布尔上下文中为true) 漏洞验证 测试方法 使用已知payload: 用户名:任意(或admin) 密码: ffifdyop 或 129581926211651571912466741651878684928 观察响应: 成功登录或返回管理员权限相关信息 防御措施 代码层面 避免使用原始MD5输出 : 使用参数化查询 : 二次转义处理 : 架构层面 使用更安全的哈希算法(如bcrypt、Argon2)替代MD5 实施最小权限原则,限制数据库用户权限 部署WAF(Web应用防火墙)检测和阻止SQL注入尝试 实际案例 CTF题目分析 利用方法 : 提交密码为 ffifdyop 生成的SQL条件变为 password = ''or'6\xc9]\x99...' 绕过认证,获取管理员权限 扩展思考 其他可能受影响的场景 文件操作:当MD5原始输出用于文件名时可能导致路径穿越 序列化数据:特殊字符可能破坏序列化结构 日志记录:原始二进制可能破坏日志格式 相关漏洞 反斜杠逃逸 : 当 addslashes() 处理后的数据与原始二进制结合时,可能产生类似Day13的注入 字符编码问题 : 宽字节注入等与字符集相关的注入方式 总结 MD5原始哈希输出引发的SQL注入是一种特殊类型的注入漏洞,它利用了哈希函数的二进制输出特性。防御此类漏洞的关键在于: 避免使用 md5(..., true) 的原始二进制输出 对所有数据库输入进行适当处理 优先使用参数化查询而非字符串拼接 定期进行安全审计和代码审查 通过理解这种漏洞的原理和利用方式,开发人员可以更好地编写安全的代码,防止类似安全问题发生。