analyzing-docker-container-forensics について
コンテナやホストのインシデントを扱うセキュリティ調査担当者向けの Docker フォレンジック手順です。証拠保全、イメージレイヤーとファイルシステムの分析、脆弱性スキャン、報告を扱います。
主な機能
- 01コンテナ状態と証拠の保全
- 02イメージレイヤーとビルド履歴の分析
- 03Docker ホストのファイルシステム痕跡の調査
- 04実行時のファイルシステム変更の比較
- 05イメージの脆弱性スキャンと報告
活用シーン
- 01侵害されたコンテナやホストの調査
- 02レジストリから取得した悪意あるイメージの分析
- 03コンテナエスケープや権限昇格の調査
- 04コンテナ環境でのクリプトジャッキング調査
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill analyzing-docker-container-forensicsインストール後、Claude Code で/analyzing-docker-container-forensicsを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdscripts/agent.py詳細
Docker コンテナフォレンジックの分析
使用するタイミング
- Docker コンテナまたはコンテナホストが侵害された場合の調査
- レジストリからプルした悪意のある Docker イメージの分析
- コンテナ化されたアプリケーションの侵害に関するインシデント対応
- コンテナエスケープの試みや権限昇格の調査
- コンテナ設定の監査と設定ミスの特定
前提条件
- フォレンジック用ワークステーションで Docker CLI にアクセスできること
- Docker ホストのファイルシステム(フォレンジックイメージまたは稼働中の環境)にアクセスできること
- Docker のレイヤー化ファイルシステム(overlay2、aufs)を理解していること
- イメージ分析用の dive、docker-explorer、または container-diff
- Docker デーモンの設定とソケットのセキュリティに関する知識
- コンテナイメージの脆弱性スキャン用の Trivy または Grype
ワークフロー
ステップ 1:コンテナの状態と証拠を保全する
# List all containers (including stopped)
docker ps -a --no-trunc > /cases/case-2024-001/docker/container_list.txt
# Inspect the compromised container
CONTAINER_ID="abc123def456"
docker inspect $CONTAINER_ID > /cases/case-2024-001/docker/container_inspect.json
# Export container filesystem as tarball (preserves current state)
docker export $CONTAINER_ID > /cases/case-2024-001/docker/container_export.tar
# Create an image from the container's current state
docker commit $CONTAINER_ID forensic-evidence:case-2024-001
docker save forensic-evidence:case-2024-001 > /cases/case-2024-001/docker/container_image.tar
# Capture container logs
docker logs $CONTAINER_ID --timestamps > /cases/case-2024-001/docker/container_logs.txt 2>&1
# Capture running processes (if container is still running)
docker top $CONTAINER_ID > /cases/case-2024-001/docker/container_processes.txt
# Capture network connections
docker exec $CONTAINER_ID netstat -tlnp 2>/dev/null > /cases/case-2024-001/docker/container_network.txt
# Copy specific files from the container
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
# Hash all exported evidence
sha256sum /cases/case-2024-001/docker/*.tar > /cases/case-2024-001/docker/evidence_hashes.txt
ステップ 2:コンテナイメージのレイヤーを分析する
# Install dive for image layer analysis
wget https://github.com/wagoodman/dive/releases/latest/download/dive_linux_amd64.deb
sudo dpkg -i dive_linux_amd64.deb
# Analyze image layers interactively
dive forensic-evidence:case-2024-001
# Non-interactive layer analysis
dive forensic-evidence:case-2024-001 --ci --json /cases/case-2024-001/docker/dive_analysis.json
# Extract and examine individual layers
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/
# List the image manifest and layer order
cat /cases/case-2024-001/docker/layers/manifest.json | python3 -m json.tool
# Examine each layer for changes
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
# Use container-diff to compare with original base image
# Install container-diff
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64
chmod +x container-diff-linux-amd64
# Compare committed image with original
./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
ステップ 3:Docker ホストのアーティファクトを調査する
# Docker data directory (default: /var/lib/docker/)
DOCKER_ROOT="/mnt/evidence/var/lib/docker"
# Examine overlay2 filesystem layers
ls -la $DOCKER_ROOT/overlay2/
# Find the container's merged filesystem
CONTAINER_HASH=$(docker inspect $CONTAINER_ID --format '{{.GraphDriver.Data.MergedDir}}' 2>/dev/null)
# Or manually from forensic image:
# Look in /var/lib/docker/containers/<container_id>/config.v2.json
# Analyze container configuration files
cat $DOCKER_ROOT/containers/$CONTAINER_ID/config.v2.json | python3 -m json.tool \
> /cases/case-2024-001/docker/container_config.json
# Check Docker daemon configuration
cat /mnt/evidence/etc/docker/daemon.json 2>/dev/null > /cases/case-2024-001/docker/daemon_config.json
# Examine Docker events log
cat $DOCKER_ROOT/containers/$CONTAINER_ID/*.log > /cases/case-2024-001/docker/container_json_logs.txt
# Check for volume mounts (potential host filesystem access)
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 SECURITY ANALYSIS ===\n")
# Check mounts
print("Volume Mounts:")
for mount in inspect.get('Mounts', []):
rw = "READ-WRITE" if mount.get('RW') else "READ-ONLY"
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" WARNING: Sensitive host path mounted read-write!")
# Check privileged mode
host_config = inspect.get('HostConfig', {})
if host_config.get('Privileged'):
print("\nWARNING: Container was running in PRIVILEGED mode!")
# Check capabilities
cap_add = host_config.get('CapAdd', [])
if cap_add:
print(f"\nAdded 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" WARNING: Dangerous capability: {cap}")
# Check PID namespace
if host_config.get('PidMode') == 'host':
print("\nWARNING: Container shares host PID namespace!")
# Check network mode
if host_config.get('NetworkMode') == 'host':
print("\nWARNING: Container shares host network namespace!")
# Check user
user = inspect.get('Config', {}).get('User', 'root (default)')
print(f"\nRunning as user: {user}")
# Check environment variables for secrets
env_vars = inspect.get('Config', {}).get('Env', [])
print(f"\nEnvironment Variables: {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" SENSITIVE: {key}=***REDACTED***")
PYEOF
ステップ 4:コンテナのファイルシステムの変更を分析する
# Compare container filesystem to original image
docker diff $CONTAINER_ID > /cases/case-2024-001/docker/filesystem_changes.txt
# A = Added, C = Changed, D = Deleted
# Analyze changes
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"Files Added: {len(added)}")
print(f"Files Changed: {len(changed)}")
print(f"Files Deleted: {len(deleted)}")
# Flag suspicious additions
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"\nSuspicious Added Files:")
for f in suspicious:
print(f" {f}")
# Flag suspicious changes
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"\nSuspicious Changed Files:")
for f in sus_changed:
print(f" {f}")
PYEOF
# Extract and examine the container export
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/
# Scan for webshells and malicious files
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
ステップ 5:脆弱性をスキャンしてレポートを作成する
# Scan the image for known vulnerabilities
trivy image forensic-evidence:case-2024-001 \
--format json \
--output /cases/case-2024-001/docker/vulnerability_scan.json
# Scan the exported filesystem
trivy fs /cases/case-2024-001/docker/container_fs/ \
--format table \
--output /cases/case-2024-001/docker/fs_vulnerabilities.txt
# Check for secrets in the image
trivy image forensic-evidence:case-2024-001 \
--scanners secret \
--format json \
--output /cases/case-2024-001/docker/secrets_scan.json
主な概念
| 概念 | 説明 |
|---|---|
| イメージレイヤー | コンテナイメージを構成する、積み重ねられた読み取り専用のファイルシステムレイヤー |
| overlay2 | レイヤーにユニオンファイルシステムを使用する Docker のデフォルトのストレージドライバー |
| コンテナの差分 | 実行時のファイルシステム変更と元のイメージとの比較 |
| 特権モード | ホストの機能を全面的に使用できるコンテナ(ほとんどの分離を迂回します) |
| Docker ソケット | Docker デーモンを制御する Unix ソケット(/var/run/docker.sock) |
| コンテナエスケープ | コンテナの分離を突破してホストに侵入する手法 |
| ボリュームマウント | コンテナ内からアクセスできるホストファイルシステムのパス |
| イメージ履歴 | 各レイヤーのビルドに使用された Dockerfile 命令の記録 |
ツールとシステム
| ツール | 用途 |
|---|---|
| docker inspect | コンテナの設定と状態に関する詳細情報 |
| docker diff | 実行中または停止中のコンテナで行われたファイルシステムの変更を表示 |
| dive | Docker イメージのレイヤーを対話的に分析するツール |
| container-diff | コンテナイメージの内容を比較する Google のツール |
| Trivy | コンテナイメージとファイルシステムの脆弱性スキャナー |
| docker-explorer | オフラインで Docker アーティファクトを分析するフォレンジックツール |
| Sysdig | コンテナのランタイムセキュリティ監視とフォレンジック |
| Falco | コンテナと Kubernetes のランタイム脅威検出 |
よくあるシナリオ
シナリオ 1:Web アプリケーションコンテナの侵害 コンテナのファイルシステムをエクスポートし、Web ルート内の Web シェルを特定して、アクセスログから悪用の試みを分析します。追加されたファイルや変更された設定を確認し、C2 通信のネットワーク接続を調査して、権限昇格につながるコンテナの機能を確認します。
シナリオ 2:悪意のあるイメージによるサプライチェーン攻撃 dive でイメージレイヤーを分析し、悪意のあるコンテンツが追加されたレイヤーを特定します。container-diff で公式ベースイメージと比較し、イメージ履歴に不審な RUN コマンドがないか確認して、埋め込まれたバックドアや暗号通貨マイナーをスキャンし、レジストリログからイメージのプルを追跡します。
シナリオ 3:コンテナエスケープの調査 コンテナが特権モードで実行されていたか、危険な機能を有効にしていたかを確認します。不正アクセスにつながるホストファイルシステムのマウントポイントを調べ、Docker-in-Docker の悪用を可能にする Docker ソケットのマウントを確認します。コンテナエスケープの兆候がないかホストシステムのログを分析し、カーネルエクスプロイトの痕跡を確認します。
シナリオ 4:コンテナ環境でのクリプトジャッキング CPU 使用率の高いコンテナを特定し、コンテナイメージをエクスポートしてマイニング用バイナリを分析します。レジストリ内に未承認のイメージがないか確認し、不正なデプロイがないかコンテナの作成イベントを調べ、マイニングプールとの通信に使われるネットワーク接続を調査します。
出力形式
Docker Container Forensics Summary:
Container: abc123def456 (nginx-app)
Image: company/web-app:v2.1
Status: Running (started 2024-01-10 09:00 UTC)
Host: docker-host-01.corp.local
Security Configuration:
Privileged: No
Capabilities Added: NET_ADMIN (WARNING)
Volume Mounts: /var/log -> /host-logs (RW)
Network Mode: bridge
User: root (WARNING)
Filesystem Changes:
Added: 23 files (5 suspicious)
Changed: 12 files (2 suspicious)
Deleted: 0 files
Suspicious Findings:
/tmp/reverse.sh - Reverse shell script (Added)
/var/www/html/.hidden/shell.php - PHP webshell (Added)
/etc/crontab - Modified (persistence cron entry added)
/root/.ssh/authorized_keys - Modified (unauthorized key added)
Vulnerability Scan:
Critical: 3 (CVE-2024-xxxx in base image)
High: 12
Medium: 34
Evidence: /cases/case-2024-001/docker/