一次 Docker 容器被植入挖矿病毒的排查与复盘


1. 事件背景与异常发现

事件发生在一台部署了 Docker 服务的 NAS 服务器上。系统长期运行平稳,但近日发现系统负载(Load Average)异常飙升,长期维持在 18 以上,导致其他服务(如 Dockerd, QEMU)响应变慢。

通过 top 命令查看系统进程,发现以下异常特征:

  • 异常进程名:两个名为 hash 的进程长期驻留。

  • 资源占用:CPU 占用率高达 450%(多核累加),但单核线程似乎被限制在 80% 左右,未完全跑死系统。

  • 用户权限:进程以 root 权限运行。

2. 排查过程

2.1 定位进程实体

首先通过 PID(32691)定位进程的实体文件位置和启动参数:

ls -l /proc/32691/exe
# 结果指向:/app/hash

cat /proc/32691/cmdline
# 关键参数:-o auto.c3pool.org:13333 -u <钱包地址> --cpu-max-threads-hint=80 --randomx

分析结论

  1. 进程是一个典型的 Monero (门罗币) 挖矿程序,使用 RandomX 算法。

  2. --cpu-max-threads-hint=80 参数解释了为何系统没有完全死机,这是病毒为了隐蔽自身、防止被管理员因卡顿察觉而设置的阈值。

  3. 路径 /app/hash 提示该进程极有可能运行在某个 Docker 容器内部。

2.2 溯源容器

由于 Docker 容器众多,需要精准定位宿主进程属于哪个容器。通过 cgroup 信息进行反查:

cat /proc/32691/cgroup
# 结果包含:docker-598de3114457...

通过 Container ID 598de3114457 比对 docker ps 列表,锁定目标容器为 nano-board

这是一个我自己开发的简易服务器状态面板应用。

2.3 提取样本与取证

在停止容器但未删除的情况下,通过 docker cp 将病毒样本提取至宿主机进行分析:

  • 文件属性:7MB 大小,ELF 64-bit LSB executable,静态链接(statically linked),去除了符号表(stripped)。

  • 时间戳分析

    • Modify 时间为 2023-11-23,证明这是一个现成的、通用的 XMRig 二进制文件,而非本地编译。

    • 通过 NAS 历史性能曲线与进程运行时间(9d+8h)推断,入侵时间点精确锁定在 12月1日

  • VirusTotal 检测:样本哈希值 364a7f8e... 在 VirusTotal 上检出率为 42/66,确认为 Trojan.Linux.Miner.XMRig

3. 入侵原因分析 (Root Cause Analysis)

核心问题:为何我自己写的软件会被黑?

经过复盘,攻击路径清晰如下:

  1. 暴露面扩大:12月1日,我申请并获得了动态公网 IP,并通过内网穿透工具将 nano-board 的端口直接暴露在了公网。

  2. 安全漏洞

    • 鉴权薄弱:服务可能存在弱口令或鉴权逻辑漏洞。

    • RCE 隐患:应用代码中可能存在命令执行(Remote Code Execution)漏洞(如不安全的 exec() 调用),导致黑客可以通过 API 注入 Shell 命令。

  3. 权限过高:Docker 容器默认以 root 用户运行。一旦黑客利用漏洞进入,即获得容器内的 Root 权限,可以随意使用 wget 下载病毒并赋予执行权限 (chmod +x)。

OverlayFS 机制注记:

病毒文件 /app/hash 位于 Docker 的 Copy-on-Write 层(读写层),并未挂载到宿主机 volume。因此,直接查看宿主机挂载目录无法找到病毒文件,必须在容器运行时或通过 docker inspect 查找 UpperDir 才能看到。

4. 损害评估与安全加固

为防止病毒逃逸(Container Escape),对宿主机进行了全面体检:

  1. SSH 后门:检查 /root/.ssh/authorized_keys,未发现异常公钥。

  2. 持久化后门:检查 crontab -l/etc/crontab/etc/cron.d/,未发现恶意定时任务。

  3. Docker API:检查 2375 端口,确认为关闭状态,未暴露。

结论:此次攻击属于典型的应用层入侵,病毒被成功隔离在容器内部,未对宿主机造成实质性渗透。

5. 解决方案与后续措施

  1. 清理现场

    • 提取样本留存后(用于分析),彻底删除病毒文件。

    • 强制删除染毒容器及镜像:docker rm -f nano-board && docker rmi ...

  2. 代码修复

    • 审查代码中的命令执行逻辑,移除或加固所有 exec 调用。

    • 增加强制的 HTTP Basic Auth 或 Token 验证。

  3. 最佳实践落地

    • 修改 Dockerfile,添加 USER node 指令,禁止容器以 Root 身份运行。

    • 收缩公网暴露面,改用 VPN (如 WireGuard/EasyTier) 或 Nginx 反向代理访问内网服务。

6. 总结

这次经历是一堂生动的 DevSecOps 课。公网 IP 是一把双刃剑,在享受便利的同时,必须时刻警惕“黑暗森林”中的自动化扫描脚本。对于个人开发者而言,“能跑就行”的代码在公网环境下往往意味着“漏洞百出”

教训: 永远不要信任用户输入,永远遵循最小权限原则(Least Privilege)。



一次 Docker 容器被植入挖矿病毒的排查与复盘
https://blog.zeges.top/archives/8uAeq44%21ZbDK
作者
Zege
发布于
2025年12月10日
许可协议