
Blockieren der DirtyFrag Linux LPE-Kette (CVE-2026-43284 / CVE-2026-43500) zur Laufzeit mit einer Cilium Tetragon TracingPolicy
Blockieren der DirtyFrag Linux-Privilegieneskalationskette (CVE-2026-43284 / CVE-2026-43500) zur Laufzeit mit einer Cilium Tetragon TracingPolicy. Die Policy sendet SIGKILL an den öffentlichen Proof-of-Concept bei seinem Socket-Setup-Schritt, bevor er den Page-Cache-Schreibvorgang erreicht, der ihm Root-Rechte geben würde.
Was das hier ist. Eine Labor-Dokumentation. Ich habe Tetragon zum ersten Mal eingerichtet und wollte sehen, ob es tatsächlich eine echte, aktuelle Kernel-LPE stoppen kann. Konnte es. Dies dokumentiert genau, was ich ausgeführt habe, was ausgelöst wurde und, genauso wichtig, die Grenzen dessen, was es beweist. Es ist kein Ersatz für Patching.
Dateien: Diese README (in sich geschlossen, Beweise inline) · block-dirtyfrag.yaml (die Policy)
| Exploit | DirtyFrag - öffentlicher PoC: V4bel/dirtyfrag |
| CVEs | CVE-2026-43284 (xfrm-ESP-Page-Cache-Schreibzugriff), CVE-2026-43500 (RxRPC-Page-Cache-Schreibzugriff) |
| Host | Ubuntu 24.04.4 LTS, Tetragon v1.7.0 (Standalone, systemd) |
Baseline - keine Policy, Kernel 6.8.0-88 (anfällig) | PoC → uid=0(root) |
Mit Policy - Kernel 6.8.0-88 | PoC SIGKILLed bei socket(AF_RXRPC); Benutzer bleibt uid=1000 |
Gepatcher Kernel 6.8.0-134 | PoC schlägt von selbst fehl (rc=4); Socket-Hook feuert trotzdem, Erkennung, nicht Entschärfung (Anmerkung) |
| Art der Kontrolle | Kompensierende Kontrolle / virtueller Patch, keine Kernel-Fix |
DirtyFrag ist eine lokale Privilegieneskalationskette, die aus zwei unabhängigen Page-Cache-Schreibprimitive im Linux-Kernel besteht: eine im xfrm/ESP (IPsec) In-Place-Entschlüsselungspfad (CVE-2026-43284) und eine im RxRPC-Pfad (CVE-2026-43500). Jede erlaubt es einem unprivilegierten lokalen Benutzer, vom Angreifer kontrollierte Bytes in schreibgeschützte Page-Cache-Seiten zu schreiben, z. B. in das gecachte Image einer setuid-root-Binärdatei wie /bin/su – und von dort Root zu erlangen. Der Schreibvorgang landet nur im Arbeitsspeicher; die Datei auf der Festplatte wird nie verändert, daher sieht die Dateiintegritätsüberwachung nichts. Es handelt sich um dieselbe Fehlerklasse wie Dirty Pipe und Copy Fail. Die beiden CVEs werden bewusst verkettet: Wenn ein Pfad in einer bestimmten Umgebung nicht verfügbar ist, funktioniert der andere trotzdem.
Auf diesem Host sind unprivilegierte Benutzernamensräume durch AppArmor eingeschränkt (kernel.apparmor_restrict_unprivileged_userns = 1), was die ESP-Hälfte der Kette blockiert. Das hinterlässt den RxRPC-Pfad, der einen AF_RXRPC-Socket (Adressfamilie 33) öffnet – und genau diesen Schritt tötet diese Policy.
Die eigentliche Lösung ist ein gepatchter Kernel. Alles hier ist ein Provisorium für einen Host, den Sie noch nicht patchen können. Ubuntu hat DirtyFrag-Fixes einige Zeit vor diesem Test ausgeliefert, daher handelt es sich um ein bekanntes N-Day, nicht um einen aktuellen 0-Day – der Punkt ist zu zeigen, was eine Laufzeitkontrolle auf einem Host tun kann, der aus irgendeinem Grund immer noch einen anfälligen Kernel ausführt.
Vollständige Policy: block-dirtyfrag.yaml. Sie installiert zwei Kproben.
Hook 1 - Grooming-Sockets (sys_socket). Die tragende Kontrolle. Der RxRPC-Pfad des Exploits muss bei jedem Lauf socket(AF_RXRPC, …) aufrufen, unabhängig davon, ob ein Kernelmodul bereits geladen ist. Die Policy prüft auf die Adressfamilie:
AF_RXRPC) → Sigkill. Auf jedem Host, der kein AFS-Client ist, öffnet praktisch nichts Legitimes einen AF_RXRPC-Socket, daher ist ein pauschaler Kill hier sicher und mit hoher Sicherheit.AF_ALG) → Post (nur Audit, kein Kill). AF_ALG ist die Userspace-Kernel-Krypto-API und hat legitime Benutzer (cryptsetup, libkcapi-Tooling, einige FIPS-Workflows). Ein Kill allein aufgrund der Familie würde Fehlalarme verursachen, daher protokolliert dieser Abschnitt nur. Der Weg zur Durchsetzung: Eine Weile auditen, eine NotIn-Allowlist aus den tatsächlich beobachteten Binärdateien erstellen, dann erwägen, auf Sigkill hochzustufen.Hook 2 - Anfälliges Modul-Autoload (security_kernel_module_request). Verteidigung in der Tiefe. Wird ausgelöst, wenn der Kernel aufgefordert wird, eine anfällige Modulfamilie automatisch zu laden (esp4, esp6, rxrpc, die Socket-Aliase net-pf-33/net-pf-38, die Crypto-Templates pcbc/fcrypt). Einschränkung: Es wird nur ausgelöst, wenn das Modul noch nicht residiert – nach dem ersten Exploit-Lauf in einer Boot-Sitzung sind diese Module geladen und dieser Hook wird stumm. Es ist eine Kaltstart-Schicht, nicht die primäre Kontrolle.
Zusammen: Hook 1 erwischt den Exploit, egal ob Module warm oder kalt sind; Hook 2 fügt auf einem kalten Host eine frühere, spezifischere Auslösung hinzu.
6.8.0-88-generic, der anfällig ist (die Baseline erreicht Root). Die Box hat auch 6.8.0-134-generic installiert – den gepatchten Kernel – und dies wurde direkt bestätigt: Ein Neustart in -134 führt dazu, dass der PoC von selbst fehlschlägt (rc=4, kein Root), mit oder ohne Policy (siehe Anmerkung unten). Um die Entschärfungsdemo zu reproduzieren, booten Sie 6.8.0-88 über GRUB (es ist noch installiert) – auf einem gepatchten Kernel gibt es nichts zu entschärfen.AF_ALG-Abschnitt.lockdown,capability,landlock,yama,apparmor – kein bpf). Daher erfolgt die Durchsetzung mittels Sigkill von der Kprobe, nicht durch ein In-Kernel-LSM-Verweigern. Der Kill erfolgt beim socket()-Syscall – der Schreibprimitive – und beendet den Prozess bei einem zwingend frühen Schritt, anstatt die "Schwachstelle selbst zu blockieren".Schritte 1–5 stammen alle aus derselben 6.8.0-88-Bootsitzung (der anfällige Kernel).
1. Umgebung - Ubuntu 24.04.4, Kernel 6.8.0-88-generic, Tetragon v1.7.0 aktiv unter systemd, unprivilegierte Userns eingeschränkt.
$ uname -r
6.8.0-88-generic
$ tetra version
CLI version: v1.7.0
$ systemctl is-active tetragon
active
2. Vorbedingungen (Policy AUS) - sauberer Ausgangspunkt: keine anfälligen Module geladen, kein xfrm-Status, keine Policy geladen.
$ lsmod | grep -E 'esp4|esp6|rxrpc' || echo "(keines geladen)"
(keines geladen)
$ sudo ip xfrm state # (leer)
$ sudo tetra tp list
ID NAME STATE FILTERID NAMESPACE SENSORS KERNELMEMORY MODE NPOST NENFORCE NMONITOR
3. Baseline (Policy AUS) - der Exploit funktioniert. Das beweist, dass der Kernel tatsächlich anfällig ist; die gesamte Dokumentation beruht darauf.
$ ./exp ; id
uid=0(root) gid=0(root) groups=0(root)
4. Policy laden.
$ sudo tetra tp add /etc/tetragon/tetragon.tp.d/block-dirtyfrag.yaml
tracing policy "…/block-dirtyfrag.yaml" added
5. Erzwungen (Policy AN) - der Kill. Der Exploit wird durch Signal beim socket()-Aufruf beendet und erreicht nie su:
🚀 process /home/…/dirtyfrag/exp
❓ syscall /home/…/dirtyfrag/exp __x64_sys_socket
Kernel:
0x0: __x64_sys_socket+0x5
0x0: do_syscall_64+0x7f
0x0: entry_SYSCALL_64_after_hwframe+0x78
💥 exit /home/…/dirtyfrag/exp SIGKILL
Das strukturierte Ereignis bestätigt sowohl den Treffer als auch den Kill – ein process_kprobe auf den Socket-Syscall, dann ein process_exit durch Signal für dieselbe PID:
// process_kprobe — der AF_RXRPC-Treffer
{ "process_kprobe": {
"process": { "pid": 24083, "uid": 1000, "binary": ".../dirtyfrag/exp" },
"function_name": "__x64_sys_socket",
"args": [ { "int_arg": 33, "label": "family" } ],
"policy_name": "block-dirtyfrag",
"action": "KPROBE_ACTION_POST"
} }
// process_exit — gleiche PID, durch Signal getötet
{ "process_exit": {
"process": { "pid": 24083, "binary": ".../dirtyfrag/exp" },
"signal": "SIGKILL"
} }
Die action der Kprobe lautet KPROBE_ACTION_POST, weil die Post-Aktion das sichtbare Ereignis ausgibt; die Sigkill-Aktion erzeugt den separaten SIGKILL-Exit. Die beiden Ereignisse zusammen sind der Beweis, der Treffer und der Kill.
Hinweis: Die rohe
07-Erfassung enthält auch einemessage-Zeichenkette aus einer früheren Revision der Policy (bevor derAF_ALG-Abschnitt auf Nur-Audit aufgeteilt wurde). Der Trefferfamily: 33und der daraus resultierendeSIGKILLsind revisionsübergreifend identisch; nur dieser Text unterscheidet sich.
Nach dem Lauf mit dem anfälligen Kernel wurde der Host in 6.8.0-134-generic (Ubuntus gepatchter Kernel) neu gestartet und der PoC erneut ausgeführt:
$ ./exp # Policy AUS
dirtyfrag: failed (rc=4) # Exploit schlägt von selbst fehl — kein Root
$ ./exp # Policy AN
Killed # SIGKILL bei socket(AF_RXRPC)
Um genau zu sein, was dies zeigt:
rc=4, kein Root), weil der Kernel gepatcht ist. Es gibt nichts, was die Policy verhindern könnte. Das Vorher/Nachher, das den Entschärfungsanspruch trägt, existiert nur auf dem anfälligen -88-Kernel.socket(AF_RXRPC) auf, also sendet Tetragon immer noch SIGKILL und zeigt den Versuch im Log an – auf einem gepatchten Kernel genauso wie auf einem ungepatchten. Das hat einen Wert als Erkennung eines Versuchs und als Verteidigung in der Tiefe, ist aber nicht dasselbe wie das Stoppen eines funktionierenden Exploits.AF_RXRPC legitim und ein pauschaler Kill würde ihn zerstören. Pro Knoten überprüfen.AF_ALG-Abschnitt ist absichtlich nur Audit. Eine Variante, die nur den AF_ALG-Pfad mit bereits warmen Modulen verwendet, würde protokolliert, nicht getötet, bis Sie diesen Abschnitt nach Erstellung einer Allowlist auf Durchsetzung hochstufen.AF_RXRPC-Socket vor der Schreibprimitive geöffnet wird. Diese Reihenfolge macht einen frühen Kill wirksam; es ist keine Garantie für jeden möglichen Exploit.Setup: Tetragon v1.7.0 Standalone, gestartet über systemctl; Policies geladen mit tetra tracingpolicy add.