1.反序列化漏洞原理
反序列化又叫对象注入,序列化在内部没有漏洞,漏洞产生是应该程序在处理对象、魔术函数以及序列化 相关的问题导致的 当传给 unserialize()的参数可控时,那么用户就可以注入 payload,进行反序列化的时 候就可能触发对象中的一些魔术方法。
2.如何判断是否为反序列化漏洞
1.定位反序列化入口点(Source)
首先,查找程序中所有进行反序列化的函数调用,这是漏洞的起点。
- Java:重点关注
ObjectInputStream.readObject()及其封装方法。 - PHP:重点关注
unserialize()函数。 - Python:重点关注
pickle.loads()等。 - .NET:重点关注 `BinaryFormatter.Deserialize()。
2.追踪数据流(Sink)
确认反序列化的数据是否来自用户可控的输入,如 GET/POST 参数、Cookie、请求头、上传文件等。如果数据完全来自可信的、不可篡改的内部来源(如本地配置文件),风险会低很多。
3.寻找"Gadget 链"(Sink)
反序列化本身无害,危险在于后续被触发的代码。需要寻找程序中是否存在可利用的"代码片段链条",这条链最终会导向能执行危险操作的函数(Sink),如执行系统命令(Runtime.exec(), system())、读写文件等。这通常需要分析类中的魔术方法(如 PHP 的 __destruct()、__wakeup(),Java 的 readObject()),它们会在反序列化过程中自动被调用。
3.反序列化里的魔法函数(PHP)
__construct() 当一个对象创建时被调用 __destruct() 当一个对象销毁前被调用
__sleep() 在对象被序列化前被调用 __wakeup 将在反序列化之后立即被调用
__toString 当一个对象被当做字符串使用时被调用 __get(),__set() 当调用或设置一个类及其父类方法中未定义的属性时
__invoke() 调用函数的方式调用一个对象时的回应方法 __call 和 __callStatic 前者是调用类不存在的方法时执行,而后者是调用类不存在的静态方式方法时执行
4.序列化字符串格式详解
每一种 PHP 数据类型在序列化后都有固定的表示格式。理解这些格式是读懂 payload 和后续手动修改序列化字符串的基础。
| 类型字母 | 含义 | 格式 | 举例 |
|---|---|---|---|
| s | 字符串 | s:长度:"内容"; | s:5:"admin"; |
| S | 二进制字符串 | S:长度:"内容";(\x00 写作 \00) | S:7:"\00*\00name"; |
| i | 整数 | i:值; | i:123; |
| d | 浮点数 | d:值; | d:3.14; |
| b | 布尔数 | b:1;(true)或 b:0;(false) | b:1; |
| a | 数组 | a:长度:{键;值;...} | a:2:{i:0;s:1:"a";i:1;s:1:"b";} |
| O | 普通对象 | O:类名长度:"类名":属性个数:{...} | O:4:"User":1:{s:4:"name";s:5:"admin";} |
| C | 自定义序列化对象 | C:类名长度:"类名":数据长度:{数据} | 实现 Serializable 接口的对象 |
| N | 空值 | N; | N; |
| R | 指针引用 | R:序号; | R:2;(指向序列化中第 2 个对象) |
| r | 值引用 | r:序号; | r:1;(指向序列化中第 1 个值) |
评论区
评论加载中...