容器带来的第二层持久化
宿主机跑 Docker 时,持久化面要多算一层:容器可以带重启策略在宿主机重启后自动拉起,容器内还可以再藏 cron、进程与凭据。攻击者常用「陌生镜像 + 特权模式 + 挂载宿主目录」的组合,从容器内直接操作宿主机。
排查思路
先枚举全部容器(含已停止的),再看每个容器的重启策略、特权标志与挂载点,最后进容器看内部的自启项与进程。已停止但策略为 always 的容器会在重启后回来,只看运行中容器会漏掉它。
基本信息
| 容器清单 | docker ps -a 列出包括已停止的全部容器 |
|---|---|
| 关键配置 | RestartPolicy、Privileged、CapAdd、Mounts |
| 镜像线索 | 陌生镜像与本地 docker build 痕迹 |
| 高危挂载 | 挂载 / 或 docker.sock 等于宿主机控制权 |
| 日志 | docker logs 与容器内 crontab 记录 |
| 适用平台 | Linux 主机上的 Docker 及兼容运行时 |
典型使用场景
- 排查「宿主机重启后异常进程自动回归」的容器来源
- 确认是否有运维范围之外的容器被部署
- 识别特权容器与挂载宿主根目录的高危配置
- 在容器内排查 CPU 异常占用(挖矿常见形态)
- 事件收尾时决定哪些容器保留、哪些需要重建
枚举容器与关键配置
枚举容器与关键配置
docker ps -a --format 'table {{.Names}}\t{{.Image}}\t{{.Status}}'
docker inspect $(docker ps -aq) --format '{{.Name}} priv={{.HostConfig.Privileged}} restart={{.HostConfig.RestartPolicy.Name}}'
docker inspect --format '{{json .Mounts}}' suspicious_container | head -c 500
docker inspect --format '{{json .Config.Cmd}} {{json .Config.Entrypoint}}' suspicious_container
docker images | head -n 20
docker diff suspicious_container | head -n 30 # 相对镜像的文件改动输出逐列读法
| 字段 | 含义 | 正常/异常 |
|---|---|---|
| Status | 容器运行状态 | 已停止但策略为 always 的容器重启后会回来 |
| Privileged | 特权模式标志 | true 时容器内几乎等价于宿主机 root |
| RestartPolicy | 重启策略 | always 与 unless-stopped 是常用持久化手段 |
| Mounts | 挂载点 | 出现 /、/etc、/root 或 docker.sock 需重点核查 |
取证顺序是先 docker inspect 与 docker logs 导出配置和日志,再 stop 容器;直接 docker rm 会把容器配置、日志与文件层一起删掉。
宿主机 Docker 套接字(docker.sock)挂进容器等于交出 Docker 控制权,发现这类挂载要按宿主机失陷处理,而不是只清容器。
进入容器复核内部持久化
进入容器复核内部持久化
docker exec -it suspicious_container sh -c 'crontab -l 2>/dev/null; ps -ef | head -n 20'
docker exec -it suspicious_container sh -c 'ls -la /etc/cron.d /etc/cron.hourly 2>/dev/null'
docker top suspicious_container # 查看容器内进程与宿主侧 PID 对应处置顺序建议
- 先导出 inspect 与 logs 作为证据
- 再停容器并观察宿主机是否出现替代进程
- 清理宿主侧对应的 systemd 单元与 cron 残留
- 确认镜像与容器来源无正当用途后再删除