Python反序列化-pyyaml模块
字数 1849 2025-08-22 22:47:39
Python反序列化安全漏洞:PyYAML模块深度解析
1. YAML与PyYAML简介
YAML是一种直观的数据序列化格式,具有以下特点:
- 比XML更简单直观的语法
- 比JSON更灵活的配置能力
- 常用于配置文件解析
- PyYAML是Python中处理YAML格式的主要库
基本函数:
load():返回一个Python对象load_all():生成一个迭代器,用于多文档YAMLdump():将Python对象转为YAML文档dump_all():将多个Python对象输出为多文档YAML
2. PyYAML反序列化漏洞原理
2.1 漏洞本质
PyYAML的反序列化问题本质是对象注入问题,通过构造特殊的YAML标签可以执行任意代码。
2.2 版本差异
- PyYAML < 5.1:默认不安全,直接使用
load()可能导致代码执行 - PyYAML >= 5.1:默认安全,但可通过指定不安全的Loader或使用
unsafe_load()绕过安全限制
2.3 危险构造器
PyYAML通过以下构造器实现对象反序列化,这些是漏洞的关键点:
Constructor.add_multi_constructor(
'tag:yaml.org,2002:python/object:',
Constructor.construct_python_object)
Constructor.add_multi_constructor(
'tag:yaml.org,2002:python/object/apply:',
Constructor.construct_python_object_apply)
Constructor.add_multi_constructor(
'tag:yaml.org,2002:python/object/new:',
Constructor.construct_python_object_new)
3. 漏洞利用方式
3.1 通用POC
以下payload可用于测试和利用PyYAML反序列化漏洞:
!!python/object/apply:os.system ["calc.exe"]
!!python/object/new:os.system ["calc.exe"]
!!python/object/new:subprocess.check_output [["calc.exe"]]
!!python/object/apply:subprocess.check_output [["calc.exe"]]
3.2 自定义类利用
可以构造自定义类的序列化字符串:
import os
import yaml
class MaliciousClass:
def __init__(self):
os.system("calc.exe")
payload = yaml.dump(MaliciousClass())
# 结果: !!python/object:__main__.MaliciousClass {}
使用时需要确保目标环境中存在对应的模块和类。
4. 安全机制分析
4.1 SafeLoader限制
safe_load()使用的SafeLoader只允许基本类型的反序列化:
SafeConstructor.add_constructor(
'tag:yaml.org,2002:null',
SafeConstructor.construct_yaml_null)
# 其他基本类型类似...
4.2 FullLoader改进
PyYAML >=5.1默认使用FullLoader,虽然保留了对象构造能力,但在make_python_instance函数中添加了限制,阻止直接调用系统函数。
5. 防御措施
5.1 安全使用方法
| 安全方法 | 说明 |
|---|---|
safe_load() |
只允许基本类型反序列化 |
load(..., Loader=SafeLoader) |
显式指定安全加载器 |
safe_dump() |
安全序列化方法 |
5.2 其他YAML库
ruamel.yaml库与PyYAML用法相似,也提供了相应的安全方法:
| 安全方法 (PyYAML) | 安全方法 (ruamel.yaml) |
|---|---|
safe_load() |
safe_load() |
safe_load_all() |
safe_load_all() |
load(...,Loader=Safeloader) |
load(...,Loader=Safeloader) |
safe_dump() |
safe_dump() |
safe_dump_all() |
safe_dump_all() |
6. 代码分析关键点
-
构造过程:
- 解析YAML标签(如
!!python/object/apply) - 调用对应的构造器函数
- 最终通过
make_python_instance创建对象实例
- 解析YAML标签(如
-
安全差异:
- SafeLoader不注册任何
python/object相关的构造器 - FullLoader注册了对象构造器但添加了执行限制
- UnsafeLoader/旧版本Loader允许直接执行
- SafeLoader不注册任何
7. 实际应用建议
-
配置检查:
- 确保使用PyYAML >=5.1版本
- 检查代码中所有
yaml.load()调用是否指定了安全Loader
-
代码审计重点:
- 查找直接使用
load()的调用 - 检查Loader参数是否可能被操控
- 验证是否有使用
unsafe_load()
- 查找直接使用
-
替代方案:
- 对于纯配置读取,考虑使用JSON
- 必须使用YAML时,采用
safe_load() - 考虑使用
ruamel.yaml替代PyYAML
8. 总结
PyYAML反序列化漏洞是一个典型的不安全反序列化案例,其核心问题在于:
- 默认情况下允许反序列化任意Python对象
- 通过特殊标签可以执行系统命令
- 虽然新版本有所改进,但不安全的用法仍然存在
开发者应当始终使用安全的方法处理YAML数据,特别是在处理不可信输入时。安全团队在审计Python应用时,应将PyYAML的使用作为重点检查对象。