| name | analyzing-docker-container-forensics |
| description | 通过分析镜像、层、卷、日志和运行时痕迹,调查受损的 Docker 容器,识别恶意活动和证据。 |
| domain | cybersecurity |
| subdomain | digital-forensics |
| tags | ["forensics","docker","container-forensics","container-security","image-analysis","runtime-investigation"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
分析 Docker 容器取证
适用场景
- 调查受损的 Docker 容器或容器主机时
- 分析从注册表拉取的恶意 Docker 镜像时
- 涉及容器化应用程序漏洞的事件响应(Incident Response)期间
- 检查容器逃逸尝试或权限提升(Privilege Escalation)时
- 审计容器配置并识别错误配置时
前置条件
- 取证工作站上的 Docker CLI 访问权限
- 访问 Docker 主机文件系统(取证镜像或实时系统)
- 了解 Docker 分层文件系统(overlay2、aufs)
- 用于镜像分析的 dive、docker-explorer 或 container-diff
- 了解 Docker 守护进程配置和 socket 安全
- 用于容器镜像漏洞扫描的 Trivy 或 Grype
工作流程
步骤 1:保全容器状态和证据
docker ps -a --no-trunc > /cases/case-2024-001/docker/container_list.txt
CONTAINER_ID="abc123def456"
docker inspect $CONTAINER_ID > /cases/case-2024-001/docker/container_inspect.json
docker export $CONTAINER_ID > /cases/case-2024-001/docker/container_export.tar
docker commit $CONTAINER_ID forensic-evidence:case-2024-001
docker save forensic-evidence:case-2024-001 > /cases/case-2024-001/docker/container_image.tar
docker logs $CONTAINER_ID --timestamps > /cases/case-2024-001/docker/container_logs.txt 2>&1
docker top $CONTAINER_ID > /cases/case-2024-001/docker/container_processes.txt
docker exec $CONTAINER_ID netstat -tlnp 2>/dev/null > /cases/case-2024-001/docker/container_network.txt
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
sha256sum /cases/case-2024-001/docker/*.tar > /cases/case-2024-001/docker/evidence_hashes.txt
步骤 2:分析容器镜像层
wget https://github.com/wagoodman/dive/releases/latest/download/dive_linux_amd64.deb
sudo dpkg -i dive_linux_amd64.deb
dive forensic-evidence:case-2024-001
dive forensic-evidence:case-2024-001 --ci --json /cases/case-2024-001/docker/dive_analysis.json
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/
cat /cases/case-2024-001/docker/layers/manifest.json | python3 -m json.tool
for layer in /cases/case-2024-001/docker/layers/*/layer.tar; do
echo "=== 层: $(dirname $layer | xargs basename) ==="
tar -tf "$layer" | head -20
echo "..."
done
curl -LO https://storage.googleapis.com/container-diff/latest/container-diff-linux-amd64
chmod +x container-diff-linux-amd64
./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_ROOT="/mnt/evidence/var/lib/docker"
ls -la $DOCKER_ROOT/overlay2/
CONTAINER_HASH=$(docker inspect $CONTAINER_ID --format '{{.GraphDriver.Data.MergedDir}}' 2>/dev/null)
cat $DOCKER_ROOT/containers/$CONTAINER_ID/config.v2.json | python3 -m json.tool \
> /cases/case-2024-001/docker/container_config.json
cat /mnt/evidence/etc/docker/daemon.json 2>/dev/null > /cases/case-2024-001/docker/daemon_config.json
cat $DOCKER_ROOT/containers/$CONTAINER_ID/*.log > /cases/case-2024-001/docker/container_json_logs.txt
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("=== 容器安全分析 ===\n")
print("卷挂载:")
for mount in inspect.get('Mounts', []):
rw = "读写" if mount.get('RW') else "只读"
print(f" {mount.get('Source', 'N/A')} -> {mount.get('Destination', 'N/A')} ({rw})")
if mount.get() (, , , ) and mount.get():
(f)
host_config = inspect.get(, {})
host_config.get():
()
cap_add = host_config.get(, [])
cap_add:
(f)
dangerous_caps = [, , , ]
cap_add:
dangerous_caps:
(f)
host_config.get() == :
()
host_config.get() == :
()
user = inspect.get(, {}).get(, )
(f)
env_vars = inspect.get(, {}).get(, [])
(f)
env_vars:
key = env.split()[0]
any(s key.upper() s [, , , , ]):
(f)
PYEOF
步骤 4:分析容器文件系统变更
docker diff $CONTAINER_ID > /cases/case-2024-001/docker/filesystem_changes.txt
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"新增文件: {len(added)}")
print(f"变更文件: {len(changed)}")
print(f"删除文件: {len(deleted)}")
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"\n可疑新增文件:")
for f in suspicious:
print(f" {f}")
sus_changed = [f for f in changed if any(s f s
[, , , , ])]
sus_changed:
(f)
f sus_changed:
(f)
PYEOF
-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/
find /cases/case-2024-001/docker/container_fs/tmp/ - f - file {} \;
find /cases/case-2024-001/docker/container_fs/ -name -newer /cases/case-2024-001/docker/container_fs/etc/hostname
步骤 5:扫描漏洞并生成报告
trivy image forensic-evidence:case-2024-001 \
--format json \
--output /cases/case-2024-001/docker/vulnerability_scan.json
trivy fs /cases/case-2024-001/docker/container_fs/ \
--format table \
--output /cases/case-2024-001/docker/fs_vulnerabilities.txt
trivy image forensic-evidence:case-2024-001 \
--scanners secret \
--format json \
--output /cases/case-2024-001/docker/secrets_scan.json
核心概念
| 概念 | 定义 |
|---|
| 镜像层(Image layers) | 堆叠形成容器镜像的只读文件系统层 |
| overlay2 | 使用联合文件系统实现层的默认 Docker 存储驱动 |
| 容器差异(Container diff) | 运行时文件系统变更与原始镜像的比较 |
| 特权模式(Privileged mode) | 拥有完整主机能力的容器(绕过大多数隔离) |
| Docker socket | 控制 Docker 守护进程的 Unix socket(/var/run/docker.sock) |
| 容器逃逸(Container escape) | 从容器隔离中突破到主机的技术 |
| 卷挂载(Volume mounts) | 在容器内可访问的主机文件系统路径 |
| 镜像历史(Image history) | 用于构建每个层的 Dockerfile 指令记录 |
工具与系统
| 工具 | 用途 |
|---|
| docker inspect | 详细的容器配置和状态信息 |
| docker diff | 显示运行中/已停止容器中的文件系统变更 |
| dive | 交互式 Docker 镜像层分析工具 |
| container-diff | 用于比较容器镜像内容的 Google 工具 |
| Trivy | 容器镜像和文件系统的漏洞扫描器 |
| docker-explorer | 用于离线 Docker 痕迹分析的取证工具 |
| Sysdig | 容器运行时安全监控和取证 |
| Falco | 用于容器和 Kubernetes 的运行时威胁检测 |
常见场景
场景:Web 应用程序容器被入侵
导出容器文件系统,识别 Web 根目录中的 Webshell,分析访问日志中的利用尝试,检查新增文件和被修改的配置,检查用于 C2 通信的网络连接,审查容器能力以发现提权路径。
场景:通过恶意镜像实施供应链攻击(Supply Chain Attack)
使用 dive 分析镜像层以识别哪一层添加了恶意内容,使用 container-diff 与官方基础镜像进行比较,检查镜像历史中可疑的 RUN 命令,扫描嵌入的后门和加密货币矿工,从注册表日志追踪镜像拉取。
场景:容器逃逸调查
检查容器是否以特权或危险能力运行,检查主机文件系统挂载点是否有未经授权的访问,审查启用 Docker-in-Docker 滥用的 Docker socket 挂载,分析主机系统日志中的容器逃逸指标,检查内核利用痕迹。
场景:容器环境中的加密劫持(Cryptojacking)
识别高 CPU 占用的容器,导出并分析容器镜像中的挖矿二进制文件,检查注册表中是否有未授权镜像,审查容器创建事件中的流氓部署,检查用于矿池通信的网络连接。
输出格式
Docker 容器取证摘要:
容器: abc123def456 (nginx-app)
镜像: company/web-app:v2.1
状态: 运行中(启动于 2024-01-10 09:00 UTC)
主机: docker-host-01.corp.local
安全配置:
特权模式: 否
已添加能力: NET_ADMIN(警告)
卷挂载: /var/log -> /host-logs(读写)
网络模式: bridge
运行用户: root(警告)
文件系统变更:
新增: 23 个文件(5 个可疑)
变更: 12 个文件(2 个可疑)
删除: 0 个文件
可疑发现:
/tmp/reverse.sh - 反向 shell 脚本(新增)
/var/www/html/.hidden/shell.php - PHP Webshell(新增)
/etc/crontab - 已修改(添加了持久化 cron 条目)
/root/.ssh/authorized_keys - 已修改(添加了未授权密钥)
漏洞扫描:
严重: 3 个(基础镜像中的 CVE-2024-xxxx)
高危: 12 个
中危: 34 个
证据: /cases/case-2024-001/docker/