服务器被植入挖矿程序:一次完整的排查与清理实战
前言
某天早上,我像往常一样检查服务器状态,却发现了一个异常现象:服务器的内存占用突然飙升到了异常高的水平。要知道,我的服务器上只部署了一个简单的静态网站,平时内存占用一直很低。这个反常的现象立刻引起了我的警觉。
经过初步排查,我发现服务器被植入了挖矿程序:
- 恶意进程 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 | 系统分配的唯一标识符 |
| %CPU | CPU 占用率 | 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 识别可疑进程
从输出中可以看到几个明显的异常:
- 进程伪装:
/var/tmp/.kworker/httpd伪装成系统进程httpd(Apache 服务),但 CPU 占用高达 89.2%,这显然不正常 - 矿池连接:第二个进程直接暴露了连接到门罗币矿池的命令行参数
- 异常位置:正常的系统进程不会放在
/var/tmp这样的临时目录中
正常情况下的预期:
- 系统进程(如 sshd、systemd)的 CPU 占用应该很低
- 不应该看到连接矿池的进程
- 不应该看到
client、kworker、httpd这样的可疑进程
第二步:紧急处理
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 发现第二波可疑进程
杀死第一批进程后,我再次检查系统,发现了另外两个可疑进程:
可疑特征:
- 进程名拼写错误(
rxz而不是常见的系统进程名) - 使用相对路径启动(
./rxz),说明隐藏在某个目录中 - 启动时间比我发现挖矿程序的时间更早
- 暂时没有矿池连接,可能是定时激活的后门程序
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 地址
- 异常的登录时间(如凌晨)
- 登录失败后成功的记录
如果发现可疑登录,需要:
- 立即修改 root 密码
- 禁用密码登录,改用密钥认证
- 配置防火墙限制 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 用户。
总结与预防
事件回顾
这次入侵事件的完整攻击链:
- 初始入侵:攻击者通过apache2的UID 0获得服务器访问权限
- 植入后门:1 月 27 日植入
rxz后门程序 - 下载挖矿程序:后门程序下载挖矿程序到
/var/tmp/.kworker/ - 建立持久化:通过 crontab 定时任务确保程序重启
- 伪装运行:挖矿程序伪装成系统进程
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
最后的建议
- 定期更新系统:
apt update && apt upgrade - 最小权限原则:不要用 root 运行应用
- 备份重要数据:定期备份,以防万一
- 监控异常:关注 CPU、内存、网络流量的异常波动
- 保持警惕:任何异常都值得深入调查
服务器安全是一个持续的过程,而不是一次性的任务。希望这次经历能为大家提供参考,共同维护服务器安全。
更多服务器安全设置请查看我的另一篇文章: Ubuntu 服务器安全加固完全指南:从小白到入门