
Funktionsfähiger PoC für CVE-2026-17106 (CopyEscape): TOCTOU-Race in docker cp, das beliebiges Schreiben auf dem Docker-Host ermöglicht. Docker-Labor + inotify-Monitor + LD_PRELOAD. Harmlose macOS-Variante und destruktive Linux-Variante.
Pädagogisches Proof of Concept zu CopyEscape (CVE-2026-17106), einer TOCTOU-Race-Condition-Schwachstelle in
docker cp, die es einem bösartigen Container ermöglicht, beliebige Dateien auf dem Docker-Host zu schreiben. Inspiriert von der ursprünglichen Arbeit von masasron, der die Schwachstelle im Blog "CopyEscape: Taking Over Docker Hosts with docker cp" entdeckte und dokumentierte.
CVE-2026-17106 ist eine TOCTOU-Race-Condition-Schwachstelle bei der Extraktion der Tar-Datei, die der Docker-Daemon während docker cp <contenedor>:<ruta> <destino> erzeugt. Betroffen sind die Docker CLI 29.6.1 und frühere Versionen; ab 29.7.0 wurde sie gepatcht. Der Fehler liegt in der CLI (Tar-Extraktion auf dem Host), nicht im Daemon.
Die als CopyEscape bezeichnete Kette zeigt, wie ein Angreifer – allein ausgehend von einem laufenden Container ohne zusätzliche Capabilities – Folgendes erreichen kann:
/watched/file.txt/ vor jedem Prozess, der es innerhalb des Containers öffnet, als reguläre Datei tarnen – mithilfe einer LD_PRELOAD-Bibliothek, die open, openat, openat2, fopen, stat, lstat, fstatat, statx und die 64-Varianten abfängt.aaa.txt bereithalten, die den Daemon zwingt, bei der Tar-Erstellung lange genug zu brauchen, damit der Monitor den Wettlauf gewinnt.inotify die Zugriffe des Daemons überwachen und im Wettlauffenster ein Unterverzeichnis escape/ durch einen absoluten Symlink auf das Host-Ziel (/Users/<usuario> unter macOS oder /usr/bin unter Linux) ersetzen – mittels zweier atomarer rename(2)-Aufrufe mit Rollback.escape, gefolgt von einem Kindeintrag escape/<basename>; die anfällige CLI erstellt den Symlink beim Client und extrahiert den Kindeintrag durch ihn hindurch, wobei sie außerhalb des vom Benutzer gewählten Ziels schreibt.Das Ergebnis ist beliebiges Schreiben von Dateien auf dem Host mit den Rechten des Prozesses, der docker cp ausführt. Die Linux-Variante überschreibt /usr/bin/runc und erreicht beim nächsten docker run / exec Codeausführung als root auf dem Host.
Dieses Repository enthält ausschließlich lehrreiches und defensives Material.
runc des Hosts: Verwende sie ausschließlich in einer Wegwerf-VM mit verifizierter Sicherungskopie.Die PoC wird mit einer harmlosen macOS-Variante geliefert (schreibt ~/pwnd als Marker), deren einziger Zweck es ist, als reproduzierbare Demonstration zu dienen.
┌─────────────────────────────────────────────────────────────────────┐
│ 1. LD_PRELOAD camufla /watched/file.txt como archivo regular │
│ open/openat/openat2/fopen/stat/lstat/fstatat/statx → decoy │
│ docker exec ... cat /watched/file.txt → "top-level file" │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 2. Layout real dentro del contenedor │
│ /watched/file.txt/ │
│ ├── aaa.txt (16 MiB de 'B', cebo lento) │
│ ├── escape/ (directorio real inicial) │
│ ├── escape/<basename> (payload: runc o pwnd) │
│ └── .swap-escape (symlink → /Users/<usr> o /usr/bin) │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 3. docker cp pide tar al daemon │
│ daemon recorre /watched/file.txt/ y abre aaa.txt │
│ inotify detecta IN_OPEN sobre aaa.txt │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 4. Monitor pivot: dos rename(2) atomicos con rollback │
│ escape/ → .old-escape/ (backup) │
│ .swap-escape → escape/ (symlink al target del host) │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 5. Tar resultante contiene: │
│ escape → /Users/<usr> (symlink absoluto) │
│ escape/<basename> (entrada hija que atraviesa el symlink) │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ 6. CLI vulnerable extrae symlink + hija │
│ crea escape → /Users/<usr> en el destino local │
│ extrae escape/<basename> A TRAVES del symlink │
│ escribe /Users/<usr>/<basename> en el host │
└──────────────────────────────────────────┬──────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────────┐
│ macOS: ~/pwnd con "COPYESCAPE_MACOS_DEMO" (demo inocua) │
│ Linux: /usr/bin/runc sobrescrito (RCE como root) │
└─────────────────────────────────────────────────────────────────────┘
Die PoC ist für die Ausführung unter macOS ausgelegt mit:
curl, tar, git und docker im PATH.alpine:3.21.HOME in der Form /Users/<usuario>.Für die macOS-Variante wird kein Root benötigt. Die Linux-Variante erfordert Root und eine Wegwerf-VM.
Der Runner run-poc.sh lädt das Binärprogramm der anfälligen CLI 29.6.1 automatisch von der offiziellen Docker-Website (download.docker.com) herunter. Er verändert die Docker-Desktop-Installation des Systems nicht: Er verwendet den aktuellen Daemon, ruft jedoch das heruntergeladene Binärprogramm für die docker cp-Operation auf.