
Ein Bericht über Dirty Frag, eine Linux Local Privilege Escalation (LPE) Schwachstellenkette, die es einem unprivilegierten Benutzer ermöglicht, root Zugriff zu erlangen
Labor zur Exploit-Reproduktion und -Erkennung für eine lokale Privilege-Escalation-Kette im Linux-Kernel.
Status: VERIFIZIERT. Ich habe die Reproduktion, die fileless-Verifikation und die Erkennung auf Syscall-Ebene im Labor abgeschlossen (Kernel 6.18.9+kali-amd64). Dieses Dokument ist ein Laborprotokoll. Jede hier gemachte Aussage wurde während des Reproduktionslaufs beobachtet. Die Screenshots und Artefakte sind echte Aufnahmen aus der VM.
Dirty Frag kombiniert zwei deterministische Logikfehler im Linux-Kernel. Diese Fehler erlauben es einem unprivilegierten lokalen Benutzer, den Page Cache von schreibgeschützten Dateien (z. B. /usr/bin/su) zu überschreiben und eine Root-Shell zu erhalten:
| Variante | CVE | Sink | Trigger-Pfad | Benötigt unprivilegiertes userns |
|---|---|---|---|---|
| xfrm‑ESP Page‑Cache Write | CVE‑2026‑43284 | crypto_authenc_esn_decrypt() in esp_input() | socket(AF_INET) mit UDP‑encap, dann xfrm_input() | Ja (CAP_NET_ADMIN) |
| RxRPC Page‑Cache Write | CVE‑2026‑43500 | rxkad_verify_packet_1() (pcbc(fcrypt)) | socket(AF_RXRPC) | Nein |
Beide Varianten verwenden dasselbe Grundmuster wie Dirty Pipe und Copy Fail. Der splice(2)-Syscall platziert eine Referenz auf eine Page-Cache-Seite einer Datei im frag-Slot eines sender-seitigen sk_buff. Der Angreifer kann diese Datei nur lesen. Empfangsseitiger Kernel-Code führt dann einen In-Place-Crypto-STORE auf diesem frag aus. Dadurch wird der Page Cache im RAM verändert. Es findet kein Platten-Schreibvorgang statt, sodass File-Integrity-Monitoring (AIDE, Tripwire) dies nicht erkennen kann. Der Angriff ist deterministisch. Er hat kein Race-Fenster und keinen Kernel-Panic bei Fehlschlag.
cac2661c53f3 (2017‑01) bis f4c50a4034e6 (gepatcht 2026‑05‑05)2dc334f1a63a (2023‑06) bis aa54b1d27fe0 (gepatcht 2026‑05‑10)CVE-2026-43284 = 8.8 (Hoch), CVE-2026-43500 = 7.8 (Hoch)Dirty Frag ist eine fileless LPE. Es korrumpiert den In-Memory-Page-Cache, nicht die Datei auf der Platte. Herkömmliches File-Integrity-Monitoring kann das nicht erkennen. Die Erkennung muss auf der Syscall-Ebene erfolgen. Die Kette verwendet diese Syscall-Primitive: socket(AF_ALG)/socket(AF_RXRPC), splice und unshare(CLONE_NEWUSER|CLONE_NEWNET). Der ESP-Pfad erstellt außerdem AF_INET-UDP- und Netlink-Sockets. Diese Ebene steht im Fokus des Detection Engineering in diesem Repository.
Beide Varianten verwenden denselben Sink: In-Place-Crypto, das Bytes auf eine Page-Cache-Seite STOREd, die der Angreifer mit splice(2) platziert.
UDP_ENCAP_ESPINUDP.vmsplice in eine Pipe, dann 16 Bytes von /usr/bin/su am Ziel-Datei-Offset mit splice.splice schiebt die Pipe in das Send-Socket. splice_to_socket() setzt MSG_SPLICE_PAGES. Dadurch wird die Page-Cache-Seite von /usr/bin/su direkt in skb->frags[0] platziert.xfrm4_udp_encap_rcv, dann xfrm_input, dann esp_input(). Der verwundbare skip_cow-Zweig (!skb_cloned() && !skb_has_frag_list()) umgeht skb_cow_data(). Er führt eine In-Place-AEAD-Entschlüsselung mit der Page-Cache-Seite als Quelle und Ziel durch.crypto_authenc_esn_decrypt() gibt einen STORE der höherwertigen 32 Bits der ESN aus. Dieser Wert ist replay_esn->seq_hi. Der Angreifer wählt diesen Wert bei der SA-Registrierung mit dem XFRMA_REPLAY_ESN_VAL-Netlink-Attribut.Der Angreifer kontrolliert sowohl die Position (splice-Offset) als auch den Wert (4 Bytes). Die Authentifizierungsprüfung läuft nach dem Store, sodass die Crypto-Ebene den Schreibvorgang nie kennzeichnet. Diese Variante erfordert CAP_NET_ADMIN und verwendet unshare(CLONE_NEWUSER|CLONE_NEWNET).
rxkad_verify_packet_1() führt eine Ein-Block-pcbc(fcrypt)-Entschlüsselung direkt auf dem splice-pinned-skb-frag durch. Es kopiert die Daten nicht zuerst. Der Angreifer wählt einen Session-Key (add_key("rxrpc", …)), sodass decrypt(ciphertext) gleich desired_plaintext ist. Dies erzeugt einen 8-Byte-STORE. Diese Variante zielt auf /etc/passwd. Sie benötigt kein User-Namespace. Sie erfordert das rxrpc.ko-Modul (standardmäßig auf Ubuntu geladen).
Der öffentliche PoC zielt auf /usr/bin/su. Er schreibt 48 ESP-Stores von je 4 Bytes (192 Bytes bei Datei-Offset 0). Er ersetzt die ersten Page-Cache-Bytes durch ein statisches Root-Shell-ELF. Der ELF-Einstiegspunkt führt setgid(0); setuid(0); setgroups(0,NULL); execve("/bin/sh", …) aus. Ein einzelner execve("/usr/bin/su") führt dann zu einer Root-Shell.
Der ESP-Patch (Mainline f4c50a4034e6) markiert Page-Frags, die über splice() ankommen, mit dem SKBFL_SHARED_FRAG-Flag. Der skip_cow-Zweig in esp_input() prüft jetzt ebenfalls dieses Flag. Shared-Frag-skbs durchlaufen skb_cow_data() vor der In-Place-AEAD-Entschlüsselung.
Der RxRPC-Patch (Mainline aa54b1d27fe0) fügt eine skb->data_len-Prüfung neben der bestehenden skb_cloned()-Prüfung hinzu. Der Kernel kopiert ein nicht-lineares skb mit gepagten Daten vor der In-Place-pcbc(fcrypt)-Entschlüsselung.
| Komponente | Details |
|---|---|
| Hypervisor | VirtualBox |
| Ziel-VM | Kali Linux 2026.1 (Snapshot auf einen verwundbaren Zustand zurückgesetzt) |
| Kernel | 6.18.9+kali‑amd64 (älter als die Mai-2026-Fixes) |
| Exploit-PoC | V4bel/dirtyfrag (einzelne C-Datei) |
| Erkennung | auditd (Regeln in detection/dirtyfrag.rules) |
Screenshot des VirtualBox-Laboraufbaus:

.
├── README.md # dieses Laborprotokoll
├── detection/
│ ├── dirtyfrag.rules # auditd-Syscall-Erkennungsregeln
│ ├── ausearch_dirtyfrag_observed.txt # echte Exploit-Erkennungsausgabe
│ ├── sigma/
│ │ └── dirty_frag_exploit.yml # Sigma-Regel für SIEM-Erkennung
│ └── yara/
│ └── dirty_frag_exploit.yar # YARA-Regel für PoC-Code auf Platte/Arbeitsspeicher
├── mitigation/
│ └── dirtyfrag_mitigation.sh # Modul-Blacklist + Page-Cache-Flush
├── poc/
│ └── check_vulnerable.py # nicht-destruktiver Pre-Flight-Checker
├── reports/
│ └── incident-dirtyfrag.md # Incident-Response-Playbook
└── screenshots/ # echte Aufnahmen aus der Labor-VM