CVE-2022-0492: как дыра четырёхлетней давности до сих пор ломает контейнеры
CVE-2022-0492: как дыра четырёхлетней давности до сих пор ломает контейнеры
Представьте: вы развернули WordPress в Docker, настроили nginx как reverse proxy, закрыли всё лишнее через nftables. Контейнер изолирован — что может пойти не так? Злоумышленник находит уязвимый плагин, получает shell в контейнере, и через несколько секунд он уже root на хосте. Не потому что взломал Docker. А потому что ядро вашего сервера содержит CVE-2022-0492 — баг, запатченный ещё в 2022 году, который 2 июня 2026 года CISA занесла в каталог Known Exploited Vulnerabilities. Занесла — потому что его эксплуатируют прямо сейчас. На таких серверах, как ваш.
ЧТО ПРОИЗОШЛО
CVE-2022-0492 — это уязвимость в функции cgroup_release_agent_write в файле kernel/cgroup/cgroup-v1.c ядра Linux. CVSS 7.8 (High), CWE-862 (Missing Authorization). Уязвимость была обнаружена исследователями Yiqi Sun и Kevin Wang из Huawei и раскрыта в феврале 2022 года. Патч вышел тогда же — в версии ядра 5.17-rc3. Казалось бы, история закончилась четыре года назад.
Но 2 июня 2026 года CISA добавила CVE-2022-0492 в KEV-каталог с дедлайном для федеральных агентств — 5 июня 2026 года. Попадание в KEV означает подтверждённую активную эксплуатацию в реальных атаках. Четыре года после патча — и баг всё ещё работает на незапатченных системах. Причина проста: legacy-серверы без процесса обновления ядра, embedded-устройства с замороженными ядрами, и контейнерные хосты, где обновляли контейнеры, но забывали про ядро хоста.
ЧТО ТАКОЕ CGROUPS V1 И RELEASE_AGENT
Control groups (cgroups) — это механизм ядра Linux, который ограничивает и учитывает ресурсы (CPU, память, сеть) для группы процессов. Именно на cgroups построены все контейнеры: Docker, Kubernetes, LXC используют cgroups для изоляции. Существует две версии: cgroups v1 (старая, до сих пор широко используется) и cgroups v2 (новая, унифицированная иерархия). CVE-2022-0492 затрагивает только v1.
В cgroups v1 есть механизм release_agent — специальный файл, в который администратор может записать путь к программе. Ядро запускает эту программу автоматически, когда cgroup становится пустой (все процессы завершились). Запускает от имени root, вне каких-либо namespace-ограничений. Это легитимная функция для автоматической уборки ресурсов. Представьте это как уборщика с мастер-ключом: он входит после того, как все ушли, и делает своё дело. Проблема в том, кто может написать ему инструкцию.
КАК РАБОТАЕТ БАГ
Суть ошибки — отсутствие проверки привилегий при записи в файл release_agent. До патча ядро не проверяло, что процесс, записывающий путь в release_agent, обладает привилегией CAP_SYS_ADMIN в исходном (host) namespace. Это и есть CWE-862: отсутствующая проверка авторизации.
Конкретный путь эксплуатации использует пользовательские namespace (user namespaces). Linux позволяет непривилегированному процессу создать новый user namespace через команду unshare, в котором этот процесс получает CAP_SYS_ADMIN — но только внутри этого namespace. Затем процесс монтирует cgroupfs внутри нового namespace и записывает в release_agent путь к произвольному скрипту. Ядро не проверяет, что CAP_SYS_ADMIN получена внутри контейнерного namespace, а не в исходном. Когда cgroup опустеет — ядро выполнит скрипт от root на хосте.
КАК ЭТО ЭКСПЛУАТИРУЕТСЯ
Атакующий, получивший shell внутри контейнера, выполняет следующую последовательность. Создаётся новый user namespace — непривилегированный процесс получает в нём CAP_SYS_ADMIN, но только внутри этого namespace. Затем монтируется cgroupfs, создаётся дочерняя cgroup, и в файл release_agent корневой cgroup записывается путь к скрипту-бэкдору. Далее включается notify_on_release для созданной cgroup, и процесс внутри неё завершается — cgroup опустела, ядро вызывает release_agent. Скрипт выполняется от root в контексте хоста, минуя все namespace-ограничения контейнера.
Важно понимать: для базовой эксплуатации через user namespaces не требуется быть root внутри контейнера. Достаточно непривилегированного пользователя — при условии, что user namespaces включены (а они включены по умолчанию в Ubuntu, Debian и большинстве дистрибутивов). Для root-процесса внутри контейнера (например, nginx, запущенного от root) условия ещё проще.
ЧТО ПРОИСХОДИТ ДАЛЬШЕ — ЗАВИСИТ ОТ КОНФИГУРАЦИИ
Результат эксплуатации зависит от того, насколько hardened ваша среда. Если контейнер запущен с AppArmor, SELinux в enforcing-режиме или Seccomp — они блокируют необходимые системные вызовы (монтирование cgroupfs, unshare) ещё до того, как атака сможет продвинуться. Docker по умолчанию применяет seccomp-профиль, который в теории ограничивает эти операции — но только если вы не запускаете контейнер с флагами --privileged, --security-opt seccomp=unconfined или --cap-add SYS_ADMIN.
Если же контейнер запущен без дополнительных средств защиты — или с ослабленными профилями (что нередко встречается в CI/CD-средах, dev-окружениях и «быстрых» деплоях) — эксплуатация успешна и приводит к полному захвату хоста. В среде Kubernetes атакующий, захвативший один pod на ноде с cgroups v1, может скомпрометировать все остальные поды на той же ноде и далее двигаться по кластеру.
РЕАЛЬНАЯ ЦЕПОЧКА АТАКИ
Типичный сценарий, который сейчас эксплуатируется: веб-сервер с WordPress работает в Docker-контейнере. Атакующий находит уязвимый плагин — RCE или загрузку файлов — и получает shell от имени www-data внутри контейнера. Хост работает на Ubuntu 20.04 с ядром, которое не обновляли с момента установки два года назад. cgroups v1 активен, AppArmor не настроен для контейнеров, Seccomp не усилен. Через CVE-2022-0492 атакующий за несколько секунд получает root на хосте, читает /etc/shadow, устанавливает SSH-бэкдор и получает постоянный доступ к серверу. Контейнер при этом продолжает работать — ничего снаружи не сломалось, никаких алертов.
ТАЙМЛАЙН
Ноябрь 2021 года — команда Aqua Security Team Nautilus фиксирует первую реальную эксплуатацию техники container escape через release_agent в дикой природе. Заметьте: ещё без CVE, ещё без патча — просто тихо работающий эксплойт в реальных атаках. 4 февраля 2022 года — Linux раскрывает CVE-2022-0492, выходит патч в ядро 5.17-rc3. Март 2022 года — Ubuntu, Red Hat, Debian выпускают обновлённые ядра. Все обновились? Нет. 2 июня 2026 года — CISA добавляет CVE-2022-0492 в KEV с дедлайном для федеральных агентств США 5 июня 2026 года. Четыре года прошло с момента патча. Атаки идут до сих пор. Это не аномалия — это индустриальная норма для незапатченных систем.
КАК ЭТО ПРОСУЩЕСТВОВАЛО 4+ ЛЕТ
Уязвимость жила в ядре с момента появления user namespaces — функциональности, добавленной в Linux 3.8 в 2013 году. Почти десять лет. Техника эксплуатации через release_agent была известна в security-сообществе задолго до 2022 года: в июле 2019 года исследователь Google Project Zero Феликс Вильгельм (Felix Wilhelm) опубликовал PoC контейнерного побега через эту функцию для привилегированных контейнеров. Все знали, что release_agent запускается от root. Но считалось: чтобы туда записать, нужен CAP_SYS_ADMIN в host namespace. Именно это предположение никто не проверил в коде.
Патч оказался однострочным. Один вызов ns_capable(ns, CAP_SYS_ADMIN) в нужном месте — коммит 24f6008564183aa120d07c03d9289519c2fe02af в репозитории Torvalds. Десять лет уязвимости, одна строка исправления. Palo Alto Unit 42 назвали её «одной из простейших Linux privilege escalation за последнее время» — и это не комплимент разработчикам ядра. Это напоминание о том, что самые опасные баги часто выглядят как скучные логические ошибки.
ПОЧЕМУ ЭТО ВСЁ ЕЩЁ АКТУАЛЬНО
Добавление в KEV через четыре года после патча — это сигнал о масштабе проблемы. Вектор атаки — локальный, но в контексте контейнеров «локальный» означает «получил shell в любом контейнере на хосте». А получить shell в веб-контейнере через уязвимый WordPress-плагин — это давно не rocket science. Реальная угрозовая модель выглядит так: CVE в плагине → RCE в контейнере → CVE-2022-0492 → root на хосте → полный контроль над всеми контейнерами и данными.
Особенно уязвимы контейнерные хосты, где «обновляли приложения, но не ядро» — это распространённая ошибка. Docker-образы пересобирают регулярно, а apt upgrade на хосте с последующим reboot — делают раз в год или никогда. Именно такие системы сейчас в прицеле.
КАК ЭТОГО НЕ ДОПУСТИТЬ В БУДУЩЕМ
Главный урок CVE-2022-0492 жёсткий: kernel hardening и container hardening — два разных слоя, и процесс патчинга нужен для обоих. Docker-образы обычно пересобирают по пайплайну, а ядро хоста остаётся без внимания месяцами. Именно эти хосты сейчас в прицеле.
Настройте автоматические обновления ядра. На Ubuntu это делается через unattended-upgrades — пакет, скорее всего, уже установлен, но security-обновления с автоматическим reboot нужно включить явно:
sudo dpkg-reconfigure -plow unattended-upgrades
Команда откроет интерактивный диалог — выберите «Yes». Чтобы разрешить автоматический reboot (например, в 02:00), добавьте в /etc/apt/apt.conf.d/50unattended-upgrades:
Unattended-Upgrade::Automatic-Reboot "true";
Unattended-Upgrade::Automatic-Reboot-Time "02:00";
На RHEL-семействе аналог — dnf-automatic. Установите пакет и включите таймер:
sudo dnf install -y dnf-automatic
sudo systemctl enable --now dnf-automatic.timer
Подпишитесь на CISA KEV-фид — если CVE туда попало, это уже не «надо бы обновиться», это «атакуют прямо сейчас». И как долгосрочная задача — миграция на cgroups v2: новая архитектура не имеет release_agent вообще, весь этот класс атак просто исчезает.
ОБНОВЛЕНИЕ
Первый шаг — проверить версию ядра и статус cgroups на хосте. Команда uname -r покажет текущее ядро. Ubuntu 22.04 LTS (jammy) и Ubuntu 24.04 LTS (noble) не подвержены уязвимости — они вышли уже с защищёнными ядрами. Для Ubuntu 20.04 LTS (focal) патч включён начиная с ядра 5.4.0-105-generic (март 2022): если у вас старее — система уязвима. Для Ubuntu 18.04 LTS (bionic) — с ядра 4.15.0-173-generic.
uname -r
Проверить, используете ли вы cgroups v1 или v2, можно командой ниже. На cgroups v1 вы увидите множество отдельных директорий — cpu, memory, devices, blkio и т.д. — каждая для своей подсистемы. На cgroups v2 — единый каталог unified или просто файлы вроде cgroup.controllers прямо в корне. Если видите v2 — уязвимость не применима.
ls /sys/fs/cgroup/
Для обновления ядра на Ubuntu/Debian выполните:
sudo apt update && sudo apt upgrade -y
sudo reboot
На RHEL/AlmaLinux/Rocky Linux:
sudo dnf clean metadata && sudo dnf upgrade -y kernel
sudo reboot
После reboot повторно выполните uname -r и убедитесь, что ядро обновилось. Обновление ядра без reboot не даёт эффекта — старое ядро продолжает работать в памяти до перезагрузки.
Проверить, защищён ли ваш Docker-контейнер от эксплуатации, можно скриптом от Unit 42 (Palo Alto Networks) — CVE-2022-0492-Checker, доступным на GitHub. Он проверяет, может ли контейнер монтировать cgroupfs и записывать в release_agent, и выдаёт явный ответ: уязвим или нет. Если обновление ядра временно невозможно — убедитесь, что контейнеры запущены с включённым AppArmor или SELinux в enforcing-режиме, и не используют флаги --privileged или --security-opt seccomp=unconfined.
ВЫВОДЫ
CVE-2022-0492 — хороший пример того, почему «патч вышел» не равно «вы защищены». Попадание старого CVE в CISA KEV — это не новость о новой уязвимости. Это новость о том, что на незапатченных системах её активно используют прямо сейчас. Если у вас есть контейнерные хосты с ядром старше 2022 года и cgroups v1 — проверьте и обновите сегодня. Команда uname -r + apt upgrade + reboot — три шага, которые закрывают реальный вектор атаки.
