Laboratório Docker autocontido demonstrando a travessia de diretório CVE-2007-4559 (TarSlip) via o módulo tarfile do Python. Inclui APIs vulneráveis e corrigidas, geração de payload e um script de demonstração interativo para educação em segurança.
Apenas para uso educacional. Este laboratório explora intencionalmente vulnerabilidades do sistema de arquivos dentro de contêineres Docker isolados. Não execute em nenhum sistema com dados sensíveis ou em ambientes de produção.
Um laboratório Docker autocontido que demonstra CVE-2007-4559 — a infame vulnerabilidade "TarSlip" no módulo tarfile do Python — através de uma cadeia de ataque concreta, de ponta a ponta:
extractall() escreve cegamente uma entrada tar nomeada ../../../etc/passwd fora do diretório de extração, sobrescrevendo o arquivo real do sistema./admin protegido.tarfile.extractall() do Python reproduz fielmente todas as entradas de um arquivo tar, incluindo entradas cujos nomes contêm sequências de travessia de diretório ../. Ele nunca foi projetado para ser uma fronteira de segurança.
nome da entrada tar : ../../../etc/passwd
diretório de extração : /shared/uploads/a1b2c3d4/
caminho resolvido : /shared/uploads/a1b2c3d4/../../../etc/passwd
= /etc/passwd ← arquivo do sistema sobrescrito
| Linha do tempo | |
|---|---|
| 2007 | Bug reportado à equipe de segurança do Python |
| 2007 – 2022 | Marcado como "não é um problema de segurança" — tarfile está "funcionando conforme o esperado" |
| 2022 | Pesquisadores da Trellix escaneiam GitHub e encontram mais de 350.000 repositórios chamando extractall() em entrada não confiável |
| 2022 | Divulgação pública. CVE-2007-4559 ressurge. Correria em toda a indústria. |
| 2023 | PEP 706 envia filter='data' no Python 3.12 — a correção é um único argumento |
A demonstração é executada em três movimentos, cada um exigindo uma tecla para avançar.
GET /admin → 401. O endpoint admin existe e está protegido. O atacante não sabe a senha.innocent.tar.gz → os arquivos caem dentro do diretório sandbox. Tudo parece normal.Atacante cria tarslip_passwd.tar.gz
└─ entrada: "../../../etc/passwd"
conteúdo: admin:hacked:1001:... ← senha plantada
│
▼
POST /upload (upload de arquivo multipart)
│
▼
extractall("/shared/uploads/{uuid}/")
resolve "../../../etc/passwd" → /etc/passwd ← CVE-2007-4559
│
▼
GET /admin Authorization: Basic admin:hacked
│
▼
HTTP 200 — "Welcome, admin! You have full admin access."
flag: CVE-2007-4559{tarslip_passwd_overwrite_to_admin_rce}
Um único HTTP POST. Nenhum shell. Nenhum payload RCE. Apenas um arquivo tar.
O mesmo tarball é enviado para a API corrigida, que passa filter='data' para extractall(). O Python lança tarfile.OutsideDestinationError — a travessia é bloqueada, /etc/passwd permanece intocado e /admin permanece bloqueado.
# Vulnerável — padrão antes do Python 3.14
tar.extractall(extraction_dir)
# Corrigido — PEP 706 (Python 3.12+)
tar.extractall(extraction_dir, filter='data')
Um argumento. Quinze anos para ser enviado.
Quatro serviços em uma rede bridge Docker isolada (tarslip-net). Nada alcança a internet.
┌─────────────────────────────────────────────────────────┐
│ tarslip-net (bridge) │
│ │
│ ┌─────────────────┐ ┌──────────────────────────┐ │
│ │ vulnerable-api │ │ file-server │ │
│ │ python:3.11.3 │ │ nginx:alpine │ │
│ │ porta 8000 │ │ porta 8080 (host) │ │
│ │ │ │ │ │
│ │ POST /upload │ │ Serve /shared via │ │
│ │ GET /admin │ │ HTTP — navegue pelas │ │
│ │ GET /health │ │ extrações visualmente │ │
│ └────────┬────────┘ └────────────┬─────────────┘ │
│ │ volume shared-storage │ │
│ └────────────────────────────┘ │
│ │
│ ┌─────────────────┐ │
│ │ attacker │ │
│ │ python:3.12 │ (sem porta no host — apenas interno)│
│ │ │ │
│ │ craft_malicious.py — gera tarballs │
│ │ demo.py — conduz a demonstração │
│ └─────────────────┘ │
└─────────────────────────────────────────────────────────┘
| Serviço | Imagem | Função | Porta do host |
|---|---|---|---|
vulnerable-api | python:3.11.3-slim | API Flask de upload + /admin protegido por autenticação /etc/passwd | 8000 |
fixed-api | python:3.12-slim | Mesmo código + USE_SAFE_EXTRACTION=true | 8000 |
file-server | nginx:alpine | Listagem de diretório dos arquivos extraídos | 8080 |
attacker | python:3.12-slim | Gerador de payload + condutor da demonstração | — |
As APIs vulnerável e corrigida usam código-fonte idêntico. A única diferença é a variável de ambiente USE_SAFE_EXTRACTION=true no contêiner corrigido, que ativa o único argumento filter='data'.
CVE-2007-4559-lab/
├── run_demo.sh ← comece aqui
├── docker-compose.vulnerable.yml
├── docker-compose.fixed.yml
├── vulnerable-api/
│ ├── app.py # API Flask: /upload + /admin + /health
│ ├── Dockerfile # insere admin:s3cr3t_Adm1nPass no /etc/passwd
│ └── requirements.txt
├── file-server/
│ ├── Dockerfile
│ └── nginx.conf
└── attacker/
├── craft_malicious.py # gera innocent.tar.gz + tarslip_passwd.tar.gz
├── demo.py # driver CLI com quatro modos (craft/baseline/exploit/verify)
├── Dockerfile
└── requirements.txt
docker compose version)bashgit clone https://github.com/seu-usuario/CVE-2007-4559-lab.git
cd CVE-2007-4559-lab
bash run_demo.sh
O script é totalmente interativo. Ele imprime uma narrativa antes de cada etapa e aguarda Enter para avançar. Nenhum conhecimento prévio de Docker é necessário para acompanhar.
| Pausa | Narrativa exibida | Ação ao pressionar Enter |
|---|---|---|
| 1 | Linha do tempo CVE, o que são os três movimentos | Constrói pilha vulnerável |
| 2 | Funções dos contêineres, senha admin inserida | Gera payloads |
| 3 | O que há dentro de cada tarball | Movimento 1 — linha de base |
| 4 | Por que /admin é 401, como é a extração normal | Movimento 2 — exploit |
| 5 | A matemática exata da travessia, o que é sobrescrito | Troca para pilha corrigida |
| 6 | O que filter='data' faz e por que funciona | Movimento 3 — verificação |
| 7 | Principais conclusões + padrão ZipSlip mais amplo | Desmontagem |
Se quiser avançar manualmente:
# Pilha vulnerável
docker compose -f docker-compose.vulnerable.yml up --build -d
docker compose -f docker-compose.vulnerable.yml exec attacker python craft_malicious.py
docker compose -f docker-compose.vulnerable.yml exec attacker python demo.py baseline
docker compose -f docker-compose.vulnerable.yml exec attacker python demo.py exploit