Docker, Pentest, Пентест

Контейнерный побег: как из Docker-контейнера пролезть в ядро хоста

Здорово, брат. Снова перед нами стена. Только на этот раз она цифровая — стенки Docker-контейнера. Админы думают, что заперли нас в коробке. Они думают, что cgroups и namespaces — это панацея. Ну что ж, давай покажем им, как мы умеем ломать песочницы. Тема сегодняшнего разбора — Контейнерный побег. Цель — прогрызть дыру до самого ядра хоста. Погнали.

Шаг 1: Осмотр на месте. Что у нас в «камере»?

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

  1. Проверка привилегий. Самый главный вопрос: не запустили ли нас с флагом --privileged? Это как дать заключенному ключи от всех дверей.

Если в выводе видишь full_effective_cap_set или кучу разрешенных capabilities, особенно cap_sys_admin, — это джекпот. Считай, полдела сделано.

  1. Монтированные тома. Админы любят пробрасывать в контейнер куски хостовой файловой системы. Самый жирный кусок — это docker.sock.

Если этот файл есть и у нас есть права на запись — это второй джекпот. Мы можем управлять Docker-демоном хоста прямо из нашего контейнера.

  1. Версия ядра. Это наш билет в мир эксплойтов. Уязвимости в ядре — классика жанра. Они бьют мимо всех защит контейнеризации.
  1. Копируем вывод. Linux ctf-box 5.4.0-109-generic ... — вот это нам и нужно. По этой строке будем искать CVE на GitHub и Exploit-DB.

Шаг 2: Векторы атаки. Выбираем отмычку

В зависимости от того, что мы нашли на первом шаге, выбираем стратегию.

Вектор A: Побег через --privileged

Это не взлом, это прогулка. Флаг --privileged отключает почти все механизмы изоляции. Мы можем делать с хостом почти все, что захотим.

План атаки:

  1. Найти диск хоста. Обычно это что-то вроде /dev/sda1/dev/vda1 или /dev/nvme0n1p1.

2. Создать точку монтирования и примонтировать файловую систему хоста.

3. Сменить корневой каталог. chroot — наш лучший друг. Мы «переезжаем» на файловую систему хоста.

Поздравляю, ты root на хосте. Можешь добавлять своего юзера, лить SSH-ключ в authorized_keys и закрепляться. Игра окончена.

    Вектор B: Удар через Docker Socket

    Если нам пробросили /var/run/docker.sock, админ, по сути, оставил ключи под ковриком. Мы можем попросить Docker-демон запустить для нас новый контейнер. Но уже с нужными нам флагами.

    План атаки:

    1. Ставим Docker-клиент внутри нашего контейнера.

    2. Запускаем новый, «злой» контейнер. Мы говорим демону хоста: «Эй, запусти-ка мне вот эту коробочку, но с полным доступом ко всему на хосте».

    • --privileged: Дает все права.
    • --pid=host: Используем PID namespace хоста.
    • nsenter ...: Заходим в пространства имен процесса с PID 1 на хосте (обычно это init/systemd).
    Ты в шелле. На хосте. С правами root. Занавес.

      Вектор C: Злоупотребление CAP_SYS_ADMIN

      Это уже интереснее. У нас нет полного --privileged, но есть одна очень жирная «способность» — CAP_SYS_ADMIN. Она позволяет делать много грязных дел, включая монтирование устройств и манипуляции с cgroups.

      План атаки (через release_agent):

      Это красивый трюк. Мы создаем cgroup, указываем в качестве release_agent наш скрипт, а затем триггерим его выполнение. Ядро само выполнит наш код на хосте.

      1. Находим путь к cgroup и создаем нашу директорию:

      2. Создаем наш payload. Например, обратный шелл:

      3. Настраиваем cgroup:

      4. Триггер:

      Как только этот процесс завершится, ядро выполнит наш release_agent. Слушай порт на своей машине (nc -lvnp YOUR_PORT), и к тебе прилетит шелл от имени root с хоста.

        Вектор D: Эксплойт ядра (The Dirty Way)

        Если ничего из вышеперечисленного не сработало, значит, админы попались грамотные. Но и на них есть управа — уязвимости в самом сердце системы.

        1. Берем версию ядра из uname -a.
        2. Идем на поиски. Google-дорки в помощь: "Linux kernel [version] privilege escalation exploit github", ищем на exploit-db.com.
        3. Пример — Dirty Pipe (CVE-2022-0847). Если ядро уязвимо (версии от 5.8 до 5.16.11, 5.15.25, 5.10.102), это наш шанс. Эксплойт позволяет перезаписывать любые файлы, доступные на чтение.
          • Цель: Перезаписать /etc/passwd, чтобы установить пустой пароль для root. Или подменить SUID-бинарник.
          • Действия:
            1. Найти и скачать PoC с GitHub (их полно).
            2. Скомпилировать его в контейнере (если есть gcc).

        3. Запустить.

        4. Если все прошло успешно, делаем su root без пароля. И мы снова на коне.

        Контейнеры — это не крепость. Это всего лишь стены из картона, если знать, где надавить.

        Советы

        1. Проверь переменные окружения (env). Иногда там оставляют пароли, ключи API, токены. Это легкая добыча.
        2. Поищи эндпоинт метаданных облачного провайдера. Если контейнер крутится в AWS/GCP/Azure, попробуй достучаться до 169.254.169.254. Оттуда можно вытащить временные креды и атаковать облачную инфраструктуру.
        3. Не забывай про procfs. Если /proc хоста как-то смонтирован, можно вытащить кучу инфы о процессах, переменных окружения и даже файловых дескрипторах других процессов на хосте.
        4. Смотри на другие контейнеры. Если получил доступ к docker.sock, выполни docker ps. Возможно, рядом крутится контейнер с базой данных или другим интересным сервисом. Пивотинг — наше все.
        5. Если нашел точку входа — закрепляйся. Не сиди в интерактивном шелле. Прокинь нормальный reverse shell через socat или msfvenom, добавь SSH-ключ, создай юзера. Будь как дома, но не забывай, что ты в гостях. И не наследи.
        Контейнерный побег: как из Docker-контейнера пролезть в ядро хоста

        На этом все. Всем хорошего дня!