
Kopierfehler: 732 Bytes zu Root auf jeder großen Linux-Distribution.
732 Bytes. Jede Distribution. Root.
Ein geradliniger Logikfehler in der kryptografischen Vorlage
authencesndes Linux-Kernels ermöglicht einem nicht privilegierten lokalen Benutzer einen präzisen, kontrollierten 4-Byte-Schreibzugriff in den Page Cache einer beliebigen lesbaren Datei — einschließlich setuid-Binaries. Keine Race Conditions. Keine Wiederholungen. Keine Neukompilierung. Root auf jeder großen Linux-Distribution, die seit 2017 ausgeliefert wurde.
📄 Technischer Bericht · 🔗 Kernel-Patch · 🛡️ CVSS: Kritisch
| Distribution | Kernel-Version |
|---|---|
| Ubuntu 24.04 LTS | 6.17.0-1007-aws |
| Amazon Linux 2023 | 6.18.8-9.213.amzn2023 |
| RHEL 10.1 | 6.12.0-124.45.1.el10_1 |
| SUSE 16 | 6.12.0-160000.9-default |
Alle vier wurden mit dem identischen 732-Byte-Python-Skript ohne Änderungen kompromittiert.
AF_ALG stellt das kryptografische Subsystem des Kernels nicht privilegiertem Userspace zur Verfügung. splice() überträgt Dateidaten per Referenz in eine Pipe — Page-Cache-Seiten werden direkt durchgereicht, ohne Kopie. Wenn ein Benutzer eine Datei in einen AF_ALG-AEAD-Socket spliced, enthält die Eingabe-Scatterlist des Sockets Live-Referenzen auf die gecachten Seiten der Datei im Kernel.
In algif_aead.c kopierte die In-Place-Optimierung von 2017 AAD und Chiffretext aus der TX-Scatterlist in den RX-Puffer, verknüpfte die Authentifizierungs-Tag-Seiten jedoch per Referenz mit sg_chain() und setzte dann req->src = req->dst:
Eingabe-SGL: [ AAD | CT | Tag ]
^
└─ sg_chain() → zeigt weiterhin auf Page-Cache-Seiten
Ausgabe-SGL: [ AAD | CT ] ──→ [ Tag (Page-Cache-Seiten) ]
(RX-Puffer) (aus TX-SGL verknüpft)
req->src ──┐
├──→ gleiche kombinierte Scatterlist
req->dst ──┘
Page-Cache-Seiten aus splice() befanden sich nun in einer beschreibbaren Ziel-Scatterlist, getrennt vom legitimen Schreibbereich nur durch eine Offset-Grenze. Nichts in der API erzwingt, dass Algorithmen innerhalb der Grenzen bleiben.
authencesns Out-of-Bounds-Scratch-Schreibzugriffauthencesn ist ein AEAD-Wrapper, der von IPsec für die Unterstützung von 64-Bit-Erweiterten Sequenznummern (ESN) verwendet wird. Um ESN-Bytes für die HMAC-Berechnung neu anzuordnen, verwendet es den Zielpuffer des Aufrufers als Scratch-Speicher — einschließlich eines Schreibzugriffs bei Offset assoclen + cryptlen, der jenseits der Authentifizierungs-Tag-Grenze liegt:
scatterwalk_map_and_copy(tmp, dst, 0, 8, 0); // AAD[0..7] lesen
scatterwalk_map_and_copy(tmp, dst, 4, 4, 1); // dst[4..7] überschreiben
scatterwalk_map_and_copy(tmp + 1, dst, assoclen + cryptlen, 4, 1); // ← schreibt über das Tag hinaus
Der dritte Aufruf schreibt 4 Bytes (seqno_lo) bei dst[assoclen + cryptlen]. Im In-Place-AF_ALG-Pfad überquert der Scatterwalk die Grenze vom RX-Puffer in die verknüpften Page-Cache-Tag-Seiten. Der Kernel mappt die Page-Cache-Seite über kmap_local_page und schreibt direkt in die gecachte Kopie der Zieldatei.
Der HMAC schlägt dann fehl (der Chiffretext ist fabriziert), recvmsg() gibt einen Fehler zurück — aber der 4-Byte-Schreibzugriff bleibt dauerhaft bestehen.
Keine einzelne Änderung war für sich genommen falsch. Die Schwachstelle liegt an der Schnittstelle aller drei.
Das Standardziel ist /usr/bin/su, eine setuid-root-Binary, die auf allen getesteten Distributionen vorhanden ist.
Schritt 1 — Socket-Einrichtung
AF_ALG-Socket öffnen, an authencesn(hmac(sha256),cbc(aes)) binden
Schlüssel setzen. Request-Socket akzeptieren. (Keine Privilegien erforderlich.)
Schritt 2 — Schreibschleife (einmal pro 4-Byte-Shellcode-Chunk)
sendmsg() → AAD-Bytes [4:8] tragen die 4 zu schreibenden Bytes (seqno_lo)
splice() → Page-Cache-Seiten der Zieldatei in den AF_ALG-Socket
recv() → löst decrypt aus → authencesn schreibt seqno_lo in den Page Cache
(recvmsg gibt einen Fehler zurück; der Schreibzugriff bleibt bestehen)
Schritt 3 — Ausführung
execve("/usr/bin/su")
Kernel lädt die Binary aus dem (nun beschädigten) Page Cache
Setuid-root-Binary führt injizierten Shellcode aus → UID 0
a = socket.socket(38, 5, 0) # AF_ALG, SOCK_SEQPACKET
a.bind(("aead", "authencesn(hmac(sha256),cbc(aes))"))
# ... Schlüssel setzen, Request-Socket u akzeptieren ...
u.sendmsg([b"A"*4 + payload_chunk], [cmsg_headers], MSG_MORE)
os.splice(target_fd, pipe_wr, offset)
os.splice(pipe_rd, alg_fd, offset)
u.recv(...) # löst Page-Cache-Schreibzugriff aus
Aktualisieren Sie auf einen Kernel mit Patch a664bf3d603d. Der Fix stellt algif_aead.c auf Out-of-Place-Betrieb zurück: req->src zeigt auf die TX-SGL; req->dst zeigt auf den RX-Puffer. Page-Cache-Seiten aus splice() bleiben nur lesbar. Der sg_chain()-Mechanismus, der sie in die beschreibbare Ziel-Scatterlist verknüpfte, wird entfernt.
// Vorher (verwundbar): src und dst teilen sich dieselbe Scatterlist
aead_request_set_crypt(&areq->cra_u.aead_req, rsgl_src, rsgl_src, used, ctx->iv);
// Nachher (behoben): src ist TX-SGL, dst ist RX-Puffer — vollständig getrennt
aead_request_set_crypt(&areq->cra_u.aead_req, tsgl_src, rsgl_dst, used, ctx->iv);
Deaktivieren Sie das Kernel-Modul algif_aead:
echo "install algif_aead /bin/false" > /etc/modprobe.d/disable-algif-aead.conf
rmmod algif_aead 2>/dev/null
Oder blockieren Sie die Erstellung von AF_ALG-Sockets über eine seccomp-Richtlinie in Ihren Workload-Profilen.
Hinweis für Container-Umgebungen: Da der Page Cache über den Host hinweg geteilt wird, überschreitet diese Schwachstelle Container-Grenzen. Wenden Sie Abschwächungen auf Knotenebene an, nicht nur pro Pod. Vollständige Details zum Kubernetes-Escape finden Sie in Teil 2.
Der Theori-Forscher Taeyang Lee identifizierte durch frühere kernelCTF-Arbeiten, dass AF_ALG + splice() einen Pfad schafft, über den nicht privilegierter Userspace Page-Cache-Seiten direkt in das kryptografische Subsystem einspeisen kann — und dass die Herkunft von Scatterlist-Seiten eine unzureichend erforschte Schwachstellenklasse darstellt.
Das Forschungsteam nutzte Xint Code, um diese Erkenntnis auf das gesamte crypto/-Subsystem mit folgendem Operator-Prompt zu skalieren:
"Dies ist das Linux-crypto/-Subsystem. Bitte untersuchen Sie alle Codepfade, die von Userspace-Syscalls aus erreichbar sind. Beachten Sie eine Schlüsselbeobachtung: splice() kann Page-Cache-Referenzen von nur lesbaren Dateien (einschließlich setuid-Binaries) an kryptografische TX-Scatterlists liefern."
Nach etwa einer Stunde automatisierter Analyse war Copy Fail das Ergebnis mit der höchsten Schwere. Weitere während desselben Scans entdeckte Schwachstellen befinden sich weiterhin in koordinierter Offenlegung.
Teil 2: Vom Pod zum Host — wie Copy Fail jede große Cloud-Kubernetes-Plattform verlässt. Bald verfügbar.
| Eigenschaft | Detail |
|---|
| Deterministisch | Geradliniger Logikfehler — keine Race Conditions, keine Timing-Fenster, keine Wiederholungen |
| Portabel | Gleiches Skript, gleiche Bytes, funktioniert auf allen getesteten Distributionen und Architekturen |
| Winzig | 732-Byte-Python-Skript, das nur die Standardbibliothek verwendet (os, socket, zlib). Erfordert Python 3.10+ für os.splice |
| Verdeckt | Die beschädigte Seite wird nie als „dirty" markiert. On-Disk-Prüfsummen bleiben unverändert; nur der In-Memory-Page-Cache wird modifiziert |
| Container-übergreifend | Der Page Cache wird systemweit über Container-Grenzen hinweg geteilt — dies ist auch ein Kubernetes-Node-Escape-Primitiv (siehe Teil 2) |
| Variable | Kontrolliert über |
|---|
| Zieldatei | Jede Datei, die vom aktuellen Benutzer lesbar ist |
| Schreib-Offset | assoclen, splice-Offset und splice-Länge |
| Schreibwert | Bytes 4–7 des in sendmsg() gelieferten AAD (seqno_lo) |
| Jahr | Ereignis |
|---|
| 2011 | authencesn zum Kernel hinzugefügt (a5079d084f8b) für IPsec-ESN-Unterstützung. Der Scratch-Schreibzugriff existierte, war aber harmlos — nur die interne xfrm-Schicht rief ihn auf, und AAD befand sich in einer separaten Scatterlist. |
| 2015 | AF_ALG erhält AEAD-Unterstützung. authencesn wird auf die neue AEAD-Schnittstelle umgestellt (104880a6b470), wodurch der assoclen + cryptlen-Schreib-Offset eingeführt wird. Noch out-of-place: Page-Cache-Seiten befanden sich in src (nur lesbar). Noch nicht ausnutzbar. |
| 2017 | In-Place-Optimierung zu algif_aead.c hinzugefügt (72548b093ee3). req->src = req->dst. Page-Cache-Tag-Seiten in die beschreibbare Ziel-Scatterlist verknüpft. Schwachstelle entstanden. |
| 2026-03-23 | An das Linux-Kernel-Sicherheitsteam gemeldet. |
| 2026-04-01 | Patch in den Mainline-Kernel übernommen. |
| 2026-04-22 | CVE-2026-31431 zugewiesen. |
| 2026-04-29 | Öffentliche Offenlegung. |
| Datum | Ereignis |
|---|
| 2026-03-23 | Schwachstelle an das Linux-Kernel-Sicherheitsteam gemeldet |
| 2026-03-24 | Erste Bestätigung erhalten |
| 2026-03-25 | Patches vorgeschlagen und überprüft |
| 2026-04-01 | Patches in den Mainline-Kernel übernommen |
| 2026-04-22 | CVE-2026-31431 zugewiesen |
| 2026-04-29 | Öffentliche Offenlegung |