反序列化感悟 作者: ynnddddd 时间: 2024-09-30 分类: 网络安全,反序列化 以下是对您提供的技术内容进行标准化整理后的版本: --- # PHP反序列化安全攻防实践指南 ## 一、__wakeup()方法绕过漏洞 ### 1.1 漏洞原理 当反序列化字符串中声明的对象属性数量与实际属性数量不一致时,PHP将跳过`__wakeup()`方法的执行。此特性存在于PHP 5 < 5.6.25和PHP 7 < 7.0.10版本中(CVE-2016-7124)。 ### 1.2 漏洞验证 ```php class HaHaHa { public $admin = 'admin'; public $passwd = 'wllm'; public function __wakeup() { echo "安全检测被绕过!"; } } // 原始序列化数据(触发__wakeup) $payload = 'O:6:"HaHaHa":2:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}'; // 修改后的攻击载荷(绕过__wakeup) $exploit = 'O:6:"HaHaHa":3:{s:5:"admin";s:5:"admin";s:6:"passwd";s:4:"wllm";}'; unserialize($exploit); // 无输出,成功绕过 ``` ### 1.3 防护建议 - 升级至PHP安全版本 - 在反序列化前进行数据签名验证 - 优先使用`__destruct()`承载关键逻辑 --- ## 二、参数传递编码问题 ### 2.1 GET与POST差异对比 | 特性 | GET请求 | POST请求 | |------------|----------------------------|-----------------------------| | 空格编码 | `+`自动转换为空格 | `+`保持原样 | | 最大长度 | 受URL长度限制(约2048字符) | 理论上无限制 | | 数据可见性 | URL明文可见 | 请求体隐藏 | post传参时,经过测试,在url编码前,原字符串有空格,例如命令 `system('cat /flag')`无法执行 ### 2.2 问题复现与解决方案 **问题代码:** ```php // 接收POST数据 $data = $_POST['payload']; $obj = unserialize($data); // 攻击载荷:包含空格命令 O:3:"lyh":3:{s:3:"url";N;s:2:"lt";s:6:"system";s:3:"lly";s:9:"cat /flag";} ``` **编码差异:** ``` 原始空格编码:cat /flag => cat+%2Fflag 正确编码应为:cat%20%2Fflag ``` **解决方案:** ```php // 接收时进行编码转换 $payload = str_replace('+', '%20', $_POST['payload']); $data = rawurldecode($payload); $obj = unserialize($data); ``` --- ## 三、反序列化生命周期详解 ### 3.1 方法执行时序 | 操作类型 | 触发方法 | 执行顺序 | |------------|--------------|--------| | 对象实例化 | __construct | 首次创建时 | | 序列化操作 | __sleep | serialize()时 | | 反序列化操作 | __wakeup | unserialize()时 | | 对象销毁 | __destruct | 销毁时或脚本结束时 | ### 3.2 验证实验 ```php class LifecycleDemo { public function __construct() { echo "[+] 构造函数执行\n"; } public function __wakeup() { echo "[!] 反序列化方法执行\n"; } } // 序列化过程(触发__construct) $serialized = serialize(new LifecycleDemo()); // 反序列化过程(仅触发__wakeup) unserialize($serialized); ``` **执行结果:** ``` [+] 构造函数执行 [!] 反序列化方法执行 ``` ### 3.3 最佳实践 1. **方法分离原则**: - `__construct`:初始化对象基本状态 - `__wakeup`:重建资源连接(数据库、文件句柄等) 2. **安全初始化示例**: ```php class SecureInit { private $dbConnection; public function __construct() { $this->initDatabase(); } public function __wakeup() { $this->__construct(); // 强制重新初始化 } private function initDatabase() { $this->dbConnection = new PDO(...); } } ``` --- ## 四、综合防护策略 1. **输入过滤**: ```php $allowedClasses = ['SafeClassA', 'SafeClassB']; $data = unserialize($input, ['allowed_classes' => $allowedClasses]); ``` 2. **签名验证**: ```php function safe_unserialize($input, $secret) { $data = json_decode(base64_decode($input), true); if (hash_hmac('sha256', $data['payload'], $secret) === $data['signature']) { return unserialize($data['payload']); } throw new Exception("数据校验失败"); } ``` 3. **日志监控**: ```php ini_set('unserialize_callback_func', 'log_callback'); function log_callback($className) { syslog(LOG_WARNING, "可疑反序列化操作: ".$className); } ``` --- ## 附录:相关资源 1. [PHP官方安全公告](https://www.php.net/archive/2016.php#2016-09-22-1) 2. [OWASP反序列化防护指南](https://cheatsheetseries.owasp.org/cheatsheets/Deserialization_Cheat_Sheet.html) 3. [CVE-2016-7124详情](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-7124) --- > **注意事项**: > 1. 所有反序列化操作应视为潜在危险行为 > 2. 生产环境建议禁用`unserialize()`函数 > 3. 使用JSON等安全数据格式替代序列化 通过系统化的安全措施和规范的开发实践,可有效降低反序列化漏洞风险。建议定期进行安全审计和渗透测试,确保防护机制的有效性。 标签: none