1.4.3 SSRF进阶
1.无回显SSRF
无回显SSRF即我们无法看到通过SSRF请求的结果,这样就极大减少了SSRF的攻击面。下面介绍当碰到无回显SSRF时,我们如何利用。
先看看如何判断SSRF漏洞是否存在。我们可以先在自己的服务器上用Netcat工具监听某个端口,然后通过SSRF去请求。如果我们的服务器收到请求了,说明存在SSRF。如果未收到,也不能判断其不存在,还需要考虑目标机器不出网的情况,如图1-108所示。
也可以通过DNSLOG去探测SSRF。
虽然没有回显,但是我们还是能够通过一些别的信息去判断探测的结果,比如状态码、响应时间或者页面上的某一个特征。
图1-108 Netcat接收请求
在没有回显的情况下攻击内网的某些服务,如Redis,盲打内网的应用和服务。因为没有回显,所以很难判断我们构造的Payload是否攻击成功了。
2.攻击有认证的Redis服务
前面说到SSRF可以攻击内网无认证的Redis服务。如果碰到有认证的Redis服务,还能通过SSRF去利用吗?答案是可以。虽然SSRF每次只能发送一个数据包,无法保持登录状态,但是Redis使用的是RESP(Redis序列化协议),Redis客户端支持管道操作,可以通过单个写入操作发送多个命令,而无须在发出下一条命令之前读取上一条命令的服务器回复,所有的回复都可以在最后阅读。这样我们就可以通过SSRF发送一个数据包,完成认证和写入文件的操作。
我们来看Redis是如何进行认证的。先设置一个密码root@123,如图1-109所示。
图1-109 Redis认证
使用Wireshark抓包看一下认证过程,如图1-110、图1-111所示。
图1-110 抓取Redis认证包
图1-111 Redis认证数据包详情
解释一下这些指令的含义。
● *number:代表每一行命令,number代表每行命令中数组中的元素个数。
● $number:代表每个元素的长度。
● *2:*代表数组,这里*2代表本次指令的数组大小为2。
● $4:代表指令的长度,这里是4。
● auth:指令为auth。
再来看一下如何通过SSRF去利用Redis的流量,代码如下。
● dir:指定Redis的工作路径,之后生成的RDB和AOF文件都会存储在这里。
● dbfilename:RDB文件名,默认为dump.rdb。
上述代码先设置工作路径为我们要写入文件的路径,然后设置dbfilename为我们要写入的文件名,就实现了任意文件写入。
我们抓一下流量看看,如图1-112、图1-113所示。
图1-112 Redis写文件数据包
图1-113 Redis写文件数据包详情
通过SSRF方式发送Redis写文件的数据包,就是利用Gopher协议把图1-113中的指令发送给Redis服务。把Payload解码后可以看到,其实就是写文件数据包中的指令,如图1-114所示。
图1-114 解码Payload
我们只需要在这些指令前面加上认证的指令,即可利用有认证的Redis服务写入任意文件。我们来试着构造一个包含认证部分的Payload,通过SSRF写一个ssrf_success.txt到tmp目录下,需要构造的指令如下。
将这些指令构造为Gopher协议格式。
首先进行URL编码,代码如下。
将%0A替换为%0D%0A,代码如下。
可以看到成功写入了文件,如图1-115所示。
图1-115 成功用Gopher协议写入文件
在实际应用的时候我们可能并不知道Redis的密码,既然能够进行认证,当然也可以去爆破Redis的密码。
3.网鼎杯-2020-玄武组-SSRFMe
首先访问题目,给出源码,代码如下。
简单审计发现,对输入的地址做了限制,限制协议为http、https、gopher、dict,限制了127、172、192.168、10这些内网网段,限制了跳转。
直接通过http://0.0.0.0即可绕过,这个IP表示本机IPv4的所有地址。根据提示,访问url=http://0.0.0.0/hint.php。得到hint.php源码,代码如下。
代码中有一个file_put_contents文件写入,但是会在文件的开头添加<?php echo 'redispass is root';exit();来强制退出代码执行。我们可以通过php伪协议绕过,但是这里限制了协议,所以此处绕不过去。请读者留意redispass is root这段代码,它表示存在Redis而且密码为root。
我们可以利用dict协议探测一下端口,访问url=dict://0.0.0.0:6379,发现Redis服务就在默认端口6379上。通过Redis写文件,发现写入不成功,题目的考点其实是Redis基于主从复制的RCE。当Redis读写量很大时,Redis会提供一种模式,即主从模式。主从模式指的是使用一个Redis实例作为主机,其余的作为备份机。主机和备份机的数据完全一致,主机支持数据写入和读取等操作,而备份机只支持与主机数据的同步和读取。也就是说,客户端可以将数据写入主机,由主机自动将写入操作同步到备份机。
主从模式很好地解决了数据备份问题,并且由于主从服务数据几乎是一致的,因此可以将写入数据的命令发送给主机执行,而将读取数据的命令发送给不同的备份机执行,从而达到读写分离的目的。在Redis 4.x之后,我们可以通过外部拓展的方式,自己编译一个.so文件来构造Redis命令。
在2018年的ZeroNights会议上,Pavel Toporkov提出了一种利用主从模式RCE的思路[1]:首先通过Redis的主机实例同步文件到备份机上,然后在备份机上加载构造好的恶意.so文件,从而执行任意命令。
首先构造一个master Server[2],代码如下。
exp.so文件代码地址为https://github.com/vulhub/redis-rogue-getshell。
通过Gopher协议发送Redis指令和目标建立主从关系,这样我们构造的exp.so文件也会被复制过去,接着通过exp.so文件构造一个Redis命令system.exec,调用我们构造的system.exec指令就可以执行任意命令了,代码如下。
将上述代码转换成Gopher协议格式,代码如下。
通过SSRF发送Payload,即可执行任意命令。