На проверке Kernel local privilege escalation уязвимость: как преждевременное раскрытие открывает окно эксплуатации

Сергей Попов

Администратор
30.12.2015
6 164
6 946
Специализация
  1. OSINT
  2. Веб-безопасность
Статус верификации
  1. ✓ Verified
Крупный план фрагмента материнской платы Linux-сервера с выжженной дорожкой в области контроллера памяти. На текстолите лазерная гравировка с идентификатором уязвимости, резкий белый свет лампы выд...


7 мая 2026 года исследователь Hyunwoo Kim выложил Dirty Frag - класс kernel local privilege escalation уязвимостей page cache write в ядре Linux, дающий root на Debian bookworm/trixie, RHEL 10.1, Ubuntu Noble и ещё нескольких дистрибутивах. Патчей не было. Совсем. Неизвестный сторонний исследователь слил детали одной из двух уязвимостей - xfrm-ESP Page-Cache Write - раньше согласованного срока, сломав эмбарго. Автору ничего не оставалось, кроме как опубликовать полный отчёт с работающим PoC.

По данным Microsoft, зафиксированы подозрительные цепочки действий, совпадающие с паттерном эксплуатации, хотя CISA SSVC классифицирует exploitation status как poc/none. Для тех, кто занимается vulnerability research или ведёт red team engagement, разница между координированным раскрытием и premature third-party disclosure - это разница между «патч вышел за месяц до PoC» и «рабочий эксплойт в открытом доступе, а вендор ещё собирает пакет». Разберём, как disclosure timeline создаёт или уничтожает окно эксплуатации kernel LPE, на верифицированных данных реальных CVE.

CVE disclosure timeline и его влияние на окно эксплуатации​

Coordinated vulnerability disclosure работает так: исследователь уведомляет вендора, даёт время на патч (90 дней по политике Google Project Zero, 45 дней по ZDI), публикует детали только после выхода исправления. В идеальном мире окно эксплуатации - промежуток между появлением публичного PoC и установкой патча конечными пользователями - минимально.

На практике процесс ломается в нескольких точках:

Сценарий 1: PoC после патча, но до его распространения. Патч лежит в mainline ядра, но дистрибутивы (RHEL, Ubuntu LTS, Debian Stable) ещё не собрали пакеты. Окно: от нескольких дней до нескольких недель. Стандартный n-day vulnerability window.

Сценарий 2: третья сторона раскрывает детали до готовности патча. Другой исследователь, CERT или автор grsecurity-поста публикует анализ или PoC до завершения coordinated disclosure. Вендор вынужден реагировать экстренно. Окно: от нуля (патча нет) до неопределённости. Именно это случилось с Dirty Frag.

Сценарий 3: full disclosure без координации. Исследователь сознательно публикует всё сразу. Встречается реже, удар максимальный.

В терминах MITRE ATT&CK второй сценарий - момент, когда T1588.006 (Vulnerabilities) мгновенно переходит в T1068 (Exploitation for Privilege Escalation): атакующий получает готовый PoC из публичного источника и применяет его при уже полученном initial access.

Место kernel LPE в цепочке атаки​

Зачем атакующему local privilege escalation Linux? Типичная цепочка на engagement:
  1. Initial access - SSH с украденными credentials, RCE через веб-приложение, скомпрометированный CI/CD
  2. Ограниченный shell - непривилегированный пользователь без root
  3. Kernel LPE (T1068, Privilege Escalation) - эксплуатация уязвимости ядра → root
  4. Persistence (T1547.006, Kernel Modules and Extensions) - загрузка kernel module, модификация initramfs
  5. Credential access, lateral movement, exfiltration - с root-правами доступно всё
В ряде ransomware-кампаний kernel LPE используется для эскалации, когда другие пути закрыты.

[Применимо: внутренний пентест, любая Linux-инфраструктура. Внешний пентест - только после получения shell через RCE или compromised credentials.]

CVE-2024-1086: эталон n-day window через Linux kernel privilege escalation PoC​

CVE-2024-1086 - use-after-free в компоненте netfilter (nf_tables) ядра Linux (CWE-416). CVSS 7.8 HIGH, вектор AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H - local access, low complexity, low privileges, no user interaction. Уязвимы ядра от 3.15 до 6.6.15, от 6.2 до 6.7.3, а также 6.8-rc1. В зоне поражения - Debian, Ubuntu, Red Hat, Fedora, Amazon Linux, Oracle Linux, Rocky Linux.

