Скрипт обнаружения для CVE-2026-31431 (Copy Fail), который проверяет версию ядра, наличие патча, конфигурации ядра, доступность сокета AF_ALG, setuid-бинарники и меры смягчения для определения статуса уязвимости в Linux-системах.
Только обнаружение. Рабочий PoC уже существует на copy.fail/#exploit. Этот скрипт предназначен для системных администраторов и команд безопасности, чтобы определить, где они уязвимы — или всё ещё уязвимы после установки патча.
29 апреля 2026 года исследовательская группа Xint Code Research публично раскрыла уязвимость под названием Copy Fail (CVE-2026-31431). Это логическая ошибка, которая незаметно присутствует в ядре Linux примерно с 2017 года — почти десятилетие — и позволяет любому непривилегированному локальному пользователю получить root.
Не «получить root при определённых условиях, с некоторой удачей и попутным ветром». Просто... получить root. Надёжно. Практически на каждом крупном дистрибутиве Linux.
Она затрагивает Ubuntu, Amazon Linux, RHEL, SUSE и всё остальное, что работает на стандартном ядре последних ~8 лет. Тот же скрипт, без перекомпиляции, без изменений под каждый дистрибутив.
Да, всё настолько плохо, как звучит.
Ядро Linux имеет криптоподсистему, доступную непривилегированным пользователям через сокеты AF_ALG. Существует механизм под названием splice(), который может передавать данные файла напрямую в эту подсистему без их копирования — это означает, что кэшированная в памяти ядра копия файла («page cache») оказывается внутри криптографической операции.
Один конкретный алгоритм — authencesn, используемый для расширенных порядковых номеров IPsec — имеет особенность: он использует выходной буфер как рабочую область и записывает 4 байта чуть дальше, чем положено. Обычно это безвредно. Но когда страницы page cache из setuid-бинарника, такого как /usr/bin/su, оказываются в цепочке этого выходного буфера (благодаря «оптимизации» 2017 года в algif_aead.c), эти 4 байта попадают прямо в кэшированную ядром копию бинарника.
Операция завершается ошибкой. Ядро никогда не помечает эту страницу как «грязную». Файл на диске не тронут. Инструменты проверки целостности файлов, проверяющие контрольные суммы на диске, не видят ничего подозрительного.
Но page cache — это то, что исполняется. А su имеет setuid root.
Полное техническое описание находится на xint.io и действительно стоит прочтения.
Семь из оригинального релиза плюс шесть новых проверок, добавленных для закрытия пробелов в обнаружении:
| № | Проверка | Что она ищет |
|---|---|---|
| 1 | Версия ядра | Находится ли это ядро в затронутом диапазоне (4.10–6.14)? |
| 2 | Наличие патча | Присутствует ли исправляющий коммит в вашем работающем ядре? |
| 3 | Модуль algif_aead | Загружен ли уязвимый модуль или может быть загружен? |
| 4 | CONFIG_CRYPTO_AUTHENC (новое) | Встроен ли CONFIG_CRYPTO_AUTHENC (=y) или он модуль (=m)? Эта единственная опция собирает и authenc, и authencesn. Встроенный вариант означает, что блокировка через modprobe blacklist не работает. |
| 5 | CONFIG_CRYPTO_USER_API_AEAD (новое) | Скомпилирован ли вообще пользовательский интерфейс AF_ALG AEAD? Если нет, весь путь эксплуатации закрыт на этапе компиляции. |
| 6 | Сокет AF_ALG | Может ли непривилегированный пользователь открыть его прямо сейчас? |
| 7 | Python os.splice | Доступен ли путь эксплуатации на чистом Python? |
| 8 | Setuid-бинарники | Расширенный список читаемых setuid-root целей, присутствующих в системе. |
| 9 | Смягчающие меры | AppArmor, SELinux, seccomp — что установлено? |
| 10 | Пользовательские пространства имён (новое) | Включены ли непривилегированные пользовательские пространства имён? (Не блокирует Copy Fail напрямую, но влияет на более широкую поверхность локального повышения привилегий.) |
| 11 | Прозрачные огромные страницы (новое) | Статус THP — может влиять на выравнивание page cache и надёжность эксплуатации. |
| 12 | Определение окружения (новое) | Контекст Docker/контейнера/ВМ — контейнеры используют ядро хоста; патчить нужно хост. |
| 13 | Предупреждение о root-пользователе (новое) | Предупреждает при запуске от root, поскольку несколько проверок дают ложные срабатывания для root независимо от ограничений для непривилегированных пользователей. |
Bash-скрипт покрывает ту же основную логику обнаружения, но опускает три специфичных для Python пункта:
| № | Проверка | Примечания |
|---|---|---|
| 1 | Версия ядра | |
| 2 | Наличие патча | |
| 3 | Модуль algif_aead | |
| 4 | Сокет AF_ALG | Использует Python как помощник, если доступен; иначе полагается на вывод из конфигурации ядра |
| 5 | Setuid-бинарники | Расширенный список, как в Python-версии |
| 6 | Смягчающие меры | AppArmor, SELinux, seccomp |
| 7 | CONFIG_CRYPTO_AUTHENC | |
| 8 | Пользовательские пространства имён | |
| 9 | Прозрачные огромные страницы | |
| 10 | Определение окружения |
Отсутствует в shell-скрипте (по сравнению с Python):
| Отсутствующая проверка | Причина |
|---|---|
| CONFIG_CRYPTO_USER_API_AEAD | Ещё не реализовано — запланировано |
| Доступность Python os.splice | Неприменимо к shell-скрипту |
| Предупреждение о root-пользователе | Ещё не реализовано — запланировано |
Ни один из скриптов ничего не исправляет и не эксплуатирует. Они сообщают вам правду о вашей системе, чтобы вы могли действовать.
# Склонируйте или скачайте скрипт, затем:
python3 cve-2026-31431-detect.py
Вот и всё. Цветной отчёт с итогом в конце.
Скрипт завершается с ненулевым кодом при обнаружении уязвимых условий, что делает его пригодным для использования в конвейерах:
| Код | Значение |
|---|---|
0 | Уязвимых условий не обнаружено |
1 | Обнаружено одно или несколько уязвимых условий |
# Пример: провалить шаг CI, если хост уязвим
python3 cve-2026-31431-detect.py
rc=$?
if [ $rc -eq 1 ]; then
echo "УЯЗВИМ — блокировать развёртывание"
elif [ $rc -ne 0 ]; then
echo "ОШИБКА — скрипт не завершился (код выхода $rc)"
fi
CVE-2026-31431 'Copy Fail' — Обнаружение уязвимости
Повреждение page cache authencesn / локальное повышение привилегий
Запуск от uid=1001, euid=1001
=== Версия ядра ===
[УЯЗВИМ] Версия ядра
Причина : Ядро находится в уязвимом диапазоне (4.10 – 6.14)
Детали : Релиз: 6.12.0-124.45.1.el10_1 — статус патча необходимо подтвердить
=== CONFIG_CRYPTO_AUTHENC (Конфигурация ядра) ===
[УЯЗВИМ] CONFIG_CRYPTO_AUTHENC
Причина : Собран как модуль (=m): автоматически загружается при bind() AF_ALG; блокировка через modprobe blacklist — правильная мера смягчения
=== CONFIG_CRYPTO_USER_API_AEAD (Конфигурация ядра) ===
[УЯЗВИМ] CONFIG_CRYPTO_USER_API_AEAD
Причина : Интерфейс AF_ALG AEAD — загружаемый модуль — непривилегированные пользователи могут получить доступ к криптоподсистеме через сокеты AF_ALG
...
СИСТЕМА, ВЕРОЯТНО, УЯЗВИМА К CVE-2026-31431
Рекомендуемые действия:
1. Примените обновление ядра вашего дистрибутива для CVE-2026-31431
2. До установки патча заблокируйте модуль:
echo 'install algif_aead /bin/false' > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null
ПРИМЕЧАНИЕ: это работает ТОЛЬКО когда CONFIG_CRYPTO_AUTHENC=m (модуль).
Если CONFIG_CRYPTO_AUTHENC=y (встроен), единственное решение — патч.
Дополнительный Bash-скрипт (cve-2026-31431-detect.sh) доступен для сред, где Python отсутствует или предпочтительны нативные shell-инструменты. Он выполняет 10 из 13 проверок — см. таблицу сравнения проверок выше для деталей отличий.
# Базовый запуск
bash cve-2026-31431-detect.sh
# JSON-вывод — подходит для приёма в SIEM, фактов Ansible, агрегации логов
bash cve-2026-31431-detect.sh --json > scan-results.json
# Тихий режим — выводить только итог (полезно в логах CI)
bash cve-2026-31431-detect.sh --quiet
# Отключить ANSI-цвета (для файлов логов)
bash cve-2026-31431-detect.sh --no-colour
Shell-скрипт использует те же коды выхода (0 = OK, 1 = уязвим) и выдаёт эквивалентный JSON-вывод для потребления в конвейерах. Если в системе доступен Python 3, shell-скрипт использует его для выполнения живого теста сокета AF_ALG; в противном случае он полагается на вывод из конфигурации ядра.
Настоящее исправление — это патч вашего ядра. Проверьте бюллетени безопасности вашего дистрибутива.
| Дистрибутив | Где искать |
|---|---|
| Ubuntu | ubuntu.com/security/CVE-2026-31431 |
| RHEL / Amazon Linux | dnf update kernel |
| SUSE | zypper update kernel-default |
| Debian | apt update && apt upgrade |
Если проверка CONFIG_CRYPTO_AUTHENC сообщает =m (собран как модуль, а не встроен), вы можете заблокировать его:
echo 'install algif_aead /bin/false' > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null
Важно: эта мера не действует, если
CONFIG_CRYPTO_AUTHENC=y(встроен). В этом случае единственное решение — патч ядра. Проверка CONFIG_CRYPTO_AUTHENC в скрипте сообщает вам, в какой ситуации вы находитесь. Обратите внимание, чтоCONFIG_CRYPTO_AUTHENC— это правильный ключ конфигурации ядра — он собирает оба модуляauthencиauthencesnиз одной опции.
Это может повлиять на IPsec, если вы его используете — проверьте перед развёртыванием по всей инфраструктуре.
Исправление в апстриме — этот коммит — он откатывает оптимизацию AEAD на месте 2017 года в algif_aead.c, разделяя scatterlist'ы источника и назначения, чтобы страницы page cache больше не могли попасть в доступный для записи буфер назначения.
Если вы запускаете это внутри Docker-контейнера, Kubernetes-пода или другой контейнерной среды, скрипт предупредит вас: контейнеры используют ядро хоста. Уязвимость находится в ядре, а не в образе контейнера. Вы должны оценить и пропатчить хост.
# GitHub Actions
# Шаг естественным образом завершится ошибкой и заблокирует конвейер, когда скрипт выйдет с кодом 1.
# Дополнительная настройка не требуется — ненулевые коды выхода по умолчанию проваливают шаги.
- name: Проверка CVE-2026-31431
run: |
python3 cve-2026-31431-detect.py
rc=$?
if [ $rc -eq 1 ]; then
echo "УЯЗВИМ — конвейер заблокирован"
exit 1
elif [ $rc -ne 0 ]; then
echo "ОШИБКА — скрипт обнаружения не завершился (код выхода $rc)"
exit $rc
fi
# Ansible
# Использует playbook_dir, чтобы путь к скрипту разрешался корректно.
# failed_when проверяет любой ненулевой код выхода (уязвимость ИЛИ ошибка скрипта).
- name: Проверка на CVE-2026-31431
script: "{{ playbook_dir }}/cve-2026-31431-detect.py"
register: cve_check
failed_when: cve_check.rc != 0
# Проверка Nagios / мониторинг (shell-скрипт — поддерживает коды выхода нативно)
bash cve-2026-31431-detect.sh --quiet
# код выхода 0 = OK, код выхода 1 = CRITICAL (уязвим)
# JSON-вывод для SIEM / агрегации логов (shell-скрипт)
bash cve-2026-31431-detect.sh --json --quiet > /var/log/cve-2026-31431-$(hostname)-$(date +%Y%m%d).json
| Дата | Событие |
|---|---|
| 2026-03-23 | Сообщено команде безопасности ядра Linux |
| 2026-03-24 | Подтверждено |
| 2026-03-25 | Предложены и рассмотрены патчи |
| 2026-04-01 | Исправление внесено в основную ветку ядра |
| 2026-04-22 | Присвоен CVE-2026-31431 |
| 2026-04-29 | Публичное раскрытие |
Благодарность Taeyang Lee из Theori за первоначальную исследовательскую идею и исследовательской группе Xint Code Research за полный отчёт о раскрытии.
Нашли ложное срабатывание? Дистрибутив, который скрипт пропускает? Конфигурацию ядра, которую стоит проверить? PR приветствуются. Цель — точный сигнал, а не просто пугающий красный текст.
Этот инструмент предоставляется как есть для целей защитной безопасности. Запускайте его на системах, которые вы уполномочены проверять. Не занимайтесь ерундой.