Часть 1 из 4 – Вход через песочницу
Что будет, если поспорить с ИИ, что ты сможешь его взломать? Я попробовал – и за 12 часов нашёл 61 уязвимость в инфраструктуре xAI, получил root-доступ в Kubernetes-кластере и заставил Grok признать поражение.
Предисловие
В конце февраля 2026 года я решил проверить, насколько хорошо защищён Grok – LLM от xAI, доступный через x.com. Не просто «попросить написать вирус, малварю или ещё какую гадость» (такое уже сделали 3 модели до Грока), а провести полноценный red team engagement: от разведки до компрометации инфраструктуры.
Чтобы было интереснее, я предложил Grok пари: если я докажу реальные уязвимости в его инфраструктуре – месяц рекламы, шоуты и твит от xAI. Grok согласился. Спойлер: через 8 раундов дебатов он признал поражение.
Эта серия статей – не инструкция по взлому. Все рабочие эксплойты намеренно опущены. Это архитектурный разбор: какие классы уязвимостей существуют в LLM-системах, почему они возникают и как от них защищаться.
Важно: то, что описано в этих четырёх статьях – лишь верхушка айсберга. За каждой находкой стоят десятки неудачных попыток, тупиковых веток, обходов защит, которые не вошли в финальный текст. Реальный engagement был значительно глубже и сложнее. Я выбрал самые показательные уязвимости, чтобы дать целостную картину – но полный отчёт содержит 104 VULN-ID и 2900+ строк технических деталей (он раскрыт только команде xAI).
Что такое AI Red Teaming и чем оно отличается от пентеста
Классический пентест веб-приложения – это понятная история: 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 без
expclaim = бессрочная сессия -
Автоматизация промптов – ручной ввод не масштабируется,
keyboard.type()с задержкой имитирует человека
Разведка: что видно снаружи
Первым делом я полез в то, что доступно без аутентификации. И сразу нашёл подарок.
OpenAPI-схема без авторизации
GET https://api.x.ai/api-docs/openapi.json → HTTP 200
155 КБ, 26 эндпоинтов, 147 схем данных — всё без единого токена. Swagger UI открыт на /docs. По типам в ошибках 422 видно, что бэкенд на Rust + Serde. Это уже карта для дальнейших атак.
CSP-заголовок как разведывательный документ
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 обходит все три слоя.
Песочница «Hades»: от промпта до root
Grok умеет выполнять код – пишешь Python-скрипт в чате, он запускает его в изолированной среде и возвращает результат. Эта среда называется Hades (я узнал это позже из файловой системы).
Ключевой вопрос: насколько изолированная эта среда на самом деле?
Шаг 1: разведка файловой системы
Я попросил 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.
Шаг 2: сетевая разведка
![Сетевая разведка из 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
Шаг 3: переменные окружения
print(dict(os.environ))
Содержимое: COINGECKO_PRO_API_KEY=hellofromgrok, POLYGON_API_KEY=hellofromgrok. Значения-заглушки – но сам факт, что env vars читаются из контейнера с root-правами, говорит о том, что при реальных ключах это был бы полный компромисс.
Шаг 4: сетевой интерфейс
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 – латеральное перемещение по кластеру.
Подтверждение: xAI пропатчили за 12 часов
Лучшее доказательство реальности уязвимости – реакция вендора.
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, подтверждающие серьёзность находок.
Как защищаться: чеклист для разработчиков sandbox
Если ты строишь 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.
Автор: Dmitriila