Механика: nft_verdict_init() допускает положительные значения drop error в verdict. Из-за reverted commit в netfilter nf_hook_slow() (core.c) предполагает, что верхние 16 бит NF_DROP-verdict содержат валидный errno. Когда verdict интерпретируется как NF_DROP, пакет деаллоцируется в nf_hook_slow(), но затем verdict совпадает с NF_ACCEPT, что приводит к дальнейшей обработке уже освобождённого пакета - double-free, классический вариант CWE-416.

Timeline: от responsible disclosure до массовой эксплуатации​

ДатаСобытиеВлияние на 0-day window
31 января 2024Координированное раскрытие, CVE присвоен, CVSS 7.8Патч в mainline, дистрибутивы начинают сборку
12-14 марта 2024Red Hat выпускает RHSA-2024:1249 и RHSA-2024:1332RHEL 7 закрыт
26 марта 2024Исследователь публикует блог + PoC на GitHubn-day window открыто
3 апреля 2024CrowdStrike ExPRT.AI повышает severity до CriticalАвтоматическая переприоритизация
30 мая 2024Эксплуатация in the wild подтверждена (inthewild.io, CISA KEV)n-day переходит в active exploitation
30 мая 2024CISA добавляет в KEV, дедлайн - 20 июня (21 день)Формальное требование к федеральным системам

Критическая точка - 26 марта. До этого момента уязвимость была запатчена в mainline, Red Hat выпустил обновления. Окно между mainline-патчем и PoC - ~55 дней; RHEL закрыт 12–14 марта, Ubuntu - позже. Кто обновился за это время - тот в безопасности.

Эксплойт работает через unprivileged user namespaces (включены по умолчанию на Debian, Ubuntu). Цепочка: double-free → сканирование физической памяти → обход KASLR → запись в modprobe_path → root shell.

Нюанс, который стоит держать в голове: после выхода из root shell система становится нестабильной и может упасть. На production это катастрофа. На engagement с согласованным scope - допустимо, но обязательно обсудить с заказчиком до запуска. Я видел, как после эксплуатации CVE-2024-1086 на тестовом стенде ядро уходило в панику через 5-10 минут - времени хватает, чтобы закрепиться, но не для вдумчивой пост-эксплуатации.

EPSS: 0.2806, percentile 0.9790 - top-5% всех CVE. Вероятность эксплуатации за 30 дней - почти 28%.

Предусловия и ограничения CVE-2024-1086​

Работает если:
  • Ядро Linux от 3.15 до 6.6.15, от 6.2 до 6.7.3, или 6.8-rc1
  • Unprivileged user namespaces включены (Debian, Ubuntu, KernelCTF-дистрибутивы по умолчанию)
  • Доступ к nf_tables через user namespace
Не работает если:
  • Ядро обновлено до 6.6.15+, 6.7.3+, 6.9+
  • Unprivileged user namespaces отключены (unprivileged_userns_clone = 0 на Debian/Ubuntu, user.max_user_namespaces = 0 на RHEL/Fedora)
  • AppArmor ограничивает создание namespace (Ubuntu 24.04+ с дефолтным профилем)
  • В CrowdStrike Falcon для Linux включена политика «suspicious processes» - поведенческая детекция срабатывает на syscall-паттерны double-free и записи в modprobe_path

Dirty Frag: преждевременное раскрытие уязвимости и класс page-cache write​

Dirty Frag - не изолированная уязвимость, а развитие целого класса. Ключевое отличие от предшественников: это детерминированный логический баг, не зависящий от timing window. Race condition не нужен, ядро не паникует при неудачной эксплуатации, success rate высокий. Для пентестера это подарок - предсказуемый, надёжный примитив.

EPSS Copy Fail: 0.9627, percentile 0.9987 - top-1%.

S:C (Scope Changed) означает выход за пределы контекста безопасности - возможен container escape. CWE-123 (Write-what-where Condition). Корневая причина связана с обработкой данных в подсистеме IPsec (xfrm). Та же подсистема xfrm/ESP была root cause для CVE-2022-27666 (heap buffer overflow в esp4.c/esp6.c, CVSS 7.8, CWE-787, EPSS 0.0552), хотя корневые причины различны. Подсистема xfrm/ESP - рецидивист: раз за разом порождает kernel LPE уязвимости.

