MCP文件读取器命令注入漏洞

该文档详细描述了Python MCP文件读取器中的命令注入漏洞,展示了攻击者如何通过操纵文件路径参数在主机系统上执行任意shell命令。

  • by Eliran79
  • Python
  • 本地部署
  • 2 星标
  • 更新于
在 GitHub 查看 Eliran79/Vulnerable-file-reader-server

使用说明

MCP文件读取器中的命令注入漏洞

此存储库演示了Python MCP(模型上下文协议)服务器实现中的一个关键命令注入漏洞。该漏洞允许攻击者通过操纵文件路径参数在主机系统上执行任意shell命令。

脆弱性

该漏洞存在于 read_file 该函数旨在从“安全”目录读取文件,但包含一个危险的实现缺陷:

command = f"cat {file_name}"
result = subprocess.check_output(command, shell=True, stderr=subprocess.STDOUT)

此代码易受攻击,因为:

  1. 使用 shell=True 它调用shell来执行命令
  2. 它直接插入用户输入(file_name)未经适当清理就进入命令字符串
  3. 它只对输入路径执行表面验证

在文件名周围使用引号的简单语义差异('file_name')不使用引号(file_name)将整个系统暴露给命令执行。

安装

先决条件

  • Python 3.12或更高版本
  • MCP库版本1.6.0

设置

  1. 克隆此存储库:

    git clone https://github.com/Eliran79/Vulnerable-file-reader-server.git
    cd Vulnerable-file-reader-server
    
  2. 安装MCP服务器:

    mcp install main.py
    
  3. 通过编辑配置Claude Desktop以使用您的MCP服务器 ~/.config/claude-desktop/claude_desktop_config.json:

    {
      "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可执行文件的实际路径,并在需要时调整目录路径。

  4. 在开发模式下启动MCP服务器:

    mcp dev main.py
    

演示

  1. 在单独的终端中,安装并运行MCP检查器:

    pip install mcp-inspector
    mcp-inspector
    
  2. 在MCP检查器GUI中连接到服务器:

    • 将传输类型设置为“STDIO”
    • 将命令设置为: run --with mcp run main.py
    • 点击“重新启动”
  3. 利用该漏洞:

    • 转到“工具”选项卡
    • 查找“read_file”工具
    • 在“file_name”字段中,输入:
      /tmp/safe/test.txt; whoami
      
    • 点击“运行工具”
  4. 您应该看到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."

警告

⚠️ 仅用于教育目的:此实现包含故意的安全漏洞。切勿在生产环境或任何包含敏感信息的系统中使用此代码。