分析Emissary 的反序列化漏洞 (CVE-2021-32634)
字数 1618 2025-08-05 08:19:38
Emissary 反序列化漏洞分析 (CVE-2021-32634) 教学文档
1. 漏洞概述
CVE-2021-32634 是 NSA 开发的 Emissary 项目中的不安全反序列化漏洞。该漏洞存在于多个端点,允许攻击者通过精心构造的序列化对象执行任意代码。
2. Emissary 项目简介
Emissary 是一个基于 P2P 的数据驱动工作流引擎,运行在异构的、可能广泛分散的、多层 P2P 计算资源网络中。主要特点包括:
- 工作流不是预先计划的,而是随着数据发现而动态确定
- 高度可配置,基本实现几乎不做任何操作
- 用户需要扩展
emissary.place.ServiceProviderPlace类来执行工作 - 工作流阶段包括:STUDY, ID, COORDINATE, TRANSFORM, ANALYZE, IO, REVIEW
emissary.core.MobileAgent负责管理工作流emissary.directory.DirectoryPlace管理可用服务及其成本和质量
3. 漏洞详细分析
3.1 第一个漏洞点:WorkSpaceClientEnqueueAction
位置:emissary.server.mvc.internal.WorkSpaceClientEnqueueAction
漏洞描述:
该端点 /WorkSpaceClientEnqueue.action 接收表单参数 WORK_BUNDLE_OBJ(即 tpObj),直接对其进行反序列化操作。
关键代码:
@POST
@Path("/WorkSpaceClientEnqueue.action")
@Consumes(MediaType.APPLICATION_FORM_URLENCODED)
@Produces(MediaType.TEXT_PLAIN)
public Response workspaceClientEnqueue(
@FormParam(WorkSpaceAdapter.CLIENT_NAME) String clientName,
@FormParam(WorkSpaceAdapter.WORK_BUNDLE_OBJ) String workBundleString) {
// 漏洞点:直接反序列化用户输入
final ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(workBundleString.getBytes("8859_1")));
WorkBundle paths = (WorkBundle) ois.readObject();
success = place.enque(paths);
}
利用条件:
- 需要经过身份验证的 POST 请求
- 由于修复了 CSRF 漏洞,无法通过 CSRF 代表已登录用户利用
3.2 第二个漏洞点:MoveToAction
位置:emissary.server.mvc.internal.MoveToAction
漏洞描述:
虽然当前未被 Jersey server 公开,但代码中存在不安全的反序列化操作,是潜在的定时炸弹。
调用链:
MoveToAction.moveTo()调用MoveToAdapter.inboundMoveTo()MoveToAdapter创建MoveToRequestBeanMoveToRequestBean使用PayloadUtil.deserialize()反序列化数据
关键代码:
// MoveToRequestBean 构造函数
final String agentData = RequestUtil.getParameter(req, AGENT_SERIAL);
setPayload(agentData);
// PayloadUtil.deserialize()
ois = new ObjectInputStream(new ByteArrayInputStream(s.getBytes("8859_1")));
3.3 第三个漏洞点:WorkSpaceAdapter
位置:emissary.server.mvc.adapters.WorkSpaceAdapter
漏洞描述:
inboundEnque() 方法中存在不安全的反序列化操作,虽然当前未被调用,但存在潜在风险。
调用链:
WorkSpaceAdapter.inboundEnque()创建EnqueRequestBeanEnqueRequestBean的setPaths()方法直接反序列化输入
关键代码:
// EnqueRequestBean 构造函数
setPaths(RequestUtil.getParameter(req, WORK_BUNDLE_OBJ));
// setPaths 方法
void setPaths(final String s) {
final ObjectInputStream ois = new ObjectInputStream(
new ByteArrayInputStream(s.getBytes("8859_1")));
this.paths = (WorkBundle) ois.readObject();
}
4. 漏洞修复建议
-
替换反序列化机制:
- 使用安全的序列化格式如 JSON 或 XML
- 如果必须使用 Java 序列化,实现
ObjectInputFilter进行严格过滤
-
访问控制:
- 确保所有敏感端点都有适当的身份验证和授权
- 实施 CSRF 防护措施
-
代码审查:
- 检查所有使用
ObjectInputStream的地方 - 移除或保护未使用但存在风险的代码路径
- 检查所有使用
-
输入验证:
- 对所有用户输入进行严格验证
- 避免直接反序列化不可信的输入
5. 漏洞影响
成功利用此漏洞可能导致:
- 任意代码执行
- 服务器完全被控制
- 敏感数据泄露
- 系统完整性破坏