Приведённые ниже идентификаторы, оценки CVSS и CWE основаны на данных disclosure-отчёта и могут быть уточнены после официальной регистрации.
732 байта Python-кода, один промпт ИИ-системе Xint Code от Theori - и детерминистический root на каждом крупном дистрибутиве Linux, выпущенном после 2017 года. CVSS 7.8 (HIGH), CWE-1288 (Incorrect Resource Transfer Between Spheres), Metasploit-модуль опубликован в день раскрытия. На момент публикации CVE-2026-31431 не зарегистрирован в NVD - все идентификаторы и оценки взяты из disclosure-отчёта и могут измениться. Для пентестера, привыкшего бороться с KASLR, race window и нестабильными PoC под каждую версию ядра, Copy Fail - событие уровня Dirty Pipe, только масштабнее. Разберём механику бага, пошаговую эксплуатацию и конкретные действия по обе стороны баррикады.
Место Copy Fail в цепочке атаки
Copy Fail - local privilege escalation, техника T1068 (Exploitation for Privilege Escalation) по MITRE ATT&CK, с маппингом на T1548.001 (Setuid and Setgid): эксплойт злоупотребляет setuid-бинарём для получения root. В реальном пентесте уязвимость занимает чёткую позицию между initial access и полным контролем над хостом: Подробнее - в нашем статье о linux для пентестера.- Initial access - атакующий получает low-privilege shell (RCE в веб-приложении, SSH с утечённым паролем, скомпрометированный CI/CD-раннер).
- Linux privilege escalation через Copy Fail - скрипт превращает
www-dataилиnobodyвrootза секунды. Ни race condition, ни per-distro offsets. - Post-exploitation - дамп credentials, lateral movement, persistence.
Что не затронуто: микроВМ (AWS Firecracker, Fargate), gVisor, V8-изоляты (Cloudflare Workers). Устоявшая граница - та, где у каждого tenant своё ядро.
Когда проверять Copy Fail первым
На внутреннем пентесте после получения shell проверка Copy Fail занимает меньше времени, чем перебор SUID-бинарей или разбор cron jobs. Decision tree для выбора вектора linux privilege escalation на хосте с ядром 2017+:| Условие | Действие |
|---|---|
Модуль algif_aead загружен или built-in, ядро не пропатчено | Copy Fail - root за секунды |
algif_aead заблокирован через initcall_blacklist | Переход к классике: SUID, capabilities, cron, sudo misconfig |
| gVisor / kata / microVM | Copy Fail неприменим, искать другие векторы |
| SELinux enforcing с нестандартной политикой | Может заблокировать AF_ALG - нужна проверка |
Анатомия бага: AF_ALG, page cache и четыре байта
Чтобы понять, почему Copy Fail работает детерминистически на любом дистрибутиве, разберём три компонента ядра, которые эксплойт связывает в одну цепочку.AF_ALG и userspace crypto API
Ядро предоставляет внутренний крипто-API для kTLS, IPsec и других подсистем. Пользовательские программы обращаются к нему через семейство сокетовAF_ALG - и это доступно непривилегированным процессам. Модуль algif_aead даёт интерфейс для AEAD-шифров (Authenticated Encryption with Associated Data).Непривилегированный процесс создаёт сокет
AF_ALG, выполняет bind() к AEAD-шаблону (authencesn(hmac(sha256),cbc(aes))), устанавливает ключ через setsockopt(), передаёт данные через sendmsg() или splice() и запускает крипто-операцию вызовом recvmsg().Критический элемент -
splice(). Этот системный вызов (T1106, Native API) передаёт данные через ссылки на страницы page cache, не копируя их. Вот тут и зарыта собака.Page cache и setuid-бинари
Page cache - общесистемный кеш содержимого файлов в оперативной памяти. Когда процесс читает/usr/bin/su, ядро загружает страницы с диска в page cache. Последующие обращения - от любого пользователя, включая execve() - читают те же закешированные страницы.Если атакующий модифицирует страницу page cache, принадлежащую setuid-бинарю, при следующем запуске этого бинаря загрузится изменённый код - с привилегиями владельца файла (root). На диске файл остаётся нетронутым.
Оптимизация 2017 года и out-of-bounds write
В 2017 годуalgif_aead получил оптимизацию in-place операций: destination и reference pages объединялись в единый scatterlist. Код не проверял, допустима ли запись алгоритмом за пределы выделенного output-региона. Девять лет никто этого не заметил.Шаблон
authencesn при расшифровке выполняет 4-байтовую запись scratch-данных по фиксированному смещению:
C:
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
splice() атакующий подключает страницы page cache целевого файла в scatterlist. Четыре «мусорных» байта authencesn записываются не в буфер пользователя, а в page cache произвольного read-only файла. Атакующий контролирует: какой файл модифицируется, смещение и конкретные 4 байта. Функция возвращает -EBADMSG (ошибка аутентификации), но запись уже произведена.По данным Bugcrowd, баг прятался девять лет потому, что подсистему
crypto/ ревьюили как криптографы: IND-CPA, side channels, валидация параметров. Вопрос «должна ли эта страница памяти вообще быть writeable» - из другой дисциплины, и он просто выпал из поля зрения.Пошаговая эксплуатация Copy Fail
Требования к окружению
| Параметр | Значение |
|---|---|
| Сценарий | Внутренний пентест, post-exploitation с low-priv shell |
| Целевые ОС | Любой Linux с ядром от 2017 г.: Ubuntu, RHEL, Amazon Linux, SUSE, Debian |
| Привилегии | Непривилегированный локальный пользователь |
| Зависимости | Python 3 (стандартная библиотека) или Go/Rust; модуль algif_aead загружен |
| RAM | От 512 МБ (page cache должен вместить целевой бинарь) |
| Race condition | Не требуется |
| Per-distro offsets | Не требуются |
| Контейнеры | Работает при shared kernel (Docker default). Не работает из gVisor, kata, microVM |
Последовательность шагов
По техническому описанию из disclosure Xint Code и анализу Cloudflare:
📚 Часть контента скрыта. Этот материал доступен участникам сообщества с рангом One Level или выше
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Получить доступ просто — достаточно зарегистрироваться и проявить активность на форуме
Ограничения техники
| Ограничение | Детали |
|---|---|
| Только локальный доступ | Copy Fail не эксплуатируется удалённо - нужен shell |
Модуль algif_aead заблокирован | Workaround через initcall_blacklist закрывает вектор |
| gVisor / microVM / kata | Не работает - отдельное ядро на tenant |
| AppArmor / SELinux enforcing | Могут ограничить AF_ALG или splice(), но default-политики дистрибутивов этого не делают |
| Hardened kernels (grsecurity) | С ограничениями на AF_ALG - вектор заблокирован |
Copy Fail vs Dirty COW vs Dirty Pipe
Три уязвимости работают через один примитив - запись в page cache read-only файлов - но фундаментально различаются в механике:| Характеристика | Dirty COW (CVE-2016-5195) | Dirty Pipe (CVE-2022-0847) | Copy Fail (CVE-2026-31431)¹ |
|---|---|---|---|
| CVSS | 7.0 NVD / 7.8 Red Hat (HIGH) | 7.8 (HIGH) | 7.8 (HIGH, заявленный) |
| CWE | CWE-362 (Race Condition) | CWE-665 NVD / CWE-908 Red Hat (Improper Initialization / Use of Uninitialized Resource) | CWE-1288 (Incorrect Resource Transfer) |
| Тип бага | Race condition в mm/gup.c | Неинициализированные флаги pipe buffer | Logic flaw в algif_aead |
| Стабильность | Нестабильный, зависит от timing | Стабильный | Детерминистический |
| Per-distro offsets | Часто требуются | Не требуются | Не требуются |
| Окно уязвимости | 2007-2016 (9 лет) | 2020-2022 (2 года) | 2017-2026 (9 лет) |
| CISA KEV | Да (2022-03-03) | Да (2022-04-25) | Да (2026-05-01) |
| EPSS | 0.9418 (Top 1%) | 0.8121 (Top 1%) | 0.0257 (85-й перцентиль) |
| Container escape | Нет | Ограниченно | Да (shared kernel) |
Dirty COW требовал гонки потоков и мог уронить систему. Dirty Pipe работал стабильнее, но затрагивал узкий диапазон ядер (5.8 - 5.16.11). Copy Fail берёт детерминизм Dirty Pipe и добавляет покрытие всех ядер 2017+ (чего у Pipe не было), плюс минимальный форензик-след.
По данным SafeBreach: эксплойт использует только стандартные системные вызовы (
socket, setsockopt, splice, sendmsg, recvmsg) и стандартную библиотеку Python - отпечаток минимальный. Помимо Python-скрипта, на GitHub доступны реализации на Rust (iss4cf0ng/CVE-2026-31431-Linux-Copy-Fail, 50 звёзд) и минимальный ELF без libc (Crihexe/copy-fail-tiny-elf-CVE-2026-31431, 61 звезда).Что увидит и не увидит защита
Поведенческий детект
По данным Cloudflare, их behavioral detection зафиксировал эксплуатацию в течение нескольких минут - без обновления сигнатур, без ручного вмешательства. Система связала цепочку: интерпретатор скрипта → крипто-подсистема ядра → запуск setuid-бинаря - и отметила как аномалию по fleet-wide паттернам. Это работает при масштабе телеметрии Cloudflare. На среднем Linux-хосте без EDR - картина совсем другая.IoC для мониторинга
Конкретные индикаторы:- Создание
AF_ALGсокетов непривилегированными процессами (для большинства workloads это аномалия - кому в продакшене нужен userspace crypto через сокеты?). splice()с файловым дескриптором setuid-бинаря в качестве источника.- Последовательность
AF_ALG bind→splice→recvmsg→execvesetuid-бинаря от одного PID/сессии.
auditd - мониторинг обращений к AF_ALG:
Bash:
auditctl -a always,exit -F arch=b64 -S socket -F a0=0x26 -k af_alg_access
Слепые зоны стандартного мониторинга
Файловый мониторинг (AIDE, Tripwire,inotify) тут бесполезен: Copy Fail модифицирует page cache, а не файл на диске. Хеши файлов остаются неизменными - можно хоть каждую минуту проверять, ничего не найдёшь. Auditd в default-конфигурации не логирует AF_ALG. Стандартные EDR без kernel-level телеметрии могут пропустить вектор, если не отслеживают крипто-подсистему.По вендорам: CrowdStrike Falcon и SentinelOne с kernel-level телеметрией имеют больше шансов на детект по поведенческим паттернам, но конкретных подтверждений от этих вендоров на момент раскрытия не опубликовано. Для Elastic 8.x+ потребуется custom detection rule на цепочку syscalls - стандартные правила Elastic Security Labs покрывают linux privilege escalation через process capabilities, но Copy Fail эксплуатирует другой вектор. Kaspersky EDR Expert на Linux-агенте: публичных данных о детекте Copy Fail нет.
Митигация и чеклист реагирования
Быстрая блокировка
Отключение модуляalgif_aead - самый быстрый workaround. По данным ThreatLocker:
Bash:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif.conf
rmmod algif_aead 2>/dev/null || true
rmmod не сработает. Red Hat рекомендует boot-параметры (RHSB-2026-002): initcall_blacklist=algif_aead_init (только AEAD-модуль), initcall_blacklist=af_alg_init (весь AF_ALG интерфейс) или initcall_blacklist=crypto_authenc_esn_module_init (конкретный алгоритм). Red Hat предупреждает о возможном влиянии на производительность kTLS и IPsec.Статус патчей по дистрибутивам
Upstream-фикс - коммитa664bf3d603d, откатывающий in-place оптимизацию 2017 года.| Дистрибутив | Advisory | Версия ядра | Дата |
|---|---|---|---|
| RHEL 10 | RHSA-2026:13566 | kernel-0:6.12.0-124.55.1.el10_1 | 2026-05-04 |
| Debian bookworm | DSA-6243-1 | linux 6.1.170-1 | 2026-05-01 |
| Debian trixie | DSA-6238-1 | linux 6.12.85-1 | 2026-04-30 |
| Ubuntu noble (NVIDIA) | USN-8289-1 | linux-nvidia 6.8.0-1054.57 | 2026-05-20 |
| Ubuntu focal | USN-8280-1 | linux 5.4.0-230.250 | 2026-05-19 |
| Ubuntu bionic | USN-8281-1 | linux 4.15.0-250.262 | 2026-05-19 |
RHEL 6 и RHEL 7 не затронуты, согласно Red Hat Security Advisory.
Хронология раскрытия
Для понимания окна экспозиции - ключевые даты по данным RHSB-2026-002:- 23 марта 2026 - исследователь связывается с upstream.
- 1 апреля - патч принят в mainline.
- 22 апреля - CVE опубликован.
- 29 апреля - публичный блог, PoC, Metasploit-модуль.
- 1 мая - CISA добавляет в KEV.
- 4 мая - первый фикс для RHEL-9 выпущен.
Чеклист для эксплуатации
Для передачи в отдел эксплуатации - конкретные действия:- Определить версию ядра на всех Linux-хостах:
uname -r. - Проверить наличие модуля:
lsmod | grep algif_aead(loadable) илиcat /proc/crypto | grep authenc(built-in). - Если патч недоступен - применить
initcall_blacklist=algif_aead_initв параметрах загрузки. - Если модуль загружаемый - выгрузить через
rmmodи заблокировать черезmodprobe.d. - Настроить auditd-правило на
AF_ALG(syscallsocketсa0=0x26). - Проверить kernel logs за последние 48 часов на следы эксплуатации.
- Для контейнерных сред - оценить runtime: shared kernel (Docker default) или изолированный (gVisor, kata, Firecracker).
- Применить патч ядра при первой возможности.
- Верифицировать: после обновления попытка
bind()кauthencesnчерезAF_ALGдолжна использовать safe path без in-place оптимизации.
crypto/ ревьюили десятки разработчиков, и каждый смотрел как криптограф: корректность шифрования, побочные каналы, валидация параметров. Вопрос «а должна ли страница памяти, пришедшая через splice(), оказаться в writable-части scatterlist» - из другой дисциплины. И он не пришёл в голову никому. Copy Fail - не провал code review. Это системное слепое пятно на стыке крипто и управления памятью. И оно будет повторяться, потому что ядро Linux содержит десятки подобных стыков, где одна подсистема доверяет инвариантам другой без явной проверки.Theori заявляет, что Xint Code нашёл баг за час с одного промпта. Если стоимость обнаружения kernel-grade linux privilege escalation упала на порядок - а публичные PoC-репозитории Copy Fail уже набрали суммарно более 800 звёзд на GitHub - бюджетирование ядерных LPE как «редких событий» больше не работает. EPSS Copy Fail пока 0.0257, намного ниже Dirty COW (0.9418) или Dirty Pipe (0.8121), но Metasploit-модуль с первого дня и CISA KEV не оставляют двусмысленности. Следующий Copy Fail - вопрос месяцев. Готовиться к нему стоит не патчами задним числом, а мониторингом крипто-подсистемы, которую большинство команд до сих пор считает «чужой территорией». Проверьте свои хосты по чеклисту из раздела выше -
lsmod | grep algif_aead покажет, есть ли у вас проблема, за десять секунд.