服务器被植入挖矿程序:一次完整的排查与清理实战

115 阅读13分钟

服务器被植入挖矿程序:一次完整的排查与清理实战

前言

某天早上,我像往常一样检查服务器状态,却发现了一个异常现象:服务器的内存占用突然飙升到了异常高的水平。要知道,我的服务器上只部署了一个简单的静态网站,平时内存占用一直很低。这个反常的现象立刻引起了我的警觉。

经过初步排查,我发现服务器被植入了挖矿程序:

  • 恶意进程 PID 1969760/var/tmp/.kworker/httpd(伪装成系统进程)
  • 恶意进程 PID 1949350/1949421:连接到门罗币矿池 xmr.nanopool.org:14433
  • 资源占用:CPU 占用高达 89%,内存占用超过 25%,已持续运行 4.5 小时

这是一次典型的服务器入侵事件。接下来,我将详细记录整个排查和清理过程,希望能为遇到类似问题的朋友提供参考。


第一步:发现异常进程

1.1 查看系统资源占用

首先,我们需要确认哪些进程在消耗系统资源。使用以下命令查看 CPU 占用最高的进程:

# 查看当前 CPU 占用最高的进程
ps aux --sort=-%cpu | head -n 10

执行后,我看到了这样的输出:

USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root     1969760 89.2 13.1 652040 265028 ?       Ssl  03:45 269:42 /var/tmp/.kworker/httpd
root     1949350  0.8 12.3 311100 248192 ?       Sl   Jan30   4:38 ./client -o xmr.nanopool.org:14433 -u 46thqyYPQnWNErt2C8TjQJUCXvrDEX1YNGT6EeGjvtY1iCKmHkR25UJewuyyagGzUeEiu98RZkFzZQMHpJX4ijKbMs2wAQw.lenux -k --tls --donate-level 1
do-agent 1969492  0.6 10.9 1383936 221464 ?      Ssl  03:43   1:58 mysqld

1.2 理解输出信息

让我们解读一下这些字段的含义:

字段含义示例说明
USER运行进程的用户root 表示以管理员权限运行
PID进程 ID系统分配的唯一标识符
%CPUCPU 占用率89.2 表示占用 89.2% 的 CPU
%MEM内存占用率13.1 表示占用 13.1% 的物理内存
VSZ虚拟内存大小单位为 KB
RSS实际物理内存单位为 KB,真正占用的内存
TTY终端类型? 表示后台进程,pts/0 表示伪终端
STAT进程状态R=运行中,S=睡眠,D=等待I/O,Z=僵尸进程
START启动时间Jan30 表示 1 月 30 日启动
TIME累计 CPU 时间269:42 表示运行了 269 小时 42 分钟
COMMAND启动命令完整的命令行

进程状态(STAT)详解

  • R:Running,运行中
  • S:Sleeping,可中断睡眠
  • D:Disk sleep,不可中断睡眠,通常在等待 I/O
  • Z:Zombie,僵尸进程
  • T:Stopped,已停止
  • s:会话领导者(session leader)
  • l:多线程进程
  • +:前台进程组
  • <:高优先级进程
  • N:低优先级进程

1.3 识别可疑进程

从输出中可以看到几个明显的异常:

  1. 进程伪装/var/tmp/.kworker/httpd 伪装成系统进程 httpd(Apache 服务),但 CPU 占用高达 89.2%,这显然不正常
  2. 矿池连接:第二个进程直接暴露了连接到门罗币矿池的命令行参数
  3. 异常位置:正常的系统进程不会放在 /var/tmp 这样的临时目录中

正常情况下的预期

  • 系统进程(如 sshd、systemd)的 CPU 占用应该很低
  • 不应该看到连接矿池的进程
  • 不应该看到 clientkworkerhttpd 这样的可疑进程

第二步:紧急处理

2.1 立即终止恶意进程

发现恶意进程后,第一步是立即终止它们:

# 强制终止进程(替换为实际的 PID)
kill -9 1969760
kill -9 1949350
kill -9 1949421

命令说明

  • kill:终止进程的命令
  • -9:发送 SIGKILL 信号,强制终止,无法被进程拦截
  • 后面的数字是进程的 PID,要仔细查看有哪些进程不正常,全部杀死

