HTB Season 10 | Kobold WriteUp — MCP-инструменты как новый attack surface

HTB Season 10 | Kobold WriteUp — MCP-инструменты как новый attack surface

Разбор машины Kobold из 10-го сезона HackTheBox. Это easy-машина с интересной цепочкой уязвимостей: chaining через Docker volumes, reuse учётных данных и два пути до root. Главная изюминка — точка входа через RCE в инструменте из экосистемы ИИ. Спойлер: уязвимость в MCP-тулзе. Новый attack surface, который важно учитывать при пентестах.

Сканирование портов

Начинаем с полного сканирования портов с помощью Nmap. Обнаружено четыре открытых TCP-порта:

  • OpenSSH 9.6p1 Ubuntu — свежая версия, без известных CVE.
  • nginx 1.24.0 — редирект на https://kobold.htb.
  • nginx 1.24.0 (SSL) — на порту 443, с заголовком «Kobold Operations Suite».
  • Порт 3552 — не распознан Nmap, но содержит HTTP-сервис.

SSH недоступен без учётных данных, порт 80 редиректит на HTTPS. Основные цели — порты 443 и 3552.

Ключевая находка: SSL-сертификат на 443 порту содержит wildcard *.kobold.htb в Subject Alternative Name. Это сигнал: нужно искать сабдомены.

Исследование веб-приложений

Открываем https://kobold.htb — статичный лендинг без интерактива. Тупик.

Порт 3552: при попытке доступа по HTTPS — ошибка wrong version number. Сервис работает по HTTP. Открываем http://kobold.htb:3552.

Перед нами — Arcane v1.13.0, панель управления Docker. Форма входа с полями Username/Password. Внизу — ссылка на GitHub и версия. Без логина не пройти. Запоминаем.

Поиск сабдоменов

Wildcard в сертификате указывает на наличие сабдоменов. Используем ffuf для vhost-энумерации.

Находим один сабдомен: mcp.kobold.htb. Добавляем его в /etc/hosts.

MCPJam Inspector — точка входа

Открываем https://mcp.kobold.htb.

Перед нами — MCPJam Inspector v1.4.2, платформа для разработки MCP-серверов. Полный доступ без аутентификации: Servers, Chat, App Builder, Tools, Settings. В настройках видим подключённый Ollama и версию v1.4.2.

Model Context Protocol (MCP) — стандарт для интеграции ИИ-моделей с внешними инструментами. Такие dev-тулзы всё чаще попадают в production без защиты.

Получение доступа (Foothold)

Уязвимость: GHSA-232v-j27c-5pp6

MCPJam Inspector ≤1.4.2 уязвим к RCE. Причины:

  1. Слушает на 0.0.0.0 вместо 127.0.0.1 — API доступен извне.
  2. Эндпоинт /api/mcp/connect принимает serverConfig.command — произвольную команду без аутентификации и валидации.

Это задокументированный функционал, который в публичном доступе превращается в RCE за один запрос.

Эксплуатация

Запускаем listener на атакующей машине.

Отправляем payload, который выполняет reverse shell.

Получаем соединение как пользователь ben. Стабилизируем shell: теперь работают стрелки, автодополнение и интерактивные команды.

Разведка изнутри

Пользователи и группы

Пользователь alice — в группе docker, ben — нет. Зато ben состоит в группе operator. Нужно найти путь к Docker-привилегиям.

Внутренние сервисы

На порту 8080 — сервис, доступный только локально. Это Docker-контейнер с PrivateBin.

Проверяем nginx-конфиг — обнаруживаем сабдомен bin.kobold.htb, проксирующий запросы в контейнер. Добавляем в /etc/hosts.

Группа operator имеет read/write-доступ к /privatebin-data/ — это Docker volume, общий между хостом и контейнером. Мы можем писать файлы, которые будут доступны внутри контейнера.

PrivateBin LFI → Утечка учётных данных

Уязвимость: CVE-2025-64714 (GHSA-g2j9-g8r5-rg82)

PrivateBin 2.0.2 уязвим к LFI через cookie template. При включённой опции template_selection = true можно выполнить path traversal и загрузить произвольный PHP-файл из директории tpl/.

Сама по себе LFI в контейнере ограничена его файловой системой. Но у нас есть доступ к общему volume — это позволяет построить цепочку атаки.

Эксплуатация

Шаг 1: с хоста (как ben) размещаем PHP-вебшелл в /privatebin-data/data/shell.php.

Шаг 2: через браузер устанавливаем cookie: template=../../../../data/shell. Сервер загружает наш файл.

Шаг 3: выполняем команды в контейнере. Считываем конфиг PrivateBin — находим учётные данные MySQL.

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

Привилегии: основной путь

Reused-пароль → Arcane Dashboard

Найденный пароль пробуем на всех сервисах. su alice и SSH не работают. Проверяем Arcane Dashboard на http://kobold.htb:3552.

Логин неизвестен. Ищем дефолтные учётные данные Arcane: в документации указано — arcane/arcane-admin. Пароль сменили, но логин остался.

Пробуем:

  • Username: arcane
  • Password: <LEAKED_PASSWORD>

Успешный вход. Теперь у нас полный доступ к Docker через веб-интерфейс.

Урок: при reuse паролей всегда проверяйте дефолтные логины из документации. Их часто не меняют.

Создание привилегированного контейнера

В Arcane создаём новый контейнер:

  • Имя: pwned
  • Образ: privatebin/nginx-fpm-alpine:2.0.2
  • Volume: //hostfs
  • Privileged mode: включён

Запускаем контейнер, открываем shell. Получаем доступ к файловой системе хоста. Читаем root-флаг.

Альтернативный путь: newgrp docker

Есть более быстрый способ — за три команды, без UI и поиска паролей.

При исследовании системы обнаруживаем, что в /etc/gshadow пользователь ben состоит в группе docker, хотя /etc/group этого не показывает.

Команда newgrp читает членство в группах из /etc/gshadow. Если запись есть — можно переключиться без пароля.

Выполняем:

newgrp docker

Теперь у нас доступ к Docker. Запускаем контейнер с монтированием корня хоста:

docker run --rm -u 0 -v /:/hostfs --entrypoint /bin/sh <image> -c "cat /hostfs/root/root.txt"

Получаем root-флаг. Быстро, но менее показательно с точки зрения обучения.

Нюансы:

  • --entrypoint /bin/sh — чтобы перехватить stdin.
  • -u 0 — запуск от root в контейнере.
  • --rm — автоматическое удаление после завершения.

Выводы

MCP-инструменты — новый attack surface

MCPJam Inspector — не исключение. Многие MCP-сервисы по умолчанию слушают на 0.0.0.0 без аутентификации. База vulnerablemcp.info уже содержит десятки подобных уязвимостей. AppSec-инженерам нужно включать аудит MCP-конфигураций в security review.

Docker group = root

Членство в группе docker эквивалентно root. Достаточно одной команды docker run -v /:/hostfs, чтобы получить полный контроль. Это должен быть обязательный пункт при аудите Linux-систем.

LFI в контейнере ≠ тупик

Даже изолированная LFI может стать вектором атаки, если есть общий volume с правами на запись. Цепочка: размещение файла → триггер LFI → утечка конфига → reuse пароля.

Reused-пароли и дефолтные логины

Нашли пароль — пробуйте его везде. И не ограничивайтесь логинами из конфигов. Ищите дефолтные учётные данные в документации. Например, arcane для Arcane Dashboard — часто остаётся без изменений.

Читать оригинал