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