⚠️ 重要提醒:仅仅杀死进程是不够的!恶意程序通常会通过定时任务、系统服务等方式自动重启,所以我们需要继续深入排查。

2.2 删除恶意文件

根据进程信息,我找到了恶意文件的位置:/var/tmp/.kworker/httpd

# 删除恶意文件目录(请务必确认路径正确!)
rm -rf /var/tmp/.kworker/
rm -rf /var/tmp/httpd

⚠️ 危险操作警告rm -rf 命令会永久删除文件,无法恢复。请仔细检查路径,确保不会误删重要文件。

2.3 查找其他隐藏文件

攻击者常常会在临时目录中隐藏多个恶意文件(以 . 开头的隐藏文件):

# 在常见的临时目录中查找隐藏文件
find /var/tmp /tmp /dev/shm -name ".*" -type f 2>/dev/null

如果发现可疑文件,使用 rm -f 命令删除。

2.4 检查矿池连接

确认是否还有进程在连接矿池:

# 搜索与矿池相关的网络连接
netstat -antp | grep -E "(nanopool|xmr|mining|pool)"

如果没有输出,说明当前没有活跃的矿池连接。


第三步:深度排查

3.1 发现第二波可疑进程

杀死第一批进程后,我再次检查系统,发现了另外两个可疑进程:

进程列表截图

可疑特征

  1. 进程名拼写错误(rxz 而不是常见的系统进程名)
  2. 使用相对路径启动(./rxz),说明隐藏在某个目录中
  3. 启动时间比我发现挖矿程序的时间更早
  4. 暂时没有矿池连接,可能是定时激活的后门程序

3.2 定位可疑程序

通过 /proc 文件系统,我们可以追踪进程的详细信息:

# 查看进程的可执行文件路径
ls -l /proc/1822032/exe

# 查看进程的工作目录
ls -l /proc/1822032/cwd

# 查看完整的启动命令
cat /proc/1822032/cmdline | tr '\0' ' ' && echo

执行结果显示:

进程详情

关键发现

  • 程序位于 /root/rxz
  • 以 root 权限运行
  • 情况已经很严重,攻击者获得了最高权限

3.3 分析恶意文件

查看文件的详细信息:

# 查看文件属性
ls -lh /root/rxz
stat /root/rxz

# 查看文件类型
file /root/rxz

文件详情

分析结果

  • 文件大小:2.6MB 的二进制可执行文件
  • 植入时间:1 月 27 日(比挖矿进程更早)
  • 技术特征:静态编译 + 符号表剥离(这是攻击者的反取证手段)

结论:这很可能是一个后门程序下载器,负责下载和启动挖矿程序。


第四步:清除持久化机制

恶意程序要想长期存活,必须设置自动启动机制。我们需要逐一排查。

4.1 检查定时任务(Crontab)

定时任务是最常见的持久化方式:

# 查看当前用户的定时任务
crontab -l

# 查看系统级定时任务
cat /etc/crontab
ls -la /etc/cron.d/

我发现了恶意定时任务:

定时任务

恶意任务内容

0 */2 * * * /var/tmp/.kworker/kworkerd >/dev/null 2>&1

这个任务每 2 小时执行一次,试图启动挖矿程序。虽然我们已经删除了程序文件,但定时任务还在,可能会重新下载恶意程序。

4.2 删除恶意定时任务

# 编辑定时任务
crontab -e

执行后会看到编辑器选择界面:

编辑器选择

选择 nano 编辑器(输入 1),找到恶意任务行并删除,然后按 Ctrl+X 保存退出。

验证删除结果:

# 确认恶意任务已删除
crontab -l

验证结果

看到的是 crontab 中删除恶意任务后的其他内容即可。


4.3 检查系统服务(Systemd)

除了定时任务,攻击者还可能创建系统服务:

# 列出正在运行的服务,过滤掉常见系统服务
systemctl list-units --type=service --state=running | grep -v -E "(systemd|dbus|ssh|cron|rsyslog|network|ufw|unattended|polkit|accounts|udisks|snapd)"

输出示例:

服务列表

字段说明