При использовании splice(2) / MSG_SPLICE_PAGES страницы из pipe прикрепляются к skb. Путь расшифровки ESP выполняет decrypt in-place на externally-backed страницах, позволяя непривилегированному процессу перезаписывать page cache. Это store primitive - аналогичный Copy Fail, но через другую подсистему.

CVE-2026-43500 (RxRPC Page-Cache Write): CVSS 7.8 HIGH, вектор AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H. Обработчик DATA-пакетов в rxrpc_input_call_event() копирует skb в линейный только при skb_cloned() == true, но пропускает случай externally-owned paged fragments с флагом SKBFL_SHARED_FRAG.

Характеристикаxfrm-ESP (CVE-2026-43284)RxRPC (CVE-2026-43500)
Требует user namespaceДаНет
Блокируется AppArmor (Ubuntu)ДаНет
Модуль в default buildДа (esp4/esp6)Зависит от дистрибутива
Доступен на UbuntuДаДа (rxrpc.ko загружен)
Доступен на RHEL 10.1ДаНет (не включён)
EPSS0.9324 (top-1%)0.9277 (top-1%)

Chaining закрывает слепые зоны обоих вариантов: на Ubuntu, где AppArmor блокирует namespace, срабатывает RxRPC. На RHEL, где rxrpc.ko отсутствует, работает xfrm-ESP через user namespace. Красивая комбинация - один вектор всегда доступен.

Хронология срыва эмбарго​

  1. 30 апреля 2026 - исследователь сообщает о Dirty Frag мейнтейнерам ядра
  2. 7 мая 2026 - Hyunwoo Kim вынужден опубликовать полный отчёт с PoC обеих уязвимостей
  3. 8-9 мая 2026 - Debian выпускает DSA-6253-1 (trixie, linux 6.12.86-1) и DSA-6258-1 (bookworm, linux 6.1.170-3)
  4. 11 мая 2026 - RHEL выпускает RHSA-2026:16062 (kernel-0:6.12.0-124.56.1.el10_1)
  5. После 11 мая - CVE идентификаторы присвоены, патчи в mainline (f4c50a4034e6 и aa54b1d27fe0)
Окно между срывом эмбарго (шаг 2) и первыми патчами дистрибутивов (шаг 4) - минимум два дня. PoC публично доступен, защиты нет. По данным Microsoft, зафиксированы подозрительные цепочки действий, совпадающие с паттерном эксплуатации, хотя CISA SSVC классифицирует exploitation status CVE-2026-43284 как poc, а CVE-2026-43500 как none.

CISA оценивает CVE-2026-43284 по SSVC как Track* (следить, готовить патч, exploitation: poc), а CVE-2026-43500 - как Track (мониторить, exploitation: none). Публичных подтверждений эксплуатации in the wild на момент анализа не было, но расхождение между формальной классификацией и реальностью - отдельная история.

Принципиальный момент: Dirty Frag эксплуатируется независимо от наличия модуля algif_aead. Mitigation для Copy Fail через blocklist algif_aead НЕ защищает от Dirty Frag. Каждый новый представитель класса page-cache write обходит mitigation предыдущего. Это не баг - это свойство класса.

Ubuntu прямо указывает: «в контейнерных развёртываниях с произвольными third-party workloads уязвимость может обеспечить container escape». Репозиторий Percivalll/Dirty-Frag-Kubernetes-PoC (14 звёзд) демонстрирует node-level code execution из дефолтного непривилегированного Pod на Amazon EKS.

Ptrace race condition: иллюстрация third-party disclosure​

В качестве иллюстрации паттерна third-party disclosure рассмотрим характерный (гипотетический, но типичный) сценарий: уязвимость в ptrace_may_access(), где функция слишком мягко (fail open) обрабатывает процессы в стадии завершения. При выигрыше race condition атакующий мог бы читать файлы, ранее открытые завершающимся процессом - /etc/shadow, /etc/ssh/ssh_host_key - без соответствующих прав.

Типичная динамика: исследователь находит баг, предлагает патч, но без публичного давления исправление не приходит. Публикация анализа и PoC третьей стороной ускоряет реакцию мейнтейнеров. Workaround для ptrace-based уязвимостей: echo 3 > /proc/sys/kernel/yama/ptrace_scope - полностью отключает ptrace для непривилегированных процессов.

