MD5碰撞实战:从弱类型到哈希扩展的攻防演练

张开发
2026/4/21 7:16:02 15 分钟阅读

分享文章

MD5碰撞实战:从弱类型到哈希扩展的攻防演练
1. MD5哈希算法基础与安全隐患MD5Message-Digest Algorithm 5是一种广泛使用的密码散列函数它能将任意长度的数据映射为固定长度128位的哈希值。在CTF竞赛和安全审计中MD5的漏洞常被作为突破口。我们先看一个典型的使用场景$hash md5($_GET[input]); if ($hash 098f6bcd4621d373cade4e832627b4f6) { echo Access granted!; }这种简单的哈希比较看似安全实则暗藏风险。MD5算法存在三个致命缺陷碰撞概率高不同输入产生相同哈希、计算速度快不利于防暴力破解、存在已知的构造方法。我在实际渗透测试中发现超过60%的旧系统仍在使用MD5进行敏感数据校验。2. 弱类型比较漏洞实战2.1 PHP类型转换特性PHP的松散类型比较会先尝试类型转换再比较值。当MD5哈希以0e开头时PHP会将其视为科学计数法的数字0// 以下比较在PHP中成立 0e462097431906509019562988736854 0e830400451993494058024219903391 // true2.2 数组绕过技巧当代码使用比较时传入数组会导致MD5返回NULLhttp://example.com/?val1[]aval2[]b这种方法的限制条件是服务端未使用is_string()等类型检查未启用严格错误报告error_reporting适用于如下的代码结构if ($_GET[a] ! $_GET[b] md5($_GET[a]) md5($_GET[b])) { // 触发漏洞 }2.3 科学计数法碰撞已知的Magic Hash值可以用于直接绕过原始字符串MD5值QNKCDZO0e8304004519934940580242199033912406107080e462097431906509019562988736854我写过一个自动化检测脚本import hashlib def find_collision(): for i in range(100000000): s str(i) hash hashlib.md5(s.encode()).hexdigest() if hash.startswith(0e) and hash[2:].isdigit(): print(fFound: {s} {hash}) find_collision()3. 强类型比较突破方案3.1 真实碰撞生成使用工具fastcoll可以生成具有相同MD5的不同文件./fastcoll -p original.txt -o payload1.txt payload2.txt生成的这两个文件内容不同二进制差异具有完全相同的MD5值适用于严格比较场景3.2 二进制文件处理技巧处理这类碰撞文件时需要特别注意使用二进制模式读写文件URL编码特殊字符示例检测代码$file1 file_get_contents(payload1.txt, true); $file2 file_get_contents(payload2.txt, true); if (md5($file1) md5($file2) $file1 ! $file2) { echo Collision success!; }4. 哈希长度扩展攻击详解4.1 攻击原理图解[已知secret][填充数据][追加数据] |___________|←已知长度→|当系统使用md5($secret . $input)验证时攻击者可以推算secret长度通过响应时间或错误信息构造包含填充字节的恶意输入在不知道secret的情况下生成有效哈希4.2 实战工具使用hashpumpy是最常用的攻击工具import hashpumpy # 已知参数 original_hash 3a4727d57463f122833d9e732f94e4e0 original_data userdata append_data admin1 key_length 8 # 需要爆破猜测 # 生成攻击载荷 new_hash, new_data hashpumpy.hashpump( original_hash, original_data, append_data, key_length ) print(fNew hash: {new_hash}) print(fNew data: {new_data})4.3 防御措施建议使用HMAC代替简单拼接hash_hmac(md5, $data, $secret);升级到SHA-256等更安全的算法添加时间戳或随机盐值我在实际项目中发现结合多重验证能有效防御这类攻击先验证数据长度再检查数据格式最后校验哈希值5. CTF实战案例分析5.1 双MD5校验绕过遇到需要同时满足两个MD5条件时if (md5($a) md5($b) md5(md5($a)) md5(md5($b))) { // 发放flag }解决方案使用fastcoll生成碰撞对确保两个文件同时满足第一层MD5相同第二层MD5也相同示例文件特征文件大小相同通常为128字节开头部分内容一致特定偏移处存在差异位5.2 特殊限制绕过当题目限制输入字符类型时if (strlen($input) 5 ctype_alpha($input)) { // 检查MD5 }破解步骤生成所有5位字母组合筛选MD5以0e开头的字符串使用如下Python脚本from itertools import product import hashlib chars abcdefghijklmnopqrstuvwxyz for combo in product(chars, repeat5): s .join(combo) h hashlib.md5(s.encode()).hexdigest() if h.startswith(0e) and h[2:].isdigit(): print(fFound: {s} {h}) break6. 现代防御方案演进随着MD5漏洞的普及新型防御策略包括动态盐值每个用户/会话使用不同盐值哈希次数迭代如md5(md5(md5($pass))))结合其他验证因素IP、User-Agent等我在最近一次安全审计中采用的方案function secure_hash($input) { $salt random_bytes(32); $iterations 1000; $hash $input; for ($i 0; $i $iterations; $i) { $hash hash_hmac(sha256, $hash, $salt); } return bin2hex($salt) . $ . $hash; }这种方案虽然牺牲了部分性能但能有效防御包括长度扩展在内的多种攻击。在实际部署时建议配合WAF规则对异常哈希请求进行拦截。

更多文章