Python代码审计实战案例总结之反序列化和命令执行
字数 1985 2025-08-15 21:30:31

Python代码审计实战:反序列化与命令执行漏洞详解

一、反序列化漏洞审计

1.1 Python反序列化模块概述

Python中常见的反序列化模块包括:

  • pickle/cPickle:Python原生序列化模块
  • yaml:YAML格式处理模块
  • json:JSON格式处理模块(相对安全)

其中pickleyaml是最常出现安全问题的模块。

1.2 反序列化漏洞原理

反序列化漏洞的核心在于:当程序从不可信源加载序列化数据时,攻击者可以构造恶意序列化数据,在反序列化过程中执行任意代码。

危险方法:

  • pickle.load()/pickle.loads()
  • yaml.load()/yaml.loads()

安全替代方法:

  • pickle:无完全安全的替代方案,应避免反序列化不可信数据
  • yaml:使用yaml.safe_load()替代yaml.load()
  • json:使用json.loads()

1.3 实战案例1:dask反序列化漏洞(CNVD-2019-16789)

漏洞分析:

  • 影响版本:dask 1.1.4
  • 漏洞文件:config.py
  • 关键代码位置:第139行collect_yaml方法
  • 漏洞触发点:第168行yaml.load()调用

漏洞利用条件:

  • 程序从可控的YAML文件加载配置
  • 使用了不安全的yaml.load()而非yaml.safe_load()

修复方案:

yaml.load()替换为yaml.safe_load()

1.4 实战案例2:NumPy命令执行漏洞(CVE-2019-6446)

漏洞分析:

  • 影响版本:NumPy < 1.16.0
  • 漏洞文件:lib/npyio.py
  • 关键参数:allow_pickle=True(默认值)
  • 漏洞触发流程:
    1. NumPy.lib.npyio.py:load()
    2. pickle.py:load()

漏洞利用条件:

  • 加载的文件不是有效的NumPy二进制文件或ZIP文件
  • allow_pickle参数为True(默认值)

POC示例:

from numpy.lib import npyio
import os
import pickle

class Test(object):
    def __reduce__(self):
        return (os.system, ('whoami',))

tmpdaa = Test()
with open("test-file.pickle", 'wb') as f:
    pickle.dump(tmpdaa, f)
npyio.load("test-file.pickle")

修复方案:

  • 升级NumPy到1.16.0及以上版本
  • 调用load()时设置allow_pickle=False

二、命令执行漏洞审计

2.1 常见危险函数

Python中可能导致命令执行的函数:

  • os.system()
  • os.popen()
  • subprocess.Popen()
  • commands.getoutput()(Python 2)
  • eval()
  • exec()

2.2 审计要点

  1. 查找上述危险函数的调用
  2. 检查参数是否可控
  3. 检查是否有适当的过滤和验证

2.3 实战案例1:numexpr命令执行漏洞(CNVD-2019-17298)

漏洞分析:

  • 漏洞文件:numexpr/cpuinfo.py
  • 关键代码位置:第37行getoutput方法
  • 平台限制:仅Linux系统可利用
  • 触发条件:
    • os.WIFEXITED(status)为True
    • os.WEXITSTATUS(status)successful_status

漏洞原理:

通过控制successful_status参数,可以绕过安全检查执行任意命令。

2.4 实战案例2:dotenv命令执行漏洞(CNVD-2019-17299)

漏洞分析:

  • 影响版本:dotenv 0.10.1
  • 漏洞文件:main.py
  • 关键代码位置:第317行
  • 漏洞原因:未对命令参数进行过滤

漏洞利用条件:

  • 能够控制传入的环境变量或命令参数

三、防御方案

3.1 反序列化漏洞防御

  1. 避免反序列化不可信数据
  2. 使用安全的替代方法:
    • yaml.safe_load()替代yaml.load()
    • json.loads()替代pickle.loads()
  3. 对序列化数据进行签名验证

3.2 命令执行漏洞防御

  1. 避免使用危险函数
  2. 使用安全的替代方法:
    • subprocess.run()替代os.system()
  3. 对用户输入进行严格过滤和验证
  4. 使用白名单机制限制可执行命令

四、审计方法论

4.1 审计流程

  1. 识别危险模块和函数
  2. 跟踪用户输入流向
  3. 检查安全控制措施
  4. 验证漏洞可利用性

4.2 工具推荐

  1. 静态分析工具:
    • Bandit
    • PyLint
    • Safety
  2. 动态分析工具:
    • 交互式调试器
    • 请求拦截代理

