Unserialize
1.0 PHP 反序列化
1.1 基础
序列化是将内存中的对象转换为字节序列或字符串的过程, 以便于存储, 传输或在网络传递.
反序列化则是将字节序列或字符串还原为原始对象.
漏洞原理: 反序列化漏洞的本质: 攻击者可控的恶意数据被程序信任并还原为对象, 而程序未对输入进行严格验证.
01 序列化实例:
1 | // 基本类型序列化 |
02 反序列化实例:
1 | // 对象 |
03 进阶案例
- 反序列化特性:
- 反序列化生成的对象, 成员属性值由被反序列化的字符串决定, 与原来类预定义的值无关
- 反序列化使用
unserialize()将字符串转换为对象, 序列化使用serialize()将对象转化为字符串 - 反序列化不触发类的成员方法, 需要调用方法后才能触发
案例1: 修改变量值 [Taobao] → [Baidu]
1 | class main{ |

案例2: 访问控制
PHP 对象序列化后的字符串
1 | O:类名长度:"类名":属性数量:{属性1类型:属性1长度:"属性名";值类型:值长度:"值";...} |
每个属性定义为: 数据类型:长度:值
1 | class main{ |
源码分析: 对于public protected private:
- public
- 格式:
s:属性长度:"属性名";值类型:值长度:"值"; - 无前缀和空字节
- 格式:
- protected
- 格式:
s:属性长度:"\0*\0属性名";值类型:值长度:"值"; - 属性名前加
\0*\0[空字节][*]- 第一个
\0表示protected *是字面量星号- 第二个
\0分隔符
- 第一个
- 格式:
- private
- 格式:
s:属性长度:"\0类名\0属性名";值类型:值长度:"值"; - 属性名前加
\0类名\0即: [空字节] + [所属类名] + [空字节]
- 格式:
注意: 在 URL/HTTP 请求中传递时, 需将空字节写为
%00
如何将byron 改为 by ?
1 |
|
01 序列化对象
1 | $obj = new main(); |
02 将序列URL编码并修改
1 | echo urlencode('O:4:"main":3:{s:4:"name";s:5:"byron";s:6:"*sex";s:3:"男";s:9:"mainage";s:2:"18";}'); |
- 手动修改
byron→by注意: 值长度同步修改 *前后分别增加%00(protected 特性)main前后分别增加%00(private 特性)
03 反序列化
1 | $unser = unserialize(urldecode("O%3A4%3A%22main%22%3A3%3A%7Bs%3A4%3A%22name%22%3Bs%3A2%3A%22by%22%3Bs%3A6%3A%22%00%2A%00sex%22%3Bs%3A3%3A%22%E7%94%B7%22%3Bs%3A9%3A%22%00main%00age%22%3Bs%3A2%3A%2218%22%3B%7D")); |

成功修改
1.2 反序列化漏洞利用
1 | class demo{ |
01 序列化对象
1 | echo serialize(new demo()); |
02 代码执行
1 | // 1. 构造payload |

如图成功执行命令获取IP
1.3 魔术方法
| 函数 | 作用 |
|---|---|
| __construct() | 类的构造函数, 创建对象时触发 |
| __destruct() | 类的析构函数, 对象被销毁时触发 |
| __sleep() | 执行serialize()时, 先调用该方法 |
| __wakeup() | 执行unserialize()时, 先调用该方法 |
Case 1:
1 | class demo{ |
Case 2:
1 | class demo{ |