Was macht Analyse der Docker-Container-Forensik?
Verwendungszweck
- Bei der Untersuchung eines kompromittierten Docker-Containers oder Container-Hosts
- Für die Analyse bösartiger Docker-Images, die aus Registries gezogen wurden
- Während der Incident-Response bei Sicherheitsvorfällen in containerisierten Anwendungen
- Bei der Untersuchung von Container-Escape-Versuchen oder Privilegieneskalation
- Für die Überprüfung von Container-Konfigurationen und die Identifizierung von Fehlkonfigurationen
Voraussetzungen
- Docker-CLI-Zugriff auf der Forensik-Workstation
- Zugriff auf das Dateisystem des Docker-Hosts (forensisches Image oder Live-System)
- Verständnis des geschichteten Dateisystems von Docker (overlay2, aufs)
- dive, docker-explorer oder container-diff zur Image-Analyse
- Kenntnisse der Docker-Daemon-Konfiguration und Socket-Sicherheit
- Trivy oder Grype zur Schwachstellenscanning von Container-Images
Arbeitsablauf
Schritt 1: Containerzustand und Beweismittel sichern
# Alle Container auflisten (auch gestoppte)
docker ps -a --no-trunc > /cases/case-2024-001/docker/container_list.txt
# Den kompromittierten Container inspizieren
CONTAINER_ID="abc123def456"
docker inspect $CONTAINER_ID > /cases/case-2024-001/docker/container_inspect.json
# Container-Dateisystem als Tarball exportieren (aktuellen Zustand sichern)
docker export $CONTAINER_ID > /cases/case-2024-001/docker/container_export.tar
# Ein Image aus dem aktuellen Container-Zustand erstellen
docker commit $CONTAINER_ID forensic-evidence:case-2024-001
docker save forensic-evidence:case-2024-001 > /cases/case-2024-001/docker/container_image.tar
# Container-Logs erfassen
docker logs $CONTAINER_ID --timestamps > /cases/case-2024-001/docker/container_logs.txt 2>&1
# Laufende Prozesse erfassen (falls der Container noch läuft)
docker top $CONTAINER_ID > /cases/case-2024-001/docker/container_processes.txt
# Netzwerkverbindungen erfassen
docker exec $CONTAINER_ID netstat -tlnp 2>/dev/null > /cases/case-2024-001/docker/container_network.txt
# Bestimmte Dateien aus dem Container kopieren
docker cp $CONTAINER_ID:/var/log/ /cases/case-2024-001/docker/container_var_log/
docker cp $CONTAINER_ID:/tmp/ /cases/case-2024-001/docker/container_tmp/
docker cp $CONTAINER_ID:/etc/passwd /cases/case-2024-001/docker/container_passwd
# Alle exportierten Beweismittel hashen
sha256sum /cases/case-2024-001/docker/*.tar > /cases/case-2024-001/docker/evidence_hashes.txt
Schritt 2: Container-Image-Layer analysieren
# dive zur Image-Layer-Analyse installieren
wget https://github.com/wagoodman/dive/releases/latest/download/dive_linux_amd64.deb
sudo dpkg -i dive_linux_amd64.deb
# Image-Layer interaktiv analysieren
dive forensic-evidence:case-2024-001
# Nicht-interaktive Layer-Analyse
dive forensic-evidence:case-2024-001 --ci --json /cases/case-2024-001/docker/dive_analysis.json
# Einzelne Layer extrahieren und untersuchen
mkdir -p /cases/case-2024-001/docker/layers/
tar -xf /cases/case-2024-001/docker/container_image.tar -C /cases/case-2024-001/docker/layers/
# Image-Manifest und Layer-Reihenfolge auflisten
cat /cases/case-2024-001/docker/layers/manifest.json | python3 -m json.tool
# Jeden Layer auf Änderungen untersuchen
for layer in /cases/case-2024-001/docker/layers/*/layer.tar; do
echo "=== Layer: $(dirname $layer | xargs basename) ==="
tar -tf "$layer" | head -20
echo "..."
done
# container-diff zum Vergleich mit dem ursprünglichen Basis-Image verwenden
# container-diff installieren
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64
chmod +x container-diff-linux-amd64
# Committiertes Image mit dem Original vergleichen
./container-diff-linux-amd64 diff daemon://nginx:latest daemon://forensic-evidence:case-2024-001 \
--type=file --type=apt --type=history --json \
> /cases/case-2024-001/docker/container_diff.json
Schritt 3: Docker-Host-Artefakte untersuchen
# Docker-Datenverzeichnis (Standard: /var/lib/docker/)
DOCKER_ROOT="/mnt/evidence/var/lib/docker"
# overlay2-Dateisystem-Layer untersuchen
ls -la $DOCKER_ROOT/overlay2/
# Das zusammengeführte Dateisystem des Containers finden
CONTAINER_HASH=$(docker inspect $CONTAINER_ID --format '{{.GraphDriver.Data.MergedDir}}' 2>/dev/null)
# Oder manuell aus dem forensischen Image:
# Blick in /var/lib/docker/containers/<container_id>/config.v2.json
# Container-Konfigurationsdateien analysieren
cat $DOCKER_ROOT/containers/$CONTAINER_ID/config.v2.json | python3 -m json.tool \
> /cases/case-2024-001/docker/container_config.json
# Docker-Daemon-Konfiguration prüfen
cat /mnt/evidence/etc/docker/daemon.json 2>/dev/null > /cases/case-2024-001/docker/daemon_config.json
# Docker-Ereignisprotokoll untersuchen
cat $DOCKER_ROOT/containers/$CONTAINER_ID/*.log > /cases/case-2024-001/docker/container_json_logs.txt
# Auf Volume-Mounts prüfen (potenzieller Host-Dateisystemzugriff)
python3 << 'PYEOF'
import json
with open('/cases/case-2024-001/docker/container_inspect.json') as f:
data = json.load(f)
inspect = data[0] if isinstance(data, list) else data
print("=== CONTAINER-SICHERHEITSANALYSE ===\n")
# Mounts prüfen
print("Volume-Mounts:")
for mount in inspect.get('Mounts', []):
rw = "LESEN-SCHREIBEN" if mount.get('RW') else "SCHREIBGESCHÜTZT"
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" WARNUNG: Sensitiver Host-Pfad lesen-schreiben gemountet!")
# Privilegierten Modus prüfen
host_config = inspect.get('HostConfig', {})
if host_config.get('Privileged'):
print("\nWARNUNG: Container lief im PRIVILEGIERTEN Modus!")
# Capabilities prüfen
cap_add = host_config.get('CapAdd', [])
if cap_add:
print(f"\nHinzugefügte Capabilities: {cap_add}")
dangerous_caps = ['SYS_ADMIN', 'SYS_PTRACE', 'NET_ADMIN', 'SYS_MODULE']
for cap in cap_add:
if cap in dangerous_caps:
print(f" WARNUNG: Gefährliche Capability: {cap}")
# PID-Namensraum prüfen
if host_config.get('PidMode') == 'host':
print("\nWARNUNG: Container teilt den Host-PID-Namensraum!")
# Netzwerkmodus prüfen
if host_config.get('NetworkMode') == 'host':
print("\nWARNUNG: Container teilt den Host-Netzwerknamensraum!")
# Benutzer prüfen
user = inspect.get('Config', {}).get('User', 'root (Standard)')
print(f"\nLäuft als Benutzer: {user}")
# Umgebungsvariablen auf Geheimnisse prüfen
env_vars = inspect.get('Config', {}).get('Env', [])
print(f"\nUmgebungsvariablen: {len(env_vars)}")
for env in env_vars:
key = env.split('=')[0]
if any(s in key.upper() for s in ['PASSWORD', 'SECRET', 'KEY', 'TOKEN', 'CREDENTIAL']):
print(f" SENSITIV: {key}=***GESCHWÄRZT***")
PYEOF
Schritt 4: Änderungen am Container-Dateisystem analysieren
# Container-Dateisystem mit dem ursprünglichen Image vergleichen
docker diff $CONTAINER_ID > /cases/case-2024-001/docker/filesystem_changes.txt
# A = Hinzugefügt, C = Geändert, D = Gelöscht
# Änderungen analysieren
python3 << 'PYEOF'
added = []
changed = []
deleted = []
with open('/cases/case-2024-001/docker/filesystem_changes.txt') as f:
for line in f:
line = line.strip()
if line.startswith('A '):
added.append(line[2:])
elif line.startswith('C '):
changed.append(line[2:])
elif line.startswith('D '):
deleted.append(line[2:])
print(f"Dateien hinzugefügt: {len(added)}")
print(f"Dateien geändert: {len(changed)}")
print(f"Dateien gelöscht: {len(deleted)}")
# Verdächtige Hinzufügungen markieren
suspicious = [f for f in added if any(s in f for s in
['/tmp/', '/dev/shm/', '/root/', '.sh', '.py', '.elf', 'reverse', 'shell', 'backdoor'])]
if suspicious:
print(f"\nVerdächtige hinzugefügte Dateien:")
for f in suspicious:
print(f" {f}")
# Verdächtige Änderungen markieren
sus_changed = [f for f in changed if any(s in f for s in
['/etc/passwd', '/etc/shadow', '/etc/crontab', '/etc/ssh', '.bashrc'])]
if sus_changed:
print(f"\nVerdächtige geänderte Dateien:")
for f in sus_changed:
print(f" {f}")
PYEOF
# Container-Export extrahieren und untersuchen
mkdir -p /cases/case-2024-001/docker/container_fs/
tar -xf /cases/case-2024-001/docker/container_export.tar -C /cases/case-2024-001/docker/container_fs/
# Nach Webshells und bösartigen Dateien suchen
find /cases/case-2024-001/docker/container_fs/tmp/ -type f -exec file {} \;
find /cases/case-2024-001/docker/container_fs/ -name "*.php" -newer /cases/case-2024-001/docker/container_fs/etc/hostname
Schritt 5: Auf Schwachstellen scannen und Bericht erstellen
# Das Image auf bekannte Schwachstellen scannen
trivy image forensic-evidence:case-2024-001 \
--format json \
--output /cases/case-2024-001/docker/vulnerability_scan.json
# Das exportierte Dateisystem scannen
trivy fs /cases/case-2024-001/docker/container_fs/ \
--format table \
--output /cases/case-2024-001/docker/fs_vulnerabilities.txt
# Nach Geheimnissen im Image suchen
trivy image forensic-evidence:case-2024-001 \
--scanners secret \
--format json \
--output /cases/case-2024-001/docker/secrets_scan.json
Schlüsselkonzepte
| Konzept | Beschreibung |
|---|---|
| Image-Layer | Nur-Lesen-Dateisystemschichten, die das Container-Image bilden |
| overlay2 | Standard-Docker-Speichertreiber mit Union-Dateisystem für Layer |
| Container-Diff | Vergleich der Laufzeit-Dateisystemänderungen mit dem Original-Image |
| Privilegierter Modus | Container mit vollständigen Host-Capabilities (umgeht die meisten Isolationen) |
| Docker-Socket | Unix-Socket (/var/run/docker.sock) zur Steuerung des Docker-Daemons |
| Container-Escape | Technik zum Ausbrechen aus der Container-Isolation auf den Host |
| Volume-Mounts | Host-Dateisystempfade, die innerhalb des Containers zugänglich gemacht werden |
| Image-Historie | Aufzeichnung der Dockerfile-Anweisungen, die zum Erstellen jedes Layers verwendet wurden |
Werkzeuge & Systeme
| Werkzeug | Zweck |
|---|---|
| docker inspect | Detaillierte Container-Konfiguration und Zustandsinformationen |
| docker diff | Dateisystemänderungen in einem laufenden/gestoppten Container anzeigen |
| dive | Interaktives Docker-Image-Layer-Analysewerkzeug |
| container-diff | Google-Werkzeug zum Vergleichen von Container-Image-Inhalten |
| Trivy | Schwachstellenscanner für Container-Images und Dateisysteme |
| docker-explorer | Forensik-Werkzeug für die Offline-Analyse von Docker-Artefakten |
| Sysdig | Laufzeit-Sicherheitsüberwachung und Forensik für Container |
| Falco | Laufzeit-Bedrohungserkennung für Container und Kubernetes |
Häufige Szenarien
Szenario 1: Kompromittierung einer Webanwendungs-Container Exportieren Sie das Container-Dateisystem, identifizieren Sie Webshells im Web-Root, analysieren Sie Zugriffslogs auf Exploit-Versuche, prüfen Sie auf hinzugefügte Dateien und geänderte Konfigurationen, untersuchen Sie Netzwerkverbindungen auf C2-Kommunikation, überprüfen Sie Container-Capabilities auf Eskalationspfade.
Szenario 2: Supply-Chain-Angriff über bösartiges Image Analysieren Sie Image-Layer mit dive, um zu identifizieren, welcher Layer bösartige Inhalte hinzugefügt hat, vergleichen Sie mit dem offiziellen Basis-Image mit container-diff, prüfen Sie die Image-Historie auf verdächtige RUN-Befehle, scannen Sie nach eingebauten Backdoors und Cryptominern, verfolgen Sie den Image-Pull anhand von Registry-Logs.
Szenario 3: Untersuchung eines Container-Escapes Prüfen Sie, ob der Container privilegiert oder mit gefährlichen Capabilities lief, untersuchen Sie Host-Dateisystem-Mountpoints auf unbefugten Zugriff, überprüfen Sie Docker-Socket-Mounts, die Docker-in-Docker-Missbrauch ermöglichen, analysieren Sie Host-Systemlogs auf Container-Escape-Indikatoren, suchen Sie nach Kernel-Exploit-Artefakten.
Szenario 4: Cryptojacking in einer Container-Umgebung Identifizieren Sie Container mit hoher CPU-Auslastung, exportieren Sie das Container-Image und analysieren Sie es auf Mining-Binaries, prüfen Sie auf unbefugte Images in der Registry, überprüfen Sie Container-Erstellungsereignisse auf Schattenbereitstellungen, untersuchen Sie Netzwerkverbindungen auf Mining-Pool-Kommunikation.
Ausgabeformat
Docker Container Forensik Zusammenfassung:
Container: abc123def456 (nginx-app)
Image: company/web-app:v2.1
Status: Läuft (gestartet 2024-01-10 09:00 UTC)
Host: docker-host-01.corp.local
Sicherheitskonfiguration:
Privilegiert: Nein
Capabilities hinzugefügt: NET_ADMIN (WARNUNG)
Volume-Mounts: /var/log -> /host-logs (RW)
Netzwerkmodus: bridge
Benutzer: root (WARNUNG)
Dateisystemänderungen:
Hinzugefügt: 23 Dateien (5 verdächtig)
Geändert: 12 Dateien (2 verdächtig)
Gelöscht: 0 Dateien
Verdächtige Funde:
/tmp/reverse.sh - Reverse-Shell-Skript (Hinzugefügt)
/var/www/html/.hidden/shell.php - PHP-Webshell (Hinzugefügt)
/etc/crontab - Geändert (Persistenz-Cron-Eintrag hinzugefügt)
/root/.ssh/authorized_keys - Geändert (Unbefugter Schlüssel hinzugefügt)
Schwachstellenscan:
Kritisch: 3 (CVE-2024-xxxx im Basis-Image)
Hoch: 12
Mittel: 34
Beweismittel: /cases/case-2024-001/docker/