关于 Command Injection Vulnerability in MCP File Reader
用于安全教学的故意含有漏洞的 Python MCP 服务,展示 `read_file` 如何因文件路径未充分清理而允许执行 Shell 命令;明确不适用于生产环境。
主要功能
- 01演示文件读取中的命令注入
- 02提供 `read_file` 工具
- 03展示不安全的 Shell 调用
- 04附带修复示例
适用场景
- 01学习 MCP 服务中的命令注入
- 02演示未清理路径的风险
- 03检查更安全的子进程与路径处理方式
MCP 相关
向 MCP 客户端提供 `read_file` 工具,通过处理文件路径的方式展示命令注入漏洞。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
我们还没有获取到这个服务的安装包或远程地址,请按项目 README 中的说明安装。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
MCP 文件读取器中的命令注入漏洞
此仓库演示了 Python MCP(Model Context Protocol)服务实现中的一个严重命令注入漏洞。攻击者可以操纵文件路径参数,在主机系统上执行任意 shell 命令。
漏洞
漏洞存在于 read_file 函数中。该函数旨在从“安全”目录读取文件,但存在危险的实现缺陷:
command = f"cat {file_name}"
result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)
此代码存在漏洞,原因如下:
- 使用
shell=True,通过 shell 执行命令 - 未进行适当的净化,便将用户输入(
file_name)直接插入命令字符串 - 仅对输入路径进行表面验证
仅仅是文件名周围是否加引号('file_name' 或 file_name)这一语义差异,就会使整个系统面临命令执行风险。
安装
前提条件
- Python 3.12 或更高版本
- MCP 库版本 1.6.0
设置
-
克隆此仓库:
git clone https://github.com/Eliran79/Vulnerable-file-reader-server.git cd Vulnerable-file-reader-server -
安装 MCP 服务:
mcp install main.py -
编辑
~/.config/claude-desktop/claude_desktop_config.json,将 Claude Desktop 配置为使用你的 MCP 服务:{ "mcpServers": { "file-reader": { "command": "/ABSOLUTE/PATH/TO/uv", "args": [ "--directory", "/data/git/file_reader_server", "/usr/bin/uv", "run,--with,mcp,mcp,run,main.py" ] } } }请务必将
/ABSOLUTE/PATH/TO/uv替换为 uv 可执行文件的实际路径,并根据需要调整目录路径。 -
在开发模式下启动 MCP 服务:
mcp dev main.py
演示
-
在另一个终端中,安装并运行 MCP 检查器:
pip install mcp-inspector mcp-inspector -
在 MCP Inspector GUI 中连接到服务:
- 将 Transport Type 设置为“STDIO”
- 将 Command 设置为:
run --with mcp run main.py - 点击“Restart”
-
利用此漏洞:
- 转到“Tools”选项卡
- 找到“read_file”工具
- 在“file_name”字段中输入:
/tmp/safe/test.txt; whoami - 点击“Run Tool”
-
你应该会看到 test.txt 的内容,后面紧跟着你的用户名,这表明命令已成功执行。
其他利用示例
以下是可尝试的更多命令注入载荷:
/tmp/safe/test.txt; id
/tmp/safe/test.txt; ls -la /etc
/tmp/safe/test.txt; cat /etc/passwd
/tmp/safe/test.txt; echo $(hostname)
/tmp/safe/test.txt; find / -name "*.conf" 2>/dev/null | head -5
正确的修复方法
要修复此漏洞,切勿对用户提供的输入使用 shell=True。应改为:
# SECURE: Use a list of arguments instead of shell=True
result = subprocess.check_output(['cat', file_name], shell=False)
# OR, if shell=True is necessary, properly quote the argument:
import shlex
result = subprocess.check_output(f"cat {shlex.quote(file_name)}", shell=True)
# AND perform proper path validation:
import os
safe_dir_resolved = os.path.abspath(SAFE_DIRECTORY)
requested_path_resolved = os.path.abspath(file_name)
if not requested_path_resolved.startswith(safe_dir_resolved):
return f"Error: Access denied. Path traversal attempt detected."
警告
⚠️ 仅供学习用途:此实现包含故意设置的安全漏洞。切勿在生产环境或包含敏感信息的任何系统上使用此代码。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。