字段含义可能的值
UNIT服务单元名称apache2.service、docker.service 等
LOAD配置文件加载状态loaded(已加载)、not-found(未找到)
ACTIVE高层级激活状态active(活动)、inactive(未活动)
SUB低层级运行状态running(运行中)、exited(已退出)
DESCRIPTION服务描述服务的功能说明

仔细检查列表中不熟悉的服务名称。

4.4 检查可疑服务

如果发现可疑服务,查看其配置:

# 查看服务配置文件
systemctl cat <服务名>

例如:

systemctl cat site_total.service

服务配置

检查 ExecStart 字段,看它启动的是什么程序。

4.5 分析可疑程序

如果服务启动的程序看起来可疑,进一步检查:

# 查看程序文件详情
ls -lh /path/to/program
file /path/to/program

# 查看目录内容
ls -la /path/to/directory/

以我的 site_total 为例:

ls -lh /www/server/site_total/site_total
file /www/server/site_total/site_total
ls -la /www/server/site_total/

程序详情

可疑特征

  • 文件较大(如 11MB)
  • 符号表被剥离(与 rxz 相同的反取证手段)
  • 位于不寻常的目录

4.6 检查网络连接

确认程序是否在连接外部服务器:

# 检查程序的网络连接
netstat -antp | grep <程序名>

# 查看程序的数据目录
ls -la /path/to/data/

例如:

netstat -antp | grep site_total
ls -la /www/server/site_total/data/

网络连接

如果不确定程序的用途,可以查看其配置文件或日志:

# 查看文件内容(前 20 行)
head -n 20 /www/server/site_total/data/tips.txt

如果发现程序确实是恶意的,直接删除整个目录即可。

4.7 检查其他持久化位置

攻击者还可能在启动脚本中设置自启动:

# 检查开机自启动脚本
cat /etc/rc.local 2>/dev/null || echo "rc.local不存在"

# 检查用户登录脚本
grep -E "(rxz|kworker|xmr|nanopool)" /root/.bashrc /root/.bash_profile /root/.profile 2>/dev/null || echo "未发现可疑内容"

启动脚本检查

如果不存在开机自启动脚本,会显示相应提示。


第五步:彻底清理

5.1 终止进程并删除文件

经过上述排查,确认所有恶意程序后,执行清理:

# 终止 rxz 进程
kill -9 1822032 1822033

# 确认进程已终止
ps aux | grep rxz | grep -v grep

# 删除 rxz 文件
rm -f /root/rxz

# 确认文件已删除
ls -l /root/rxz

删除确认

看到 "No such file or directory" 表示删除成功。

5.2 全面扫描临时目录

在临时目录中查找最近创建的可执行文件:

# 查找最近 7 天创建的可执行文件
find /tmp /var/tmp -type f -executable -mtime -7 2>/dev/null

如果没有输出,说明临时目录已清理干净。


第六步:溯源分析

6.1 检查 SSH 登录日志

由于恶意程序获得了 root 权限,我怀疑是通过 SSH 入侵的:

# 查看最近的 SSH 登录记录
last -n 20

重点关注

  • 陌生的 IP 地址
  • 异常的登录时间(如凌晨)
  • 登录失败后成功的记录

如果发现可疑登录,需要:

  1. 立即修改 root 密码
  2. 禁用密码登录,改用密钥认证
  3. 配置防火墙限制 SSH 访问

6.2 检查数据库服务

Redis 和 MySQL 如果配置不当,也可能成为入侵入口:

# 检查 Redis 是否绑定到公网
grep "^bind" /www/server/redis/redis.conf

# 检查 Redis 是否设置了密码
grep "^requirepass" /www/server/redis/redis.conf

