
PoC funcional do CVE-2026-17106 (CopyEscape): corrida TOCTOU no docker cp que permite escrita arbitrária no host Docker. Laboratório Docker + monitor inotify + LD_PRELOAD. Variante macOS inócua e Linux destrutiva.
PoC educativa de CopyEscape (CVE-2026-17106), vulnerabilidade de corrida TOCTOU em
docker cpque permite a um contêiner malicioso escrever arquivos arbitrários no host Docker. Inspirada no trabalho original de masasron, que descobriu e documentou a vulnerabilidade no blog "CopyEscape: Taking Over Docker Hosts with docker cp".
CVE-2026-17106 é uma vulnerabilidade de condição de corrida (TOCTOU) na extração do arquivo tar que o daemon do Docker produz durante docker cp <contenedor>:<ruta> <destino>. Afeta a CLI do Docker 29.6.1 e versões anteriores; corrigida a partir da 29.7.0. O bug reside na CLI (extração do tar no host), não no daemon.
A cadeia batizada de CopyEscape demonstra como, partindo apenas de um contêiner em execução sem capacidades extras, um atacante pode:
/watched/file.txt/ como um arquivo regular diante de qualquer processo que o abra dentro do contêiner, por meio de uma biblioteca LD_PRELOAD que intercepta open, openat, openat2, fopen, stat, lstat, fstatat, statx e as variantes 64.aaa.txt de 16 MiB que força o daemon a demorar o suficiente para produzir o tar para que o monitor vença a corrida.inotify os acessos do daemon e, na janela de corrida, substituir um subdiretório escape/ por um symlink absoluto para o alvo do host (/Users/<usuario> no macOS ou /usr/bin no Linux) por meio de dois rename(2) atômicos com rollback.escape seguido de uma entrada filha escape/<basename>; a CLI vulnerável cria o symlink no cliente e extrai a entrada filha através dele, escrevendo fora do destino escolhido pelo usuário.O resultado é escrita arbitrária de arquivos no host com as permissões do processo que executa docker cp. A variante Linux sobrescreve /usr/bin/runc e consegue execução de código como root no host no próximo docker run / exec.
Este repositório contém material estritamente educativo e defensivo.
runc do host: use-a somente em uma VM descartável com cópia de segurança verificada.A PoC é entregue com uma variante macOS inócua (escreve ~/pwnd como marcador) cuja única finalidade é servir como demonstração reproduzível.
┌─────────────────────────────────────────────────────────────────────┐
│ 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) │
└─────────────────────────────────────────────────────────────────────┘
A PoC está construída para ser executada no macOS com:
curl, tar, git e docker no PATH.alpine:3.21.HOME com a forma /Users/<usuario>.Não é necessário root para a variante macOS. A variante Linux requer root e uma VM descartável.
O runner run-poc.sh baixa automaticamente o binário da CLI vulnerável 29.6.1 do site oficial do Docker (download.docker.com). Não modifica a instalação do Docker Desktop do sistema: usa o daemon atual, mas invoca o binário baixado para a operação docker cp.