![CTF实战:技术、解题与进阶](https://wfqqreader-1252317822.image.myqcloud.com/cover/482/47755482/b_47755482.jpg)
1.4.3 SSRF进阶
1.无回显SSRF
无回显SSRF即我们无法看到通过SSRF请求的结果,这样就极大减少了SSRF的攻击面。下面介绍当碰到无回显SSRF时,我们如何利用。
先看看如何判断SSRF漏洞是否存在。我们可以先在自己的服务器上用Netcat工具监听某个端口,然后通过SSRF去请求。如果我们的服务器收到请求了,说明存在SSRF。如果未收到,也不能判断其不存在,还需要考虑目标机器不出网的情况,如图1-108所示。
也可以通过DNSLOG去探测SSRF。
虽然没有回显,但是我们还是能够通过一些别的信息去判断探测的结果,比如状态码、响应时间或者页面上的某一个特征。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/76_01.jpg?sign=1739128233-xxRxN8zHR9xdU5w6sjOtfSlk1UUc7ECF-0-600b1171273025ec70d15be608e7539a)
图1-108 Netcat接收请求
在没有回显的情况下攻击内网的某些服务,如Redis,盲打内网的应用和服务。因为没有回显,所以很难判断我们构造的Payload是否攻击成功了。
2.攻击有认证的Redis服务
前面说到SSRF可以攻击内网无认证的Redis服务。如果碰到有认证的Redis服务,还能通过SSRF去利用吗?答案是可以。虽然SSRF每次只能发送一个数据包,无法保持登录状态,但是Redis使用的是RESP(Redis序列化协议),Redis客户端支持管道操作,可以通过单个写入操作发送多个命令,而无须在发出下一条命令之前读取上一条命令的服务器回复,所有的回复都可以在最后阅读。这样我们就可以通过SSRF发送一个数据包,完成认证和写入文件的操作。
我们来看Redis是如何进行认证的。先设置一个密码root@123,如图1-109所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/76_02.jpg?sign=1739128233-QWl1nm86fY9bG0oNBGcOjXNH53xrQtz9-0-329441fac8df79794d796d453fc45364)
图1-109 Redis认证
使用Wireshark抓包看一下认证过程,如图1-110、图1-111所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/76_03.jpg?sign=1739128233-j689onv9FtwAb7PQmv8vCTo49oFtfOWT-0-a4f45c6860f018a6c0847c76d087d234)
图1-110 抓取Redis认证包
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/77_01.jpg?sign=1739128233-hgpkP0X2iTd0csmY4waswMkJOVhU1mc6-0-febf223f12d7018aeec6caf3e091ae58)
图1-111 Redis认证数据包详情
解释一下这些指令的含义。
● *number:代表每一行命令,number代表每行命令中数组中的元素个数。
● $number:代表每个元素的长度。
● *2:*代表数组,这里*2代表本次指令的数组大小为2。
● $4:代表指令的长度,这里是4。
● auth:指令为auth。
再来看一下如何通过SSRF去利用Redis的流量,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/77_02.jpg?sign=1739128233-n0j4avcsfSOjYs4t1AoIsa3YyHswSEsL-0-21117ea7f017ad158a52439791028517)
● dir:指定Redis的工作路径,之后生成的RDB和AOF文件都会存储在这里。
● dbfilename:RDB文件名,默认为dump.rdb。
上述代码先设置工作路径为我们要写入文件的路径,然后设置dbfilename为我们要写入的文件名,就实现了任意文件写入。
我们抓一下流量看看,如图1-112、图1-113所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/78_01.jpg?sign=1739128233-WI6nUK8FnvBeoE9SvWcvzrMtrjaGJKsU-0-4735b7a4d537618f343ebe37ffe47f11)
图1-112 Redis写文件数据包
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/78_02.jpg?sign=1739128233-g6htqIjIHHsIEeQLsojB7Q2KxFJXaQ7S-0-c9c8a3a441675cce725965ef828bae5e)
图1-113 Redis写文件数据包详情
通过SSRF方式发送Redis写文件的数据包,就是利用Gopher协议把图1-113中的指令发送给Redis服务。把Payload解码后可以看到,其实就是写文件数据包中的指令,如图1-114所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/79_01.jpg?sign=1739128233-imXWgzhosIW7XHq3z7YAWElcvjr8bVv2-0-125754dede7e1abedc70dee4f99f2ead)
图1-114 解码Payload
我们只需要在这些指令前面加上认证的指令,即可利用有认证的Redis服务写入任意文件。我们来试着构造一个包含认证部分的Payload,通过SSRF写一个ssrf_success.txt到tmp目录下,需要构造的指令如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/79_02.jpg?sign=1739128233-D0r3Jl5GVBJ31MtyyD3UhxLmzIF2canO-0-0ae35bfaa80845ca2e6301b969fea065)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_01.jpg?sign=1739128233-rFFjXP00qULiI01R7IUvYsxR1JxwcFxn-0-c1683eb16249ad847b5db32ce3fab551)
将这些指令构造为Gopher协议格式。
首先进行URL编码,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_02.jpg?sign=1739128233-IJS6c6DDgqrv3DwheWGiSy6t7nVh0jex-0-1b71f8bc5ce0fdc610746d1895700d19)
将%0A替换为%0D%0A,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_03.jpg?sign=1739128233-2hk5O0wkGnTp4ZV9NSiXMA3KoDu75tTL-0-f3ba9884d6c6a628c30866de1e5d3d23)
可以看到成功写入了文件,如图1-115所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_04.jpg?sign=1739128233-reb7Y3IE85sINGRD49lDHEntiCzIlYwh-0-948563f3106207e00b249bb3e6db0747)
图1-115 成功用Gopher协议写入文件
在实际应用的时候我们可能并不知道Redis的密码,既然能够进行认证,当然也可以去爆破Redis的密码。
3.网鼎杯-2020-玄武组-SSRFMe
首先访问题目,给出源码,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/81_01.jpg?sign=1739128233-UlyvAyNak3cwC7LUzEVOBwek7R8z6OJF-0-2cd210b08d69f6fbae4e8691355616f9)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/82_01.jpg?sign=1739128233-5Ez8Th6aV1oh4ncmM8Dkr0B9ynTIqyrr-0-3f82c413617420c435c3a4bd9d32496e)
简单审计发现,对输入的地址做了限制,限制协议为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源码,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/82_02.jpg?sign=1739128233-Zm53HSPZrgxAHBExfeOvdyskLVpXx0kJ-0-a0b25a0d5cab0396e7b5f6eeee2c5bce)
代码中有一个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],代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/83_01.jpg?sign=1739128233-yt7StLCM6qxWrBUvVTBv76xJjQvDsywI-0-e19f502998563f47cbb7a734f48d7755)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/84_01.jpg?sign=1739128233-3EPa5GSCkeMJTe2WQnPwCJoRZjNZ3mlJ-0-0470bdf7b031be5d85b778fb1a771631)
exp.so文件代码地址为https://github.com/vulhub/redis-rogue-getshell。
通过Gopher协议发送Redis指令和目标建立主从关系,这样我们构造的exp.so文件也会被复制过去,接着通过exp.so文件构造一个Redis命令system.exec,调用我们构造的system.exec指令就可以执行任意命令了,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/84_02.jpg?sign=1739128233-48TUPhz55a57rxuT76M5lzRcnrxe0M1T-0-3dedfccb27707f9491d7b7ba119c3855)
将上述代码转换成Gopher协议格式,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/84_03.jpg?sign=1739128233-ewpWyKOeKzf9Qh9kmBx85YF1vx9j6LtC-0-7d0c63c6fdba14cfec17dfb2ab2b32e6)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/85_01.jpg?sign=1739128233-mmyeHAp2JZqSaRP9tHZYzQPJUxAJyqyJ-0-3b5b3788d189cab38fb76f5cf356ce95)
通过SSRF发送Payload,即可执行任意命令。