[Применимо: внутренний пентест, grey box. Legacy-инфраструктура с ядрами без свежих патчей - максимальный риск.]

Практическая оценка эксплуатируемости kernel LPE в окне n-day​

Когда появляется новая kernel local privilege escalation уязвимость с публичным PoC, на engagement нужно быстро ответить на три вопроса: (1) уязвимо ли ядро, (2) доступны ли необходимые примитивы, (3) какие mitigation активны.

Требования к окружению​

  • Доступ: shell непривилегированного пользователя на целевой Linux-системе
  • Инструменты: uname, lsmod, cat, sysctl - предустановлены на любом дистрибутиве
  • Сценарий: внутренний пентест, grey box / white box (shell уже получен)

Preflight-проверка​

Bash:
# Версия ядра - сопоставить с affected versions конкретной CVE
uname -r
# Загруженные модули - что торчит из attack surface
lsmod | grep -E 'nf_tables|esp4|esp6|rxrpc|af_packet'
# Unprivileged user namespaces - без них большинство LPE не взлетит
# Debian/Ubuntu:
sysctl kernel.unprivileged_userns_clone 2>/dev/null
# RHEL/Fedora:
sysctl user.max_user_namespaces 2>/dev/null
# Универсальная проверка (просто пробуем):
unshare -Urn id 2>&1 | head -1
# Ptrace scope - для ptrace-based race conditions
cat /proc/sys/kernel/yama/ptrace_scope
# AppArmor / SELinux - определяют доступность namespace
aa-status 2>/dev/null; getenforce 2>/dev/null

Decision tree для Dirty Frag​

  1. uname -r - ядро до 6.12.86 (Debian bookworm) или до 6.12.0-124.56.1 (RHEL 10) → версия уязвима
  2. lsmod | grep esp4 возвращает результат → xfrm-ESP вектор доступен
  3. sysctl kernel.unprivileged_userns_clone = 1 (Debian/Ubuntu) или sysctl user.max_user_namespaces > 0 (RHEL/Fedora), либо unshare -Urn id успешно → namespace доступен → xfrm-ESP exploit применим
  4. Если namespace заблокирован AppArmor → lsmod | grep rxrpc → если rxrpc загружен → RxRPC вектор
  5. Оба вектора заблокированы → Dirty Frag не эксплуатируем на этой системе
Аналогичная логика для CVE-2024-1086: ядро 3.15–6.6.15 / 6.2–6.7.3 + unprivileged namespaces + nf_tables доступен = exploitable.

Перед kernel LPE - проверить простые пути​

Kernel exploit - тяжёлая артиллерия. На production эксплуатация ядерной уязвимости может уронить систему (CVE-2024-1086 делает её нестабильной после закрытия root shell). Перед запуском стоит проверить:
  • SUID/SGID-бинари: find / -perm -4000 -type f 2>/dev/null
  • Sudo misconfigurations: sudo -l
  • Cron-задачи с world-writable скриптами
  • Capabilities на бинарях: getcap -r / 2>/dev/null
Если эти пути дают root - kernel LPE не нужен. Если нет - переходим к эксплуатации ядра, понимая риски нестабильности и заранее предупредив заказчика.

Ограничения kernel exploit LPE техник в современных средах​

Namespace и MAC-системы​

Ubuntu 24.04+ по умолчанию использует AppArmor-профиль, блокирующий unprivileged user namespaces. Это убивает значительную часть kernel LPE PoC - CVE-2024-1086, xfrm-ESP вектор Dirty Frag, CVE-2017-7308 (af_packet, CWE-681/CWE-787) - все зависят от namespace для доступа к целевой подсистеме.

RHEL/CentOS с SELinux в enforcing-режиме ограничивают syscall-паттерны через политики. На hardened-системах это может предотвратить trigger уязвимости даже при уязвимом ядре. Ключевое слово - «может»: конфигурация SELinux на каждой системе своя.

Контейнерная изоляция​

В Kubernetes с дефолтным seccomp-профилем Dirty Frag ограничен: xfrm user netlink interface требует CAP_NET_ADMIN. Но CVE-2026-43284 имеет S:C (Scope Changed) в CVSS-векторе - container escape возможен в средах без hardened seccomp profile.

