Análise Forense de Containers Docker
Quando Usar
- Ao investigar um container Docker comprometido ou o host do container
- Para analisar imagens Docker maliciosas baixadas de registries
- Durante resposta a incidentes envolvendo violações de aplicações conteinerizadas
- Ao examinar tentativas de escape de container ou escalonamento de privilégio
- Para auditar configurações de containers e identificar configurações incorretas
Pré-requisitos
- Acesso à CLI do Docker na workstation forense
- Acesso ao sistema de arquivos do host Docker (imagem forense ou ao vivo)
- Compreensão do sistema de arquivos em camadas do Docker (overlay2, aufs)
- dive, docker-explorer ou container-diff para análise de imagens
- Conhecimento da configuração do daemon Docker e segurança do socket
- Trivy ou Grype para escaneamento de vulnerabilidades de imagens de containers
Fluxo de Trabalho
Passo 1: Preservar o Estado do Container e as Evidências
# Listar todos os containers (incluindo parados)
docker ps -a --no-trunc > /casos/caso-2024-001/docker/lista_containers.txt
# Inspecionar o container comprometido
CONTAINER_ID="abc123def456"
docker inspect $CONTAINER_ID > /casos/caso-2024-001/docker/inspecao_container.json
# Exportar o sistema de arquivos do container como tarball (preserva o estado atual)
docker export $CONTAINER_ID > /casos/caso-2024-001/docker/exportacao_container.tar
# Criar uma imagem a partir do estado atual do container
docker commit $CONTAINER_ID evidencia-forense:caso-2024-001
docker save evidencia-forense:caso-2024-001 > /casos/caso-2024-001/docker/imagem_container.tar
# Capturar logs do container
docker logs $CONTAINER_ID --timestamps > /casos/caso-2024-001/docker/logs_container.txt 2>&1
# Capturar processos em execução (se o container ainda estiver em execução)
docker top $CONTAINER_ID > /casos/caso-2024-001/docker/processos_container.txt
# Capturar conexões de rede
docker exec $CONTAINER_ID netstat -tlnp 2>/dev/null > /casos/caso-2024-001/docker/rede_container.txt
# Copiar arquivos específicos do container
docker cp $CONTAINER_ID:/var/log/ /casos/caso-2024-001/docker/container_var_log/
docker cp $CONTAINER_ID:/tmp/ /casos/caso-2024-001/docker/container_tmp/
docker cp $CONTAINER_ID:/etc/passwd /casos/caso-2024-001/docker/container_passwd
# Hashear todas as evidências exportadas
sha256sum /casos/caso-2024-001/docker/*.tar > /casos/caso-2024-001/docker/hashes_evidencias.txt
Passo 2: Analisar as Camadas da Imagem do Container
# Instalar dive para análise de camadas de imagem
wget https://github.com/wagoodman/dive/releases/latest/download/dive_linux_amd64.deb
sudo dpkg -i dive_linux_amd64.deb
# Analisar camadas da imagem interativamente
dive evidencia-forense:caso-2024-001
# Análise de camadas não interativa
dive evidencia-forense:caso-2024-001 --ci --json /casos/caso-2024-001/docker/analise_dive.json
# Extrair e examinar camadas individuais
mkdir -p /casos/caso-2024-001/docker/camadas/
tar -xf /casos/caso-2024-001/docker/imagem_container.tar -C /casos/caso-2024-001/docker/camadas/
# Listar o manifesto da imagem e a ordem das camadas
cat /casos/caso-2024-001/docker/camadas/manifest.json | python3 -m json.tool
# Examinar cada camada em busca de alterações
for camada in /casos/caso-2024-001/docker/camadas/*/layer.tar; do
echo "=== Camada: $(dirname $camada | xargs basename) ==="
tar -tf "$camada" | head -20
echo "..."
done
# Usar container-diff para comparar com a imagem base original
# Instalar container-diff
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64
chmod +x container-diff-linux-amd64
# Comparar imagem salva com a original
./container-diff-linux-amd64 diff daemon://nginx:latest daemon://evidencia-forense:caso-2024-001 \
--type=file --type=apt --type=history --json \
> /casos/caso-2024-001/docker/diff_container.json
Passo 3: Examinar Artefatos do Host Docker
# Diretório de dados do Docker (padrão: /var/lib/docker/)
DOCKER_ROOT="/mnt/evidencia/var/lib/docker"
# Examinar camadas do sistema de arquivos overlay2
ls -la $DOCKER_ROOT/overlay2/
# Encontrar o sistema de arquivos mesclado do container
CONTAINER_HASH=$(docker inspect $CONTAINER_ID --format '{{.GraphDriver.Data.MergedDir}}' 2>/dev/null)
# Ou manualmente a partir da imagem forense:
# Procurar em /var/lib/docker/containers/<container_id>/config.v2.json
# Analisar arquivos de configuração do container
cat $DOCKER_ROOT/containers/$CONTAINER_ID/config.v2.json | python3 -m json.tool \
> /casos/caso-2024-001/docker/config_container.json
# Verificar configuração do daemon Docker
cat /mnt/evidencia/etc/docker/daemon.json 2>/dev/null > /casos/caso-2024-001/docker/config_daemon.json
# Examinar log de eventos do Docker
cat $DOCKER_ROOT/containers/$CONTAINER_ID/*.log > /casos/caso-2024-001/docker/logs_json_container.txt
# Verificar montagens de volumes (potencial acesso ao sistema de arquivos do host)
python3 << 'PYEOF'
import json
with open('/casos/caso-2024-001/docker/inspecao_container.json') as f:
data = json.load(f)
inspect = data[0] if isinstance(data, list) else data
print("=== ANÁLISE DE SEGURANÇA DO CONTAINER ===\n")
# Verificar montagens
print("Montagens de Volume:")
for mount in inspect.get('Mounts', []):
rw = "LEITURA-ESCRITA" if mount.get('RW') else "SOMENTE LEITURA"
print(f" {mount.get('Source', 'N/A')} -> {mount.get('Destination', 'N/A')} ({rw})")
if mount.get('Source') in ('/', '/etc', '/var', '/root') and mount.get('RW'):
print(f" AVISO: Caminho sensível do host montado com leitura-escrita!")
# Verificar modo privilegiado
host_config = inspect.get('HostConfig', {})
if host_config.get('Privileged'):
print("\nAVISO: O container estava executando em modo PRIVILEGIADO!")
# Verificar capabilities
cap_add = host_config.get('CapAdd', [])
if cap_add:
print(f"\nCapabilities Adicionadas: {cap_add}")
perigosas = ['SYS_ADMIN', 'SYS_PTRACE', 'NET_ADMIN', 'SYS_MODULE']
for cap in cap_add:
if cap in perigosas:
print(f" AVISO: Capability perigosa: {cap}")
# Verificar namespace PID
if host_config.get('PidMode') == 'host':
print("\nAVISO: Container compartilha o namespace PID do host!")
# Verificar modo de rede
if host_config.get('NetworkMode') == 'host':
print("\nAVISO: Container compartilha o namespace de rede do host!")
# Verificar usuário
user = inspect.get('Config', {}).get('User', 'root (padrão)')
print(f"\nExecutando como usuário: {user}")
# Verificar variáveis de ambiente em busca de segredos
env_vars = inspect.get('Config', {}).get('Env', [])
print(f"\nVariáveis de Ambiente: {len(env_vars)}")
for env in env_vars:
key = env.split('=')[0]
if any(s in key.upper() for s in ['SENHA', 'SEGREDO', 'CHAVE', 'TOKEN', 'CREDENCIAL']):
print(f" SENSÍVEL: {key}=***EDITADO***")
PYEOF
Passo 4: Analisar as Alterações no Sistema de Arquivos do Container
# Comparar o sistema de arquivos do container com a imagem original
docker diff $CONTAINER_ID > /casos/caso-2024-001/docker/alteracoes_sistema_arquivos.txt
# A = Adicionado, C = Alterado, D = Excluído
# Analisar alterações
python3 << 'PYEOF'
adicionados = []
alterados = []
excluidos = []
with open('/casos/caso-2024-001/docker/alteracoes_sistema_arquivos.txt') as f:
for line in f:
line = line.strip()
if line.startswith('A '):
adicionados.append(line[2:])
elif line.startswith('C '):
alterados.append(line[2:])
elif line.startswith('D '):
excluidos.append(line[2:])
print(f"Arquivos Adicionados: {len(adicionados)}")
print(f"Arquivos Alterados: {len(alterados)}")
print(f"Arquivos Excluídos: {len(excluidos)}")
# Sinalizar adições suspeitas
suspeitos = [f for f in adicionados if any(s in f for s in
['/tmp/', '/dev/shm/', '/root/', '.sh', '.py', '.elf', 'reverse', 'shell', 'backdoor'])]
if suspeitos:
print(f"\nArquivos Adicionados Suspeitos:")
for f in suspeitos:
print(f" {f}")
# Sinalizar alterações suspeitas
sus_alterados = [f for f in alterados if any(s in f for s in
['/etc/passwd', '/etc/shadow', '/etc/crontab', '/etc/ssh', '.bashrc'])]
if sus_alterados:
print(f"\nArquivos Alterados Suspeitos:")
for f in sus_alterados:
print(f" {f}")
PYEOF
# Extrair e examinar a exportação do container
mkdir -p /casos/caso-2024-001/docker/fs_container/
tar -xf /casos/caso-2024-001/docker/exportacao_container.tar -C /casos/caso-2024-001/docker/fs_container/
# Escanear por webshells e arquivos maliciosos
find /casos/caso-2024-001/docker/fs_container/tmp/ -type f -exec file {} \;
find /casos/caso-2024-001/docker/fs_container/ -name "*.php" -newer /casos/caso-2024-001/docker/fs_container/etc/hostname
Passo 5: Escanear Vulnerabilidades e Gerar Relatório
# Escanear a imagem em busca de vulnerabilidades conhecidas
trivy image evidencia-forense:caso-2024-001 \
--format json \
--output /casos/caso-2024-001/docker/escaneamento_vulnerabilidades.json
# Escanear o sistema de arquivos exportado
trivy fs /casos/caso-2024-001/docker/fs_container/ \
--format table \
--output /casos/caso-2024-001/docker/vulnerabilidades_fs.txt
# Verificar segredos na imagem
trivy image evidencia-forense:caso-2024-001 \
--scanners secret \
--format json \
--output /casos/caso-2024-001/docker/escaneamento_segredos.json
Conceitos-chave
| Conceito | Descrição |
|---|---|
| Camadas da imagem | Camadas do sistema de arquivos somente leitura empilhadas para formar a imagem do container |
| overlay2 | Driver de armazenamento Docker padrão que usa sistema de arquivos union para camadas |
| Diff do container | Comparação das alterações do sistema de arquivos em tempo de execução contra a imagem original |
| Modo privilegiado | Container com capacidades completas do host (ignora a maioria do isolamento) |
| Socket Docker | Socket Unix (/var/run/docker.sock) que controla o daemon Docker |
| Escape de container | Técnica para quebrar o isolamento do container e acessar o host |
| Montagens de volume | Caminhos do sistema de arquivos do host tornados acessíveis dentro do container |
| Histórico da imagem | Registro das instruções do Dockerfile usadas para construir cada camada |
Ferramentas e Sistemas
| Ferramenta | Propósito |
|---|---|
| docker inspect | Informações detalhadas de configuração e estado do container |
| docker diff | Mostra alterações no sistema de arquivos em um container em execução/parado |
| dive | Ferramenta interativa de análise de camadas de imagens Docker |
| container-diff | Ferramenta do Google para comparar conteúdos de imagens de containers |
| Trivy | Escâner de vulnerabilidades para imagens de containers e sistemas de arquivos |
| docker-explorer | Ferramenta forense para análise offline de artefatos Docker |
| Sysdig | Monitoramento de segurança e forense em tempo de execução de containers |
| Falco | Detecção de ameaças em tempo de execução para containers e Kubernetes |
Cenários Comuns
Cenário 1: Comprometimento de Container de Aplicação Web Exportar o sistema de arquivos do container, identificar webshells no diretório raiz web, analisar logs de acesso em busca de tentativas de exploração, verificar arquivos adicionados e configurações modificadas, examinar conexões de rede para comunicação C2, revisar capacidades do container para caminhos de escalonamento.
Cenário 2: Ataque à Cadeia de Suprimentos via Imagem Maliciosa Analisar camadas da imagem com dive para identificar qual camada adicionou conteúdo malicioso, comparar com a imagem base oficial usando container-diff, verificar o histórico da imagem em busca de comandos RUN suspeitos, escanear por backdoors e mineradores de criptomoedas embutidos, rastrear o pull da imagem a partir de logs do registry.
Cenário 3: Investigação de Escape de Container Verificar se o container foi executado em modo privilegiado ou com capacidades perigosas, examinar pontos de montagem do sistema de arquivos do host para acesso não autorizado, revisar a montagem do socket Docker permitindo abuso de Docker-in-Docker, analisar logs do sistema do host para indicadores de escape de container, verificar artefatos de exploração do kernel.
Cenário 4: Cryptojacking em Ambiente de Container Identificar containers com alto uso de CPU, exportar e analisar a imagem do container em busca de binários de mineração, verificar imagens não autorizadas no registry, revisar eventos de criação de containers para implantações maliciosas, examinar conexões de rede para comunicações com pools de mineração.
Formato de Saída
Resumo de Forense de Container Docker:
Container: abc123def456 (nginx-app)
Imagem: company/web-app:v2.1
Status: Em execução (iniciado em 2024-01-10 09:00 UTC)
Host: docker-host-01.corp.local
Configuração de Segurança:
Privilegiado: Não
Capabilities Adicionadas: NET_ADMIN (AVISO)
Montagens de Volume: /var/log -> /host-logs (RW)
Modo de Rede: bridge
Usuário: root (AVISO)
Alterações no Sistema de Arquivos:
Adicionados: 23 arquivos (5 suspeitos)
Alterados: 12 arquivos (2 suspeitos)
Excluídos: 0 arquivos
Descobertas Suspeitas:
/tmp/reverse.sh - Script de shell reverso (Adicionado)
/var/www/html/.hidden/shell.php - Webshell PHP (Adicionado)
/etc/crontab - Modificado (entrada de cron de persistência adicionada)
/root/.ssh/authorized_keys - Modificado (chave não autorizada adicionada)
Escaneamento de Vulnerabilidades:
Críticas: 3 (CVE-2024-xxxx na imagem base)
Altas: 12
Médias: 34
Evidências: /casos/caso-2024-001/docker/