一次意外:打开局域网里另一台备用服务器想重新部署系统,结果机器上没跑任何业务,CPU 却常驻 99%——被当矿机了。这篇是当时排查过程的复盘,外加后来总结的守护进程溯源通用方法。
0x01 排查三板斧:top 看不到就换工具
① 为什么 top 看不到进程:木马动了 /etc/ld.so.preload,强制所有动态链接程序加载 sshdD.so——top/ps/ls 调用的 libc 函数(readdir 一类)被劫持,看到的进程列表是过滤后的。这正是”rootkit 级隐藏”的标准姿势:不是进程不在,是”展示层”被换了。
② busybox 是静态编译的,不走 ld.so.preload 的动态加载链路,所以 busybox top 看到的是真实进程列表——应急机里常备 busybox 的理由。
③ 持久化必在启动项:进程可以藏,开机总要自启。crontab -l 一眼命中:
@reboot /var/log/log > /dev/null 2>&1 & disown
/var/log/log 伪装成日志文件的二进制可执行文件——file 一验即穿。丢沙箱跑行为:连接矿池、下载更新、篡改 ld.so.preload,链路齐活。
0x02 清理清单(对应劫持型木马)
顺序很重要——先断持久化再杀进程,否则看门狗会拉起:
# 1. 切断自启与 preload(恢复展示层)
crontab -r # 或编辑删除 @reboot 行;再排查 /etc/cron.*、systemd timer
echo > /etc/ld.so.preload # 清空强制预加载(先 mv 备份取证)
rm -f /var/log/log # 删载荷(先留副本)
# 2. 杀进程树
busybox top # 拿真实 PID
kill -9 <pid> # 杀不掉查 /proc/<pid>/exe 是否为已删除文件(挂载型)
# 3. 排查同类落点 + 复盘入口
grep -rE "curl|wget|base64" /etc/cron* /var/spool/cron/
last ; cat /root/.bash_history ; cat /var/log/secure | grep Accepted
和应急响应篇的原则一致:断网+杀毒不是应急,回答”怎么进来的、还有没有同类后门”才算。
0x03 进阶:用 auditd 抓”守护进程”的真身
清理时常见一个困境:某个恶意文件(比如 abc)被反复拉起,杀掉又复活——是谁在守护它?通用溯源方法:
# 1. 定位文件真实路径
ls -l /proc/$(pgrep abc)/exe
# 2. 加 audit 规则监控"执行"动作
auditctl -w /tmp/.hidden/abc -p x -k abc_execution
# 3. 等它再次被拉起,读日志
ausearch -k abc_execution -ts recent
日志关键字段是 ppid(父进程 ID):
type=SYSCALL ... ppid=1234 pid=5678 ... comm="bash" exe="/usr/bin/bash" key="abc_execution"
顺藤摸瓜:ps -fp 1234 → /proc/1234/exe → cat /proc/1234/cmdline——守护进程现形(常见落点:被篡改的系统服务、另一个 cron、rc.local、被替换的 sshd)。
0x04 反思
这台机器的入侵入口大概率是弱口令/老漏洞(不是本文重点),但两条预防措施是通用的:/etc/ld.so.preload 纳入文件完整性监控(它被改写等于展示层失守);应急工具箱常备静态编译的 busybox/lsof。攻防的差距往往就在”谁的工具不依赖被污染的运行环境”。