![]() |
https://forum.antichat.xyz/attachmen...a548536641.png
Контейнер - это не виртуальная машина. Когда ты оказываешься внутри контейнера на пентесте, между тобой и ядром хоста нет аппаратного гипервизора. Есть набор софтовых абстракций - namespaces, cgroups, capabilities, seccomp-профили - и любая из них может быть ослаблена мисконфигурацией или сломана уязвимостью. Побег из Docker контейнера (Escape to Host, T1611 по MITRE ATT&CK, тактика privilege-escalation) - переход из изолированного пользовательского пространства на хост с получением контроля над базовой системой и всеми соседними контейнерами. Здесь я разбираю конкретные container escape techniques - от тривиального злоупотребления Код:
--privilegedПочему контейнерная изоляция ломается Прежде чем ломать - нужно понять, что именно нас держит. Контейнер - это процесс (или группа процессов), которому через механизмы ядра Linux создано собственное пользовательское пространство. Четыре столпа этой изоляции: Namespaces определяют, что процесс видит. Mount namespace даёт отдельную файловую систему, PID namespace - отдельное дерево процессов, NET namespace - отдельный сетевой стек. Процесс внутри контейнера взаимодействует со своими экземплярами глобальных ресурсов и не видит хостовые. Cgroups определяют, сколько ресурсов процесс может сожрать: CPU, память, I/O. Но cgroups v1 содержат механизм Код:
release_agentCapabilities определяют, что процесс может делать. Linux разбивает привилегии root на дискретные единицы: Код:
CAP_SYS_ADMINКод:
CAP_SYS_PTRACEКод:
CAP_NET_ADMINSeccomp фильтрует системные вызовы. Профиль Docker по умолчанию блокирует опасные syscall'ы вроде Код:
mountКод:
rebootКод:
kexec_loadКритический момент: все контейнеры на хосте разделяют одно ядро. Уязвимость в ядре эксплуатируется из любого контейнера, независимо от его конфигурации. Это фундаментальное отличие от виртуальных машин, где каждая ВМ работает со своим экземпляром ядра, изолированным на уровне CPU. Разведка: определяем вектор побега изнутри контейнера Первое, что делаешь, получив шелл в контейнере - собираешь информацию о среде. Не стреляешь вслепую, а методично определяешь, какие механизмы изоляции ослаблены. Проверка: мы вообще в контейнере? Bash: Код:
# Наличие .dockerenv - верный признак Docker-контейнераBash: Код:
# Если установлен capshКод:
CapEffКод:
0000003fffffffffКод:
--privilegedПроверка монтирований и сокетов Bash: Код:
# Ищем Docker socketBash: Код:
unameИнструментЧто делаетКогда использовать Код:
amicontainedКод:
deepceКод:
CDKЯ обычно начинаю с Код:
amicontainedКод:
deepceDocker privileged mode escape: прогулка, а не взлом Флаг Код:
--privilegedКод:
/devПочему это работает Когда Docker запускает контейнер с Код:
--privilegedКод:
/dev/sdaКод:
/dev/nvme0n1p1Код:
mountПошаговая эксплуатация Шаг 1. Подтверждаем privileged mode: Bash: Код:
# Проверяем capabilities - должны быть полныеBash: Код:
fdiskBash: Код:
mkdirBash: Код:
# Вариант 1: chroot в хостовую ФСКод:
chroot /mnt/host /bin/bashИ вот что обидно (для защитников): privileged-контейнеры по-прежнему часто встречаются в production. CI/CD-пайплайны с Docker-in-Docker, мониторинговые агенты, dev-окружения, где разработчик добавил Код:
--privilegedMounted Docker socket exploitation: ключи под ковриком Монтирование Docker-сокета ( Код:
/var/run/docker.sockПочему это работает Docker daemon работает от root. Сокет Код:
/var/run/docker.sockПошаговая эксплуатация Шаг 1. Проверяем наличие сокета: Bash: Код:
lsЕсли в контейнере нет клиента Docker, используем curl: Bash: Код:
# Проверяем, что API доступноЕсли Docker-клиент доступен: Bash: Код:
docker -H unix:///var/run/docker.sock run -it --privilegedBash: Код:
# Создаём контейнер через APIBash: Код:
docker -H unix:///var/run/docker.sock run -it --privilegedКод:
nsenterПолучив доступ к Docker API, обязательно проверь соседние контейнеры через Код:
docker psCgroups release_agent escape: красивый трюк с ядром Этот вектор работает, когда контейнер не имеет полного Код:
--privilegedКод:
CAP_SYS_ADMINКод:
notify_on_releaseМеханика на уровне ядра В cgroups v1 каждая cgroup имеет файл Код:
notify_on_releaseКод:
1Код:
release_agentКод:
release_agentПочему cgroups v2 не уязвим В cgroups v2 механизм Код:
release_agentBash: Код:
# Если существует /sys/fs/cgroup/cgroup.controllers - это cgroup v2Шаг 1. Монтируем cgroup и создаём поддиректорию: Bash: Код:
mkdirBash: Код:
echoBash: Код:
catBash: Код:
# Запускаем процесс в нашей cgroup и сразу завершаем егоКод:
escapeКод:
notify_on_release=1Код:
release_agentBash: Код:
catBash: Код:
catRunc - низкоуровневый контейнерный рантайм, который непосредственно создаёт и запускает контейнеры. Его используют Docker, containerd, CRI-O, Kubernetes. Уязвимость в runc бьёт по всей контейнерной инфраструктуре разом. CVE-2019-5736: перезапись бинарника runc на хосте CVSS 8.6 (HIGH), вектор CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:C - обратите внимание на Код:
S:CМеханика: Уязвимость связана с некорректной обработкой файловых дескрипторов. Когда выполняется Код:
docker execКод:
/proc/self/exeУсловия эксплуатации:
CVE-2024-21626: Leaky Vessels - утечка файловых дескрипторов CVSS 8.6 (HIGH), вектор аналогичный - Код:
S:CМеханика: Из-за утечки внутреннего файлового дескриптора атакующий мог заставить процесс, создаваемый через Код:
runc execПо данным Wiz, уязвимость имела широкое воздействие на облачные среды - затронут базовый компонент всей контейнерной инфраструктуры. Серия CVE-2025: новые symlink/TOCTOU-уязвимости runc В 2025 году раскрыты три новых уязвимости в runc, эксплуатирующие схожие классы проблем - symlink-гонки и некорректную верификацию bind-mount'ов (не связаны с оригинальным брендом Leaky Vessels от Snyk, который относился к CVE-2024-21626 и смежным CVE): CVE-2025-31133 ( Код:
CVSS 7.3 HIGH по CVSS 4.0, PR:L/UI:A/AT:PКод:
/dev/nullКод:
/dev/nullКод:
/dev/nullКод:
/proc/sys/kernel/core_patternCVE-2025-52565 (CVSS 8.4 HIGH по CVSS 4.0). Те же CWE-61 и CWE-363. Из-за недостаточных проверок при bind-mount Код:
/dev/pts/$nКод:
/dev/consoleКод:
PR:NКод:
UI:PCVE-2025-52881 (CVSS 7.3 HIGH по Код:
CVSS 4.0, PR:L/UI:A/AT:PКод:
/procКод:
docker buildx buildВсе три уязвимости исправлены в runc 1.2.8 и новее. Общий паттерн - symlink/TOCTOU-гонки (CWE-61, CWE-363) при инициализации контейнера. Runc наступает на одни и те же грабли - гонки при работе с симлинками. Kernel exploits: общее ядро - общие уязвимости В отличие от уязвимостей runc, kernel exploits не зависят от конфигурации контейнера. Ядро уязвимо - побег возможен из любого контейнера. Тут уже не важно, насколько аккуратно настроены capabilities и seccomp. CVE-2022-0847 - Dirty Pipe CVSS 7.8 (HIGH), вектор CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U. CWE-665 (Improper Initialization). Уязвимость в pipe-подсистеме ядра Linux: поле Код:
flagsВ контексте контейнеров основной вектор escape - перезапись бинарников контейнерного рантайма (runc, containerd-shim) через Код:
/procCVE-2022-0185 - Integer Overflow → Heap-Based Buffer Overflow в Filesystem Context CVSS 8.4 (HIGH), вектор CVSS:3.1/AV:L/AC:L/PR:N/UI:N/S:U - Код:
S:UКод:
legacy_parse_paramКод:
CAP_SYS_ADMINCVE-2024-1086 - nf_tables Use-After-Free CVSS 7.8 (HIGH). CWE-416 (Use After Free). Уязвимость в netfilter-подсистеме: функция Код:
nft_verdict_init()Код:
nf_hook_slow()CVE-2016-5195 - Dirty COW CVSS 7.0 (HIGH), вектор CVSS:3.1/AV:L/AC:H/PR:L/UI:N/S:U - AC:H указывает на высокую сложность из-за необходимости выиграть race condition, что может потребовать множественных попыток. CWE-362 (Race Condition). Race condition в подсистеме управления памятью ядра, позволявшая запись в read-only memory mappings. Одна из первых kernel CVE, массово использовавшихся для побега из контейнеров. Старая, но на непатченных системах до сих пор встречается (да, такие ещё живы). Docker socket через сеть: побег без локального сокета Отдельная история - когда Docker daemon доступен по TCP (порт 2375/2376). Встречается в Kubernetes-кластерах, CI/CD-пайплайнах, dev-средах. Проверка: Bash: Код:
# Изнутри контейнера или сетиKubernetes container escape: расширение поверхности атаки В Kubernetes-средах вектора побега усиливаются дополнительными мисконфигурациями:
Bash: Код:
# Наличие хостового PID namespaceВот последовательность, которую я использую на engagement'ах. Порядок оптимизирован по вероятности успеха и скорости: 📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше Получить доступ просто — достаточно проявить активность на форуме Что затрудняет побег: защитные механизмы глазами атакующего Понимание защиты помогает правильно оценить среду и не тратить время на нерабочие векторы. User namespaces. Если включены, root внутри контейнера (UID 0) маппится на непривилегированного пользователя на хосте. Даже побег из контейнера не даёт root на хосте. Проверка: Код:
cat /proc/self/uid_mapКод:
0 0 4294967295Seccomp-профили. Дефолтный Docker-профиль блокирует около 44 syscall'ов, включая Код:
mountКод:
ptraceКод:
rebootКод:
mountAppArmor/SELinux. Дополнительные MAC-политики ограничивают доступ к файлам и операциям даже для процессов с нужными capabilities. Cgroups v2. Удалён Код:
release_agentRootless containers. Docker daemon работает от непривилегированного пользователя. Даже при полном побеге атакующий получает лишь права этого пользователя. Неприятно. Read-only root filesystem. Затрудняет размещение payload'ов, но обходится через tmpfs-монтирования. Своевременный патчинг. Container escape CVE в runc, containerd и ядре Linux публикуются регулярно. Aggressive patching schedule - самая эффективная защита от эксплуатации уязвимостей. Для минимизации поверхности атаки рекомендуется использовать специализированные container-optimized ОС: Bottlerocket, Flatcar, Talos Linux. Для обнаружения попыток побега в runtime - инструменты на основе eBPF: Falco и Sysdig Secure отслеживают аномальные системные вызовы, нетипичные деревья процессов и использование capabilities, характерное для эксплуатации. Заключение Побег из Docker контейнера - не экзотика, а стандартная часть kill chain при пентесте контейнерной инфраструктуры. Privileged mode и mounted Docker socket - тривиальные векторы, которые встречаются чаще, чем хотелось бы. Cgroups release_agent требует Код:
CAP_SYS_ADMINКонтейнер - набор софтовых абстракций, а не аппаратная граница. Попробуйте прогнать свои production-контейнеры по чеклисту из раздела «10 шагов». Если нашли Код:
--privileged |
| Время: 10:21 |