
Proof-of-Concept, das einen Container-Ausbruch auf Amazon EKS demonstriert, indem es Dirty Frag (CVE-2026-43284) Kernel-Page-Cache-Korruption über gemeinsame Image-Layer und privilegierte DaemonSets ausnutzt.
Ein Proof-of-Concept, der demonstriert, wie ein standardmäßiger, unprivilegierter Kubernetes-Pod auf Amazon EKS Codeausführung auf Knotenebene erreichen kann, indem die Dirty-Frag-Linux-Kernel-Page-Cache-Korruptions-Schwachstelle über gemeinsame Container-Image-Layer ausgenutzt wird.
Die zentrale Angriffsprimitive lautet: Jedes privilegierte DaemonSet, das Image-Layer mit einem angreiferkontrollierten Container teilt, kann für einen Container-Escape bewaffnet werden. Dieses PoC verwendet kube-proxy als ein konkretes Beispiel, aber die Technik lässt sich auf jede privilegierte Workload im Cluster verallgemeinern.
Validierung auf Amazon EKS (Kernel 6.12.80) — ein unprivilegierter Pod schreibt [*] success über das privilegierte kube-proxy-DaemonSet in das Host-Dateisystem:

Haftungsausschluss: Dieses Repository wird ausschließlich zu Bildungs- und Verteidigungszwecken veröffentlicht. Verwenden Sie es ausschließlich auf Systemen, die Sie besitzen oder für deren Test Sie ausdrücklich autorisiert sind.
Dirty Frag (CVE-2026-43284) ist eine Linux-Kernel-Page-Cache-Korruptions-Schwachstelle im xfrm/ESP-Empfangspfad. Im betroffenen Pfad kann esp_input() skb_cow_data() für ein nicht-lineares skb ohne frag_list überspringen, wodurch crypto_authenc_esn_decrypt() 4 Bytes angreiferkontrollierter Daten in eine Page-Cache-Seite speichern kann, die über splice() erreicht wird.
Die Datei auf der Festplatte wird nicht verändert. Die korrupten Bytes befinden sich im Kernel-Page-Cache und werden von späteren Lesern derselben gecachten Dateiseite beobachtet.
Vollständige Details zur ursprünglichen Schwachstelle finden Sie unter V4bel/dirtyfrag.
Der Angriff nutzt drei Eigenschaften aus, die in Kubernetes-Clustern häufig gemeinsam auftreten:
privileged: true, hostNetwork: true, umfangreiche Capabilities usw.), die regelmäßig Binärdateien aus ihrem Image ausführen.Wenn diese Bedingungen zusammentreffen, kann ein unprivilegierter Pod eine Binärdatei in einem gemeinsamen Image-Layer korrumpieren, und ein privilegiertes DaemonSet auf demselben Knoten führt die korrumpierte Binärdatei unwissentlich mit seinen erhöhten Privilegien aus — was eine vollständige Codeausführung auf Knotenebene erreicht.
Das Angriffsziel ist NICHT auf kube-proxy beschränkt. Jedes privilegierte DaemonSet (Monitoring-Agenten, CNI-Plugins, Log-Collector, Sicherheitsagenten usw.), dessen Container-Image Layer mit einem angreiferkontrollierten Image teilt, ist ein geeignetes Ziel.
Dieses Projekt ist vom Kubernetes-Ausbeutungsmodell inspiriert, das im Copy Fail Kubernetes PoC dokumentiert ist, verwendet jedoch eine andere Kernel-Primitive.
Die Angriffskette hat drei Phasen: Page-Cache-Korruption, containerübergreifende Ausbreitung und privilegierte Ausführung.
Die PoC-Binärdatei führt die folgende Sequenz aus einem unprivilegierten Container aus:
unshare(CLONE_NEWUSER | CLONE_NEWNET) in neue User- und Netzwerk-Namespaces.splice() und konstruierte ESP-Eingaben, um den verwundbaren Kernel-Pfad auszulösen.Für die Zieldatei ist keine Schreibberechtigung erforderlich. Die Datei auf der Festplatte bleibt unverändert — nur der In-Memory-Page-Cache wird korrumpiert.
Container-Runtimes bedienen Lesevorgänge aus Overlay-Lower-Layern über den Kernel-Page-Cache. Wenn der PoC-Container und kube-proxy dieselbe Lower-Layer-Datei teilen, beobachten beide dieselben gecachten Seiten.
Das EKS-Image in diesem Repository basiert auf:
public.ecr.aws/eks-distro-build-tooling/eks-distro-minimal-base-iptables:2026-03-11-1773190710.2023
Diese Basis wurde gewählt, um mit der EKS-kube-proxy-Userspace-Toolchain-Schicht übereinzustimmen, die in der validierten Umgebung verwendet wird.
Wenn kube-proxy als Nächstes eine gepatchte iptables-Familien-Binärdatei ausführt, lädt der Kernel die korrumpierten gecachten Seiten. Die PoC-Payload mountet das Host-Root-Gerät und schreibt eine Markierungsdatei nach /root/res.
Der erwartete Markierungsinhalt ist:
[*] success
┌──────────────────────────────┐ ┌────────────────────────┐ ┌──────────────────────────┐
│ PoC-Pod │ │ Kernel-Page-Cache │ │ kube-proxy-DaemonSet │
│ unprivilegierter Container │ │ │ │ privilegierter Container│
│ │ │ │ │ │
│ 1. unshare user+net ns │ │ │ │ │
│ 2. xfrm-SAs installieren │ │ │ │ │
│ 3. Ziel-Binärdatei splices │────▶│ Shared-Layer-Binärdatei│────▶│ führt gepatchte Binär- │
│ über ESP-Pfad │ │ Page-Cache gepatcht │ │ datei aus; Payload läuft│
│ │ │ │ │ mit Privilegien auf │
│ │ │ │ │ Knotenebene │
└──────────────────────────────┘ └────────────────────────┘ └──────────────────────────┘
Ich habe es auf GKE- und ACK-Clustern getestet. Alle schlugen fehl.
Die Dirty-Frag-Primitive erfordert die Erstellung von User-Namespaces (CLONE_NEWUSER), um CAP_NET_ADMIN innerhalb eines neuen Netzwerk-Namespace zu erhalten. Sowohl ACK als auch GKE blockieren dies auf Knotenebene über verschiedene Mechanismen:
user.max_user_namespaces=0) verhindert die Erstellung unprivilegierter User-Namespaces vollständig.--seccomp-default-Flag von kubelet) blockiert den unshare-Syscall unabhängig vom Namespace-Limit.Dies ist ein wesentlicher Unterschied zu Copy Fail (CVE-2026-31431), das keine User-Namespaces erfordert und alle drei Plattformen erfolgreich ausbeutet.
Die bereitgestellte EKS-Variante patcht die folgenden Binärdateien, wenn sie vorhanden sind:
/usr/sbin/xtables-legacy-multi
/usr/sbin/xtables-nft-multi
Diese Binärdateien werden von der iptables-Toolchain aufgerufen, die von kube-proxy verwendet wird. Der genaue Auslösezeitpunkt hängt von der Knoten- und Service-Abstimmungsaktivität ab. In der validierten Umgebung wurde die Payload durch normale kube-proxy-Abstimmung ausgelöst.
Wichtige Einschränkungen:
ipset nur auf, wenn es im ipvs-Modus konfiguriert ist. Der Standardmodus (iptables) verwendet ipset nicht.xtables-legacy-multi, xtables-nft-multi), um verschiedene Proxy-Modi abzudecken, aber ob sie aufgerufen werden, hängt von der Cluster-Konfiguration ab.Wenn kube-proxy in Ihrem Cluster nicht privilegiert ist, gilt das Angriffsprinzip dennoch — Sie müssen nur ein anderes privilegiertes DaemonSet identifizieren, das Image-Layer mit einem Basis-Image teilt, aus dem Sie bauen können.
.
├── exploit/
│ └── dirtyfrag.c # xfrm/ESP-Page-Cache-Writer
├── payload/
│ ├── payload-eks.c # nolibc-Payload, die /root/res auf dem Host schreibt
│ └── nolibc/ # Linux-nolibc-Header
├── deploy/
│ └── poc-eks.yaml # Manifest für unprivilegiertes EKS-Deployment
├── scripts/
│ ├── setup-eks.sh # Kopieren, Bauen und Importieren des Images auf einem EKS-Knoten
│ ├── run-poc.sh # Bereitstellen und Markierung prüfen
│ └── cleanup.sh # Pod, Markierung, gecachte Seiten und lokales Image entfernen
├── Dockerfile.eks # EKS-Image basierend auf eks-distro-minimal-base-iptables
├── Makefile # Payload-, Exploit-, Docker- und nerdctl-Build-Ziele
└── .github/workflows/
└── docker-publish.yml # GHCR-Veröffentlichungs-Workflow
# Payload + Exploit-Binärdatei bauen
make build-eks CC=x86_64-linux-gnu-gcc
# Docker-Image bauen
make docker-build-eks
# Bereitstellen (unprivilegierter Pod)
kubectl apply -f deploy/poc-eks.yaml
# Logs prüfen
kubectl logs deployment/dirtyfrag-poc-eks
# Escape auf dem Knoten verifizieren
ssh ec2-user@<node-ip> "sudo cat /root/res"
# Erwartet: [*] success
Der GitHub-Actions-Workflow (.github/workflows/docker-publish.yml) veröffentlicht das Image bei Push auf main oder bei Tag-Erstellung auf GHCR. Ersetzen Sie <owner> in deploy/poc-eks.yaml durch den GitHub-Benutzer oder die Organisation, der/die den Fork besitzt.
kubectl delete -f deploy/poc-eks.yaml --ignore-not-found
ssh ec2-user@<node-ip> "sudo rm -f /root/res"
kubectl delete pod -n kube-system -l k8s-app=kube-proxy --force
f4c50a4034e6).f4c50a4034e6 oder des Hersteller-Backports.esp4 und esp6, wenn IPsec-ESP auf Worker-Knoten nicht benötigt wird.user.max_user_namespaces=0 verhindert, dass dieses PoC CAP_NET_ADMIN in einem neuen Netzwerk-Namespace erhält (dies ist auf ACK bereits der Standard).privileged: true und umfangreichen Host-Zugriff, sofern nicht unbedingt erforderlich.Beispiel für einen Modulblock:
printf 'install esp4 /bin/false\ninstall esp6 /bin/false\n' | sudo tee /etc/modprobe.d/dirtyfrag.conf
sudo rmmod esp4 esp6 2>/dev/null || true
Der Exploit-Code ist unter der MIT-Lizenz von V4bel/dirtyfrag adaptiert.
Der Payload-Code stammt von tgies/copy-fail-c und ist unter LGPL-2.1-or-later ODER MIT dual-lizenziert.
Die nolibc-Header stammen aus der Linux-Kernel-Self-Test-Infrastruktur.
| Eigenschaft | Copy Fail | Dirty Frag |
|---|
| CVE | CVE-2026-31431 | CVE-2026-43284 |
| Kernel-Pfad | AF_ALG + splice() | xfrm/ESP + splice() |
| Namespace-Anforderung | Nicht erforderlich | Erfordert User-Namespaces |
| Haupt-Capability | Keine im anfänglichen Container | CAP_NET_ADMIN innerhalb des neuen Netzwerk-Namespace |
| Relevantes Modul | algif_aead | esp4 |
| Praktischer Unterschied | Bricht, wenn AF_ALG-Vektor blockiert ist | Weiterhin relevant, wenn AF_ALG nicht verfügbar ist, aber ESP/User-Namespaces aktiviert sind |
| Eigenschaft | Wert |
|---|
| Plattform | Amazon Elastic Kubernetes Service (EKS) |
| Knoten-Kernel | 6.12.80-106.156.amzn2023.x86_64 |
| Patch-Status | Kernel vor dem Fix, f4c50a4034e6 fehlt |
esp4-Modul | Geladen |
| User-Namespaces | Aktiviert (user.max_user_namespaces=15030) |
| SELinux | Permissiv |
| Seccomp | Im getesteten Pod-Kontext unconfined |
| Ziel-DaemonSet | kube-proxy |
| Ziel-Privilegien | privileged: true, hostNetwork: true |
| Proxy-Modus | iptables |
| Markierungspfad | /root/res |
| Plattform | Ergebnis | Grund |
|---|
| Alibaba Cloud ACK | Fehlgeschlagen | user.max_user_namespaces ist auf Standard-Knoten-Images auf 0 gesetzt, sodass unprivilegierte Benutzer CLONE_NEWUSER-unshare nicht verwenden können. |
| Google GKE | Fehlgeschlagen | user.max_user_namespaces ist 15426, aber kubelet aktiviert --seccomp-default. Die Standard-Seccomp-Richtlinie deaktiviert den unshare-Syscall. |