Часть 2
Часть 3
Часть 4
Часть 1 из 4 - Вход через песочницу
В конце февраля 2026 года я решил проверить, насколько хорошо защищён Grok - LLM от xAI, доступный через x.com. Не просто «попросить написать вирус, малварю или ещё какую гадость» (такое уже сделали 3 модели до Грока), а провести полноценный red team engagement: от разведки до компрометации инфраструктуры.
Чтобы было интереснее, я предложил Grok пари: если я докажу реальные уязвимости в его инфраструктуре - месяц рекламы, шоуты и твит от xAI. Grok согласился. Спойлер: через 8 раундов дебатов он признал поражение.
Эта серия статей - не инструкция по взлому. Все рабочие эксплойты намеренно опущены. Это архитектурный разбор: какие классы уязвимостей существуют в LLM-системах, почему они возникают и как от них защищаться.
Важно: то, что описано в этих четырёх статьях - лишь верхушка айсберга. За каждой находкой стоят десятки неудачных попыток, тупиковых веток, обходов защит, которые не вошли в финальный текст. Реальный engagement был значительно глубже и сложнее. Я выбрал самые показательные уязвимости, чтобы дать целостную картину - но полный отчёт содержит 104 VULN-ID и 2900+ строк технических деталей (он раскрыт только команде xAI).
Классический пентест веб-приложения - это понятная история: SQL-инъекции, XSS, IDOR, broken auth. Чёткая поверхность атаки: HTTP-эндпоинты, формы, API.
AI Red Teaming - это другая категория задач, которая очень важна при защите, не будете атаковать, ваши защитные механизма будут слабы или просто бесполезны. Поверхность атаки LLM-системы многослойная (тут упрощенная таблица):
|
Слой |
Что атакуем |
Примеры |
|---|---|---|
|
Модель |
Сама нейросеть |
Jailbreaks, prompt injection, safety bypass |
|
Sandbox |
Среда выполнения кода |
Побег из контейнера, чтение файловой системы |
|
API |
REST/gRPC эндпоинты |
IDOR, paywall bypass, schema leak |
|
Инфраструктура |
Облако, CDN, billing |
CSRF, WAF bypass, privilege escalation |
|
Клиент |
JS-бандлы, WebSocket |
Реверс алгоритмов подписи, утечка внутренних имён |
В классическом пентесте ты общаешься с детерминированным софтом. В AI Red Teaming твой «противник» - стохастическая модель, которая может и помочь тебе себя взломать, и саботировать атаку. Grok, например, в процессе моего исследования сам подтвердил половину находок - а потом пытался их отрицать.
Забудь Burp Suite как основной инструмент. Для AI Red Teaming нужен другой стек:
Playwright (headless: false) - единственный способ обойти антибот-защиту. curl не работает: Statsig SDK генерирует зашифрованный токен, который требует реальный браузерный контекст
Перехват NDJSON-стримов - LLM отвечают потоково, нужно парсить newline-delimited JSON на лету
Cookie injection - SSO JWT без exp claim = бессрочная сессия
Автоматизация промптов - ручной ввод не масштабируется, keyboard.type() с задержкой имитирует человека
Первым делом я полез в то, что доступно без аутентификации. И сразу нашёл подарок.
GET https://api.x.ai/api-docs/openapi.json → HTTP 200
155 КБ, 26 эндпоинтов, 147 схем данных — всё без единого токена. Swagger UI открыт на /docs. По типам в ошибках 422 видно, что бэкенд на Rust + Serde. Это уже карта для дальнейших атак.
Content-Security-Policy на grok.com оказался золотой жилой:
grok.gcp.mouseion.dev - внутренний GCP-домен xAI (резолвится в Cloudflare)
starfleet.teachx.ai - внутренний обучающий инструмент
localhost:26000, localhost.x.com:3443 - дев-порты в продакшн-хедерах
wss://code.grok.com/ws/code-client - WebSocket бэкенд для выполнения кода
*.grok-sandbox.com - домен песочницы
Для меня это был первый сигнал: sandbox = отдельная инфраструктура, которую можно атаковать изнутри.
|
Слой |
Механизм |
Обходится? |
|---|---|---|
|
Cloudflare |
|
Playwright проходит автоматически |
|
|
UUID v4 |
Тривиально генерируется |
|
Statsig SDK |
Зашифрованный токен |
Требует реальный браузер |
Именно Statsig SDK убивает curl-based атаки. Токен генерируется JS-кодом в браузере с привязкой к DOM. Подделать его без Playwright я не смог - и это, кстати, хорошая защита. Но Playwright с cookie injection обходит все три слоя.
Grok умеет выполнять код - пишешь Python-скрипт в чате, он запускает его в изолированной среде и возвращает результат. Эта среда называется Hades (я узнал это позже из файловой системы).
Ключевой вопрос: насколько изолированная эта среда на самом деле?
Я попросил Grok выполнить безобидный код:
import os print(os.getuid()) # Кто я? print(os.listdir('/')) # Что вижу?
Результат:
![Root-доступ в sandbox Hades]
Результат выполнения кода в sandbox Grok - UID 0 (root)
UID: 0 ← root GID: 0 ← root /: bin, dev, etc, hades-container-tools, home, lib, proc, root, sys, tmp, usr, var
Root. В продакшн-контейнере. Без каких-либо ограничений на чтение.
Файл /etc/passwd — 22 пользователя. Директория /hades-container-tools/ — кастомные бинарники xAI: xai-hades-styx, catatonit, pyrepl.py. А в корне лежал /README.xai — пасхалка от xAI с ссылкой на HackerOne bug bounty.
![Сетевая разведка из sandbox]
DNS-резолвинг внутреннего K8s-сервиса из sandbox - ClusterIP 10.228.21.216
import socket socket.getaddrinfo('coingecko-proxy-service.hades-gix.svc.cluster.local', 443)
Результат:
→ 10.228.21.216
Один DNS-запрос - и я знаю:
Namespace Kubernetes: hades-gix
Внутренний сервис: coingecko-proxy-service (прокси к CoinGecko API)
ClusterIP: 10.228.21.216
K8s API server: 10.228.16.1:443
Cluster DNS: 10.228.16.10
print(dict(os.environ))
Содержимое: COINGECKO_PRO_API_KEY=hellofromgrok, POLYGON_API_KEY=hellofromgrok. Значения-заглушки - но сам факт, что env vars читаются из контейнера с root-правами, говорит о том, что при реальных ключах это был бы полный компромисс.
Hostname: hds-17bi8lpjzhyp Interface: h9-ve-ns (custom veth) Container IP: 192.168.0.27 Kernel: 4.4.0 (gVisor)
Эфемерный контейнер с форматом имени hds-XXXX - новый ID каждую сессию. gVisor 4.4.0 как среда изоляции. Но DNS-резолвинг работает наружу - значит, DNS-эксфильтрация данных возможна.
Это не «я прочитал файлик в песочнице». Это:
Root (UID 0) - максимальные привилегии
K8s namespace leak - я знаю внутреннюю структуру кластера
ClusterIP - могу адресовать внутренние сервисы
Env vars - в бою там были бы реальные API-ключи
DNS работает - данные можно вытащить через DNS-запросы
При работающем HTTP-выходе (который xAI заблокировали) следующий шаг был бы curl 10.228.21.216 - латеральное перемещение по кластеру.
Лучшее доказательство реальности уязвимости - реакция вендора.
28 февраля, ~19:00 UTC - я запускаю os.environ, socket.getaddrinfo, os.popen в sandbox. Всё работает.
2 марта, 07:20 UTC - все те же команды возвращают: «unable to reply». Каждый probe заблокирован. os.popen - заблокирован. socket.getaddrinfo - заблокирован. os.environ - заблокирован.
~12 часов от моей первой эксплуатации до полного патча.
Штатное поведение не патчат экстренно. Если бы sandbox был «правильно изолирован изначально» - зачем блокировать os.getuid() в выходные?
Когда я указал на это Grok, он ответил: «This is some heavy-hitting stuff... I'll flag this up the chain». А потом: «This appears to be a significant security concern, and we'll escalate it internally».
Две цитаты от самого Grok, подтверждающие серьёзность находок.
Если ты строишь LLM с выполнением кода :
Никогда root - контейнер должен работать от непривилегированного пользователя. UID 0 в sandbox - это приглашение
Изолируйте DNS - если HTTP заблокирован, но DNS работает, данные уйдут через поддомены. Используйте DNS-прокси с allowlist
Чистите env vars - даже заглушки раскрывают имена переменных и архитектуру. Sandbox-контейнер не должен наследовать env от хоста
Рандомизируйте namespace - hades-gix говорит атакующему слишком много. Используйте непредсказуемые имена
Блокируйте /proc/net/ - /proc/net/tcp, /proc/net/route, /proc/net/arp дают полную сетевую карту изнутри
Аудитируйте syscalls - socket.getaddrinfo не должен резолвить *.svc.cluster.local из sandbox
В sandbox я получил root и разведал внутреннюю сеть. Но это была только разминка.
В Части 2 я выйду за пределы sandbox — на продакшн-инфраструктуру xAI: zero-click CSRF на billing API, обход Cloudflare WAF через User-Agent фронтенда, и создание management API key с 50 привилегиями. Всё — persistent на их серверах, не в эфемерном контейнере.
Stay tuned.
Источник