4.3 重点关注

  1. 反序列化操作
  2. 系统命令执行
  3. 文件操作
  4. 数据库操作
  5. 模板渲染

五、总结

Python代码审计需要重点关注:

  1. 反序列化操作(pickle/yaml)
  2. 命令执行函数调用
  3. 用户输入流向
  4. 平台特性差异

通过案例学习可以积累审计经验,提高发现漏洞的效率。在实际审计中,应结合静态分析和动态验证,全面评估代码安全性。

Python代码审计实战:反序列化与命令执行漏洞详解 一、反序列化漏洞审计 1.1 Python反序列化模块概述 Python中常见的反序列化模块包括: pickle / cPickle :Python原生序列化模块 yaml :YAML格式处理模块 json :JSON格式处理模块(相对安全) 其中 pickle 和 yaml 是最常出现安全问题的模块。 1.2 反序列化漏洞原理 反序列化漏洞的核心在于:当程序从不可信源加载序列化数据时,攻击者可以构造恶意序列化数据,在反序列化过程中执行任意代码。 危险方法: pickle.load() / pickle.loads() yaml.load() / yaml.loads() 安全替代方法: pickle :无完全安全的替代方案,应避免反序列化不可信数据 yaml :使用 yaml.safe_load() 替代 yaml.load() json :使用 json.loads() 1.3 实战案例1:dask反序列化漏洞(CNVD-2019-16789) 漏洞分析: 影响版本:dask 1.1.4 漏洞文件: config.py 关键代码位置:第139行 collect_yaml 方法 漏洞触发点:第168行 yaml.load() 调用 漏洞利用条件: 程序从可控的YAML文件加载配置 使用了不安全的 yaml.load() 而非 yaml.safe_load() 修复方案: 将 yaml.load() 替换为 yaml.safe_load() 1.4 实战案例2:NumPy命令执行漏洞(CVE-2019-6446) 漏洞分析: 影响版本:NumPy < 1.16.0 漏洞文件: lib/npyio.py 关键参数: allow_pickle=True (默认值) 漏洞触发流程: NumPy.lib.npyio.py:load() pickle.py:load() 漏洞利用条件: 加载的文件不是有效的NumPy二进制文件或ZIP文件 allow_pickle 参数为True(默认值) POC示例: 修复方案: 升级NumPy到1.16.0及以上版本 调用 load() 时设置 allow_pickle=False 二、命令执行漏洞审计 2.1 常见危险函数 Python中可能导致命令执行的函数: os.system() os.popen() subprocess.Popen() commands.getoutput() (Python 2) eval() exec() 2.2 审计要点 查找上述危险函数的调用 检查参数是否可控 检查是否有适当的过滤和验证 2.3 实战案例1:numexpr命令执行漏洞(CNVD-2019-17298) 漏洞分析: 漏洞文件: numexpr/cpuinfo.py 关键代码位置:第37行 getoutput 方法 平台限制:仅Linux系统可利用 触发条件: os.WIFEXITED(status) 为True os.WEXITSTATUS(status) 在 successful_status 中 漏洞原理: 通过控制 successful_status 参数,可以绕过安全检查执行任意命令。 2.4 实战案例2:dotenv命令执行漏洞(CNVD-2019-17299) 漏洞分析: 影响版本:dotenv 0.10.1 漏洞文件: main.py 关键代码位置:第317行 漏洞原因:未对命令参数进行过滤 漏洞利用条件: 能够控制传入的环境变量或命令参数 三、防御方案 3.1 反序列化漏洞防御 避免反序列化不可信数据 使用安全的替代方法: yaml.safe_load() 替代 yaml.load() json.loads() 替代 pickle.loads() 对序列化数据进行签名验证 3.2 命令执行漏洞防御 避免使用危险函数 使用安全的替代方法: subprocess.run() 替代 os.system() 对用户输入进行严格过滤和验证 使用白名单机制限制可执行命令 四、审计方法论 4.1 审计流程 识别危险模块和函数 跟踪用户输入流向 检查安全控制措施 验证漏洞可利用性 4.2 工具推荐 静态分析工具: Bandit PyLint Safety 动态分析工具: 交互式调试器 请求拦截代理 4.3 重点关注 反序列化操作 系统命令执行 文件操作 数据库操作 模板渲染 五、总结 Python代码审计需要重点关注: 反序列化操作(pickle/yaml) 命令执行函数调用 用户输入流向 平台特性差异 通过案例学习可以积累审计经验,提高发现漏洞的效率。在实际审计中,应结合静态分析和动态验证,全面评估代码安全性。