![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=1738981131-LLfoBJqiOhkSnwYOECScfOHFQ2TQP9qr-0-9c0e9e8ae3675a0dda33c6d67aaab164)
图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=1738981131-fgR7rqUUX8eP336XZEeLtQLmkK5mhpBd-0-e1fd4805129fcf02687bf64128c5fcab)
图1-109 Redis认证
使用Wireshark抓包看一下认证过程,如图1-110、图1-111所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/76_03.jpg?sign=1738981131-ruBJO9uwZS25slo9fohhCqVu5SZZmitX-0-123d30d0517c7433a0a6e7ac0076ee65)
图1-110 抓取Redis认证包
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/77_01.jpg?sign=1738981131-INATfEexXijA78DZltjQ3swvOE4Z4jxV-0-cc6d3821fe527030e94c4411785d6d45)
图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=1738981131-gbXrIMDRNVxM0k0bwEsCFzWKBV8DD0dg-0-e761a5b8101f180208c08ed140ba7420)
● 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=1738981131-rNDwdXAfzpAuiOuyqDKafOTxB3Muw0s5-0-e41e4b6aec8ba0d80e739ced288b0d26)
图1-112 Redis写文件数据包
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/78_02.jpg?sign=1738981131-MmCwiHOUNdUlZSaLypicfZY9izxKoI5e-0-0d3a783ef3128f18fbd893a42c8a6768)
图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=1738981131-23OJAt6FBeaGgbX5MEQGIi2F6xOOVGys-0-6c4605fce4f65f0da71eebbac3f61167)
图1-114 解码Payload
我们只需要在这些指令前面加上认证的指令,即可利用有认证的Redis服务写入任意文件。我们来试着构造一个包含认证部分的Payload,通过SSRF写一个ssrf_success.txt到tmp目录下,需要构造的指令如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/79_02.jpg?sign=1738981131-xXDCAZ6dsA8mNJFV0nsv0HtRZxUfajbh-0-ee889c4fa61ad59f63ce2a7b0703064c)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_01.jpg?sign=1738981131-drkm52uQGgDSya4rothY6WEi4CXOzpLT-0-84adab68d14e015c06887657ef5efd40)
将这些指令构造为Gopher协议格式。
首先进行URL编码,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_02.jpg?sign=1738981131-vKxs4EQCrwbLoAVs54jBRJ4NByHrwJMu-0-c8b6fe2b11e904053b3c95dda4b71797)
将%0A替换为%0D%0A,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_03.jpg?sign=1738981131-aWm0FL9oQ8nMEJEJHZjhTXIIKecj4wj8-0-20446cdea16e3bb7df78f4bfee4dee66)
可以看到成功写入了文件,如图1-115所示。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/80_04.jpg?sign=1738981131-P28xgE5cL2aeiIMzA604bDaGhpXBGh5m-0-aa3c3aff8a891077fc3b85bead4630df)
图1-115 成功用Gopher协议写入文件
在实际应用的时候我们可能并不知道Redis的密码,既然能够进行认证,当然也可以去爆破Redis的密码。
3.网鼎杯-2020-玄武组-SSRFMe
首先访问题目,给出源码,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/81_01.jpg?sign=1738981131-uaFTZamalMQze1MC06uD6BUFP4sSlqnr-0-2e57586fe94723ecb933e1587f8b9f8d)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/82_01.jpg?sign=1738981131-zAZmhlCxFVPrsRQgX235lsKXU1IFmzVe-0-eb6e10c43bfdf163c66d1bfed63088ca)
简单审计发现,对输入的地址做了限制,限制协议为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=1738981131-93hJaZ4ilQDjfRoI63Wn9eYXjxB97Lif-0-943a5ed2a0634294b79db35f502ee145)
代码中有一个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=1738981131-YtVgiMvL26X1EXbUyBcGadHhHn1v2fJ4-0-8f55401931505de0ca12214d69e6ef90)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/84_01.jpg?sign=1738981131-kEY6lglOCJnYdHS7H3b66L9QjrBFuUpi-0-9b2b6166f38d9d7da799b46aef2e3480)
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=1738981131-dUjOU7Cn1UZ4eLjZJaQ2l6TJ4bfbPp9f-0-1bb137dbc4acc980d170bf1cb2862eff)
将上述代码转换成Gopher协议格式,代码如下。
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/84_03.jpg?sign=1738981131-cp6KbEqhlxaOmzfL8of9GUYmM0pWxnxM-0-37fcc909737c585306b60c36bf2b816d)
![](https://epubservercos.yuewen.com/2B7BD9/27167019607668606/epubprivate/OEBPS/Images/85_01.jpg?sign=1738981131-Ll7x5ycvZTYiBNHcmHwgokgqTG1Zz3OE-0-1a08e35b469651c3bf432056f6262643)
通过SSRF发送Payload,即可执行任意命令。