PHP反序列化原理及绕过技巧解析
PHP序列化常用于数据缓存传输。掌握序列化结构与魔术方法(如__wakeup)是理解漏洞的基础。本文将解析PHP反序列化核心原理,并详细说明如何绕过正则过滤、CVE-2016-7124缺陷及属性校验等常见安全措施。
反序列化简介与魔术方法
在PHP开发中,序列化(Serialization)是将对象转换为可存储或传输的字符串过程,反序列化则是还原该对象的过程。这一机制广泛应用于Session缓存、Cookie传递或跨服务器数据传输。
反序列化的核心在于类中定义的“魔术方法”(Magic Methods),它们在特定生命周期被自动调用:
__wakeup():执行unserialize()时立即触发。__sleep():执行serialize()前触发,用于定义需要序列化的属性。__destruct():对象在所有引用被删除后销毁时触发。__get() / __set():读写不可访问或未定义属性的触发器。__call() / __callStatic():调用不可访问的方法时的静态与非静态触发器。__toString():将对象当作字符串输出(如echo $obj;)时触发。__invoke():尝试将对象作为函数调用时触发。
反序列化绕过技巧与原理
在实际安全测试中,常遇到WAF或过滤代码对序列化字符串进行限制。以下列举几种经典的绕过策略。
第1步:利用属性不敏感绕过(PHP 7.1+)
在早期的PHP版本中,不同可见性属性的序列化字符串有明显区分:
- Public属性:直接存储名字。
- Protected属性:以 %00*%00 包裹。
- Private属性:以 %00类名%00 包裹。
但在 PHP 7.1 及以上版本,反序列化引擎变得不敏感,不再严格区分属性可见性的特殊字符。这意味着即使序列化字符串中缺少这些字节,也能正确识别属性并赋值。
<?php
class test{
protected $a;
public function __construct(){
$this->a = 'abc';
}
public function __destruct(){
echo $this->a;
}
}
// 即使使用了public的格式 s:1:"a",依然能生效
unserialize('O:4:"test":1:{s:1:"a";s:3:"abc";}');第2步:跳过 __wakeup 执行(CVE-2016-7124)
此漏洞影响版本:
- PHP 5 < 5.6.25
- PHP 7 < 7.0.10
利用条件:当序列化字符串中表示的对象属性个数(count)大于实际属性个数时,__wakeup() 将被跳过,从而无法执行清理操作或关闭某些功能。
修改序列化字符串中的数值部分即可实现绕过:
// 原始对象有两个属性,但构造只赋值了一个,此处演示伪造
// O:4:"test":1:{...} 改为 O:4:"test":2:{...}注意:在PHP 7.0.10之后该Trick已失效,新版本引入了严格的长度检查。
第3步:利用数组闭合绕过正则检测
许多过滤器使用 preg_match('/^O:\d+/') 拦截对象序列化开头。如果我们将目标对象放入数组中,外层将是数组标识符 a:,而对象位于内部,可完美绕过开头检测。
<?php
function match($data){
if (preg_match('/^O:\d+/',$data)){
die('Blocked!');
}else{
return $data;
}
}
// 正常对象开头是 O:4:"test"
$payload = 'a:1:{i:0;O:4:"test":1:{s:1:"a";s:3:"abc";}}';
unserialize(match($payload)); // 成功通过,内部test对象析构第4步:利用加号伪装整数
PHP允许在整数前添加正负号。通过将 O:4 修改为 O:+4,可以改变字符串外观以混淆正则表达式(如匹配非数字开头的场景):
$a = 'O:4:"test":1:{s:1:"a";s:3:"abc";}';
$b = str_replace('O:4', 'O:+4', $a);
unserialize($b); // 仍然能被解析第5步:属性引用特性与十六进制编码
引用:若在 __construct 中设置变量引用(如 $this->b = &$this->a;),反序列化后可通过比较两者值达到特定逻辑判断。
十六进制:序列化字符串中的键名(string)支持十六进制转义。例如小写字母 a 可写为 \61,这可用于绕过简单的黑名单:
标准:s:1:"a" → 十六进制改写:S:1:"\61" (注意 S 大写在某些情况下也会引发解析变化,主要利用其表示字符类型的灵活性)。
总结
了解序列化字符串的结构是防御和检测反序列化漏洞的关键。从简单的魔术方法调用到复杂的绕过技巧(如CVE修复前的版本差异、引用传递等),每一个点都可能成为代码审计的重点。
以上就是PHP浅析反序列化结构及常见绕过技术的详细内容,更多关于PHP安全与反序列化漏洞防护的资料请关注本站其它相关文章!
本站声明
本文内容仅供参考,不代表本站观点。转载或引用请注明出处。如发现内容问题,请通过联系我们页面反馈。