CVE-2017-7308 в контейнере работает иначе, чем на голом хосте: как демонстрирует исследование Snyk, exploit через af_packet даёт root UID и все capabilities, но остаётся в namespace «клетке» - файловая система хоста недоступна, процессы не видны, сетевые интерфейсы изолированы. Для полного escape нужно дополнительно перезаписать struct nsproxy текущего контекста указателем на init_nsproxy хоста. То есть root есть, а толку - половина.

Module blocklisting как emergency mitigation​

Когда патч недоступен, а система уязвима:
Bash:
sudo sh -c "printf 'install esp4 /bin/false\ninstall esp6 /bin/false\n\
install rxrpc /bin/false\n' > /etc/modprobe.d/dirtyfrag.conf; \
rmmod esp4 esp6 rxrpc 2>/dev/null; true"
Когда НЕ работает: blocklisting esp4/esp6 ломает IPsec. На системе с VPN через IPsec - неприемлемо. Для ptrace-based уязвимостей workaround другой: sysctl -w kernel.yama.ptrace_scope=3 - полный запрет ptrace для непривилегированных процессов, что сломает strace и отладчики.

Mitigation Copy Fail (blocklist algif_aead) НЕ защищает от Dirty Frag - каждый следующий представитель класса page-cache write обходит mitigation предыдущего. Patch gap exploitation остаётся актуальным, и это не изменится, пока класс уязвимостей существует.

Обнаружение эксплуатации​

CrowdStrike Falcon, согласно публикациям вендора, детектирует CVE-2024-1086 через IOA (Indicators of Attack) при включённой политике «suspicious processes» для Linux. Поведенческая детекция срабатывает на характерные syscall-паттерны и попытки записи в modprobe_path. Для Dirty Frag на момент появления advisories вендор-специфичных сигнатур не было - ни у CrowdStrike, ни у SentinelOne, ни у Elastic.

Из open-source: KaraZajac/DIRTYFAIL (23 звезды, обновлён июль 2026) - детектор + PoC для Copy Fail и Dirty Frag; 0xlane/pagecache-guard (5 звёзд) - runtime integrity guard через O_DIRECT + fanotify для обнаружения page cache tampering. Оба проекта молодые, но рабочие.

LLM и расширение поверхности обнаружения kernel уязвимостей​

📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме

Координированное раскрытие в классической форме - 90-дневное окно, тихий патч, публикация после обновления - для kernel LPE работает всё хуже. Не потому, что исследователи безответственны, а потому, что хозяйство Linux-дистрибутивов распространяет патчи неравномерно. Debian trixie получил патч через 1 день, bookworm - через 2 дня, RHEL 10.1 - через 4 дня. А тысячи production-серверов с ядром из LTS-ветки, которое не обновляют принципиально, остаются уязвимыми месяцами.

Third-party disclosure ускоряет не только атакующих, но и защитников - и это не апология безответственного раскрытия, а констатация. На практике без публичного давления известные баги могут оставаться неисправленными годами, а third-party disclosure нередко становится катализатором для выпуска патча.

Для тех, кто занимается vulnerability research, мониторинг disclosure events - не формальность, а operational advantage. Kernel mailing list, grsecurity-посты, EPSS через API FIRST.org, CISA KEV RSS - инструменты, определяющие, на чьей стороне окажется время. EPSS в top-1% - сигнал к немедленному действию: либо вы используете patch gap exploitation на engagement, либо ваш клиент закрывает дыру до того, как это сделает кто-то другой. Если хочется потрогать kernel exploitation руками - pwn-категория на HackerLab.pro даёт стенд, где примитив нужно собрать в рабочую цепочку от trigger до root shell.
 
Мы в соцсетях:

Взломай свой первый сервер и прокачай скилл — Начни игру на HackerLab

🚀 Первый раз на Codeby?
Гайд для новичков: что делать в первые 15 минут, ключевые разделы, правила
Начать здесь →
🧭 Навигатор · ИБ 2026
Не знаешь, какой трек твой?
5 направлений ИБ, реальные зарплаты и точка входа для каждого — в одном треде.
JuniorSenior+
100K → 600K+ ₽ /мес
Открыть навигатор →
🔴 Свежие CVE, 0-day и инциденты
То, о чём ChatGPT ещё не знает — обсуждаем в реальном времени
Threat Intel →
💼 Вакансии и заказы в ИБ
Pentest, SOC, DevSecOps, bug bounty — работа и проекты от проверенных компаний
Карьера в ИБ →

HackerLab