
Образовательная переработка PoC для Copy Fail (CVE-2026-31431) — повышение привилегий в Linux kernel через algif_aead in-place crypto + запись в page-cache через splice()
Образовательная переработка proof-of-concept от Theori/Xint для CVE-2026-31431 —
локальной уязвимости повышения привилегий в интерфейсе криптографических сокетов
algif_aead ядра Linux. Затрагивает все основные ветки ядра с 4.14 (июль 2017)
по 6.18.21, а также стабильную ветку 6.19 вплоть до 6.19.11.
Только для образовательных целей и авторизованных исследований безопасности. НЕ запускайте на системах, которыми вы не владеете или на тестирование которых у вас нет явного письменного разрешения. Запуск на уязвимом хосте даёт любому непривилегированному локальному пользователю немедленный root-доступ. Авторы не несут ответственности за неправомерное использование.
Ядро Linux предоставляет доступ к внутриядерному криптографическому API из
пользовательского пространства начиная с ядра 3.2 через семейство сокетов
AF_ALG (<linux/if_alg.h>). Пользовательское пространство открывает сокет
SOCK_SEQPACKET, привязывает его к шаблону алгоритма (например,
"aead" / "authencesn(hmac(sha256),cbc(aes))") и отправляет данные для
шифрования или дешифрования.
В 2017 году была внедрена оптимизация производительности, которая позволяет алгоритмам AEAD шифровать или дешифровать данные на месте (in-place), когда ядро обнаруживает, что источник и назначение используют одни и те же нижележащие страницы. Это позволяет избежать избыточного копирования памяти при каждой операции.
Шаблон authencesn (который добавляет поддержку расширенных порядковых номеров
(ESN) к аутентифицированному шифрованию) содержит запись в черновую область
(scratch-write) при дешифровании: он записывает байты ESN в определённое
смещение в буфере данных операции до выполнения проверки аутентификации. Когда
исходные страницы операции были получены из кэша страниц (page cache)
обычного файла через splice(), и активна оптимизация in-place, эта черновая
запись попадает напрямую обратно в эти кэшированные страницы.
Поскольку кэш страниц ядра является общим отображением — любой процесс, открывающий тот же файл, видит те же физические страницы — непривилегированный пользователь может:
/usr/bin/su) с флагом O_RDONLY.AF_ALG.authencesn; черновая запись ESN повреждает
страницу по контролируемому смещению байтами, контролируемыми атакующим.Сканеры целостности вне хоста (AIDE, Tripwire, IMA/EVM), которые сравнивают контрольные суммы файлов на диске, полностью слепы к этой атаке. Запись исчезает после вытеснения из кэша страниц или перезагрузки, не оставляя криминалистических следов на диске.
Нацелившись на /usr/bin/su (двоичный файл с setuid root) и перезаписав
ветвление, которое контролирует проверку аутентификации PAM, атакующий получает
root-оболочку без пароля.
| Ветка | Первая уязвимая | Последняя уязвимая | Исправлено в |
|---|---|---|---|
| mainline | 4.14 | 6.18.21 | 6.18.22 |
| 6.19 stable | 6.19.0 | 6.19.11 | 6.19.12 |
| 7.0-rc | 7.0-rc1 | 7.0-rc6 | 7.0-rc7 |
Коммит оптимизации, который внёс ошибку, появился в цикле разработки 4.14
(июль 2017). Любое ядро, скомпилированное с CONFIG_CRYPTO_USER_API_AEAD=y
и CONFIG_CRYPTO_AUTHENC=y (оба параметра обычно включены по умолчанию)
в указанных выше диапазонах, уязвимо.
| Дистрибутив | Поставляемое ядро (прибл.) | Исправлено? |
|---|---|---|
| Debian 12 (Bookworm) | 6.1.x | Да (бэкпорт) |
| Debian 13 (Trixie) | 6.12.x / 6.14.x | Да (бэкпорт) |
| Ubuntu 24.04 LTS | 6.8.x | Да (USN-7xxx) |
| Ubuntu 24.10 | 6.11.x | Да |
| RHEL 9.x | 5.14.x (перебазировано) | Да (RHSA) |
| Alpine 3.20 | 6.6.x | Да (бэкпорт) |
| Arch Linux | rolling (≥ 6.18.22 сейчас) | Да |
| Kali Linux 2026.1 | 6.18.12 | Уязвимо |
| Kali Linux 2026.2+ | 6.18.22+ | Исправлено |
| Linux Mint 22 | 6.8.x (на базе Ubuntu) | Да (Ubuntu USN) |
Проверьте трекер безопасности вашего дистрибутива для получения точного статуса исправления.
os.splice добавлен в Python 3.10)/usr/bin/su,
доступен для чтения всем, так как является setuid)# Показать, что было бы записано, не затрагивая ядро (безопасно):
python3 copy_fail_exploit.py --dry-run
# Патч кэша страниц /usr/bin/su (требуется уязвимое ядро):
# ВНИМАНИЕ: требуется уязвимое ядро — используйте только на системах, которыми вы владеете
python3 copy_fail_exploit.py
# Патч и немедленное повышение привилегий до root:
python3 copy_fail_exploit.py --spawn-shell
# Использование пользовательского целевого двоичного файла и полезной нагрузки:
python3 copy_fail_exploit.py --target /usr/bin/sudo --payload-file ./custom_patch.bin
# Подробный вывод (печать каждой 4-байтовой записи):
python3 copy_fail_exploit.py --verbose --dry-run
По умолчанию --spawn-shell выключен. После патчинга скрипт выводит:
[+] Патч применён к кэшу страниц '/usr/bin/su' (диск не изменён).
Запустите `su` для повышения привилегий или перезапустите с --spawn-shell.
Для восстановления: echo 3 | sudo tee /proc/sys/vm/drop_caches
Вы должны явно согласиться на запуск оболочки с помощью --spawn-shell. Это
сделано намеренно: это заставляет вас понять, что сделал эксплойт, прежде чем
выполнять результат.
Настройка примитива.
Эксплойт открывает сокет AF_ALG и привязывает его к шаблону
authencesn(hmac(sha256),cbc(aes)) с фиктивным нулевым ключом. Затем он
настраивает размер тега аутентификации на 4 байта через ALG_SET_AEAD_AUTHSIZE.
accept() на управляющем сокете даёт операционный сокет, который может
отправлять отдельные запросы на дешифрование.
Инициирование записи в кэш страниц.
Для каждого 4-байтового фрагмента полезной нагрузки патча эксплойт вызывает
sendmsg() на операционном сокете с установленным флагом MSG_MORE, передавая
8 байт ассоциированных данных (AAD): 4 байта заполнителя, за которыми следуют
4 байта полезной нагрузки. MSG_MORE сообщает ядру удерживать операцию, пока
не поступят дополнительные данные. Затем он создаёт канал (pipe) и выполняет
два вызова splice() — file_fd → pipe → op_sock — передавая страницы из
кэша страниц самого файла в качестве входных данных для операции дешифрования.
Когда наконец вызывается recv(), ядро выполняет дешифрование authencesn.
Срабатывает оптимизация in-place (источник и назначение — одни и те же страницы),
и черновая запись ESN копирует наши байты полезной нагрузки в страницу кэша по
целевому смещению. recv() возвращает EBADMSG, потому что тег аутентификации
не может быть проверен — это ожидаемо и безвредно. Запись уже произошла.
Патчинг двоичного файла.
Встроенная полезная нагрузка (взятая дословно из PoC Theori) перезаписывает
инструкцию ветвления в /usr/bin/su из стандартной сборки util-linux,
превращая условный переход, который обеспечивает аутентификацию PAM, в
безусловный переход (fall-through). После патчинга запуск su без пароля
успешен и даёт root-оболочку. Двоичный файл на диске не тронут; сброс записей
кэша страниц (echo 3 > /proc/sys/vm/drop_caches) мгновенно отменяет изменение.