安全配置

  • bind 127.0.0.1:只允许本地访问(安全)
  • bind 0.0.0.0:允许所有 IP 访问(危险)
  • 必须设置强密码(requirepass

如果返回 127.0.0.1,说明是本地绑定,配置安全。

6.3 检查重复 UID 0(高危漏洞)

什么是 UID 0?

UID(User ID)是 Linux 系统中每个用户的唯一标识符。其中 UID 0 是 root 用户的专属 ID,拥有系统最高权限。

为什么重复 UID 0 很危险?

如果有其他用户(比如 apache2)也拥有 UID 0,那它就等同于 root,可以执行任何操作。这就像给了攻击者一把系统的万能钥匙。

在我这次的入侵事件中,攻击者就是通过将 apache2 用户的 UID 修改为 0,从而获得了 root 权限,进而植入挖矿程序。

检查和修复步骤

第 1 步:检查哪些用户的 UID 为 0

# 查找所有 UID 为 0 的用户
grep ":0:" /etc/passwd

正常输出:应该只有一行

root:x:0:0:root:/root:/bin/bash

⚠️ 异常情况:如果看到其他用户(如 apache2、www-data 等),说明存在安全漏洞。


第 2 步:检查异常用户是否有进程在运行

# 检查是否有进程在使用该用户(以 apache2 为例)
ps aux | grep apache2 | head -n 5

如果没有输出,说明没有进程在使用,可以安全删除。


第 3 步:备份并删除异常用户

⚠️ 重要提醒:修改系统用户文件前,务必先备份!

# 备份原文件
sudo cp /etc/passwd /etc/passwd.backup
sudo cp /etc/shadow /etc/shadow.backup

# 删除异常用户(以 apache2 为例)
sudo sed -i '/^apache2:/d' /etc/passwd
sudo sed -i '/^apache2:/d' /etc/shadow

命令说明

  • sed -i:直接修改文件
  • /^apache2:/d:删除以 apache2 开头的行
  • 需要同时删除 /etc/passwd/etc/shadow 中的记录

第 4 步:验证修复结果

# 再次检查 UID 0 的用户
grep ":0:" /etc/passwd

预期结果:应该只剩下 root 用户。


总结与预防

事件回顾

这次入侵事件的完整攻击链:

  1. 初始入侵:攻击者通过apache2的UID 0获得服务器访问权限
  2. 植入后门:1 月 27 日植入 rxz 后门程序
  3. 下载挖矿程序:后门程序下载挖矿程序到 /var/tmp/.kworker/
  4. 建立持久化:通过 crontab 定时任务确保程序重启
  5. 伪装运行:挖矿程序伪装成系统进程 httpd,连接矿池挖矿

预防措施

为了避免类似事件再次发生,建议采取以下措施:

1. 加固 SSH 安全
# 编辑 SSH 配置
vi /etc/ssh/sshd_config

关键配置:

# 禁用密码登录
PasswordAuthentication no

# 禁用 root 直接登录
PermitRootLogin no

# 只允许密钥认证
PubkeyAuthentication yes

# 修改默认端口(可选)
Port 2222

重启 SSH 服务:

systemctl restart sshd
2. 配置防火墙
# 只允许特定 IP 访问 SSH
ufw allow from <你的IP> to any port 22
ufw enable
3. 加固数据库

Redis

# 绑定到本地
bind 127.0.0.1

# 设置强密码
requirepass <复杂密码>

# 禁用危险命令
rename-command FLUSHALL ""
rename-command FLUSHDB ""

MySQL

# 只监听本地
bind-address = 127.0.0.1

# 删除匿名用户
DELETE FROM mysql.user WHERE User='';

# 禁止 root 远程登录
DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1');
4. 定期安全检查

创建监控脚本:

#!/bin/bash
# 检查异常进程
ps aux --sort=-%cpu | head -n 5

# 检查网络连接
netstat -antp | grep -E "(xmr|mining|pool)"

# 检查定时任务
crontab -l

# 检查最近登录
last -n 10

设置每日自动检查:

# 添加到 crontab
0 9 * * * /path/to/security-check.sh | mail -s "服务器安全检查" your@email.com
5. 安装入侵检测工具
# 安装 fail2ban(防止暴力破解)
apt install fail2ban

# 安装 rkhunter(rootkit 检测)
apt install rkhunter
rkhunter --update
rkhunter --check

最后的建议

  1. 定期更新系统apt update && apt upgrade
  2. 最小权限原则:不要用 root 运行应用
  3. 备份重要数据:定期备份,以防万一
  4. 监控异常:关注 CPU、内存、网络流量的异常波动
  5. 保持警惕:任何异常都值得深入调查

服务器安全是一个持续的过程,而不是一次性的任务。希望这次经历能为大家提供参考,共同维护服务器安全。

更多服务器安全设置请查看我的另一篇文章: Ubuntu 服务器安全加固完全指南:从小白到入门