SSRF(Server-Side Request Forgery:服务器端请求伪造)是一种由攻击者构造形成由
服务端发起请求的一个安全漏洞。一般情况下,SSRF是要目标网站的内部系统。(因为他是
从内部系统访问的,所有可以通过它攻击外网无法访问的内部系统,也就是把目标网站当中
间人)
SSRF形成的原因大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,文档等等。
正常用户访问网站的流程是:
输入A网站URL一>发送请求->A服务器接受请求(没有过滤),并处理->返回用户响应
【那网站有个请求是www.oldboyedu,com/xxx.php?image-URL】
那么产生SSRF漏洞的环节在哪里呢?安全的网站应接收请求后,检测请求的合法性,
产生的原因:服务器端的验证并没有对其谐求获取图片的参数(image=)做出严格的过滤以及限制,
导致A网站可以从其他服务器的获取数据,
例如:
www.boy.com/xxx.php?image=www.luffycity.com/1.jpg.
如果我们将www.luffycity..com/1.jpg换为与该服务器相连的内网服务器地址会产生什么效果呢?
如果存在该内网地址就会返回1xx 2xx之类的状态码,不存在就会其他的状态码。
简析:SSF漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有检测
这个请求是否合法的,然后服务器以他的身份来访问其他服务器的资源。
SSRF用途
攻击者利用ssrf可以实现的攻击主要有5种:
1.可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务的banner信息;
2.攻击运行在内网或本地的应用程序(比如溢出);
3.对内网Wb应用进行指纹识别,通过访问默认文件实现;~
4.攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts2,sqli等)
5.利用fi1e协议读取本地文件等。
SSRF漏洞出没位置
1.分享:通过URL地址分享网页内容
2.转码服务
3.在线翻译
4.图片加载与下载:通过URL地址加载或下载图片
5.图片、文章收藏功能
6.未公开的api实现以及其他调用URL的功能
7)从URL关键字中寻找
绕过解读:
1、更改IP地址写法
一些开发者会通过对传过来的L参数进行正则匹配的方式来过滤掉内网IP,如采用如下
正则表达式:
10(\. ([2][0-4]\d[2][5][0-5][01]?\d?\d)){3}$
172\.([1][6-9][2]\d3[01])(\.([2][0-4]\d[2][5][0-5][01]?\d?\d)2}$
192\.168(\.([2][0-4]\d[2][5][0-5][01]?\d?\d)){2}$
对于这种过滤我们可以采用改编IP的写法的方式进行绕过,例如192.168.0.1这个IP地址
我们可以改写成:
(1)、8进制格式:0300.0250.0.1
(2)、16进制格式:0xC0.0xA8.0.1
(3)、10进制整数格式:3232235521
(4)、16进制整数格式:0xC0A80001.
还有一种特殊的省略模式,例如10.0.0.1这个IP可以写成10.1
2、利用解析URL所出现的问题,
在某些情况下,后端程序可能会对访问的URL进行解析,对解析出来的host地址进行过滤。
这时候可能会出现对URL参数解析不当,导致可以绕过过滤。
http://www.boy.com@192.168.0.1/
当后端程序通过不正确的正则表达式(比如将 http 之后到 com 为止的字符内容,也就是
www.oldboyedu.com,认为是访问请求的 host 地址时)对上述 URL 的内容进行解析的时候,
很有可能会认为访问 URL 的 host 为 www.oldboyedu.com,而实际上这个 URL 所请求的内容
都是 192.168.0.1 上的内容。
SSRF 常用的后端实现
终极简析: SSRF 漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有
检测这个请求是否合法的,然后服务器以他的身份来访问其他服务器的
ssrf 攻击可能存在任何语言编写的应用,我们通过一些 php 实现的代码来作为样例分
析。代码的大部分来自于真实的应用源码。
file_get_contents:
<?php
if (isset($_POST['url']))
{
$content = file_get_contents($_POST['url']);
$filename ='./images/'.rand().';img1.jpg';
file_put_contents($filename, $content);
echo $_POST['url'];
$img = "<img src=\"".$filename."\"/>";
}
echo $img;
?>
这段代码使用 file_get_contents 函数从用户指定的 url 获取图片,然后把它用一个随机
文件名保存在硬盘上,并展示给用户。
fsockopen():
<?php
function GetFile($host,$port,$link)
{
$fp = fsockopen($host, intval($port), $errno, $errstr, 30);
if (!$fp) {
echo "$errstr (error number $errno) \n";
} else {
$out = "GET $link HTTP/1.1\r\n";
$out .= "Host: $host\r\n";
$out .= "Connection: Close\r\n\r\n";
$out .= "\r\n";
fwrite($fp, $out);
$contents='';
while (!feof($fp)) {
$contents.= fgets($fp, 1024);
}
fclose($fp);
return $contents;
}
}
?>
这段代码使用fsockopen函数实现获取用户制定url的数据(文件或者html)。这个函数会使用
socket跟服务器建立tcp连接,传输原始数据。
SSRF中各个编程语言可以使用的协议如下图所示:
gopher协议的运用
接下来主要介绍下在SSRF漏洞利用中号称万金油的gopher协议。
简要介绍:gopher协议是比http协议更早出现的协议,现在已经不常用了,但是在SSRF漏洞利用中gopher可以说是万金油,因为可以使用gopher发送各种格式的请求包,这样变可以解决漏洞点不在GET参数的问题了。
基本协议格式:URL:gopher://<host>:<port>/<gopher-path>
进行如下请求可以发送一个POST请求,且参数cmd的值为balabal,这里构造gopher请求的时候,回车换行符号要进行2次url编码
由于gopher可以构造各种HTTP请求包,所以gopher在SSRF漏洞利用中充当万金油的角色,具体的攻击方式可以参考如下链接: https://blog.chaitin.cn/gopher-attack-surfaces/
dict协议应用
dict协议是一个字典服务器协议,通常用于让客户端使用过程中能够访问更多的字典源,但是在SSRF中如果可以使用dict协议那么就可以轻易的获取目标服务器端口上运行的服务版本等信息。
如请求http://192.168.163.150/test.php?url=dict://192.168.163.1:3306/info 可以获取目标主机的3306端口上运行着mysq-l5.5.55版本的应用。
有关SSRF其它扩展可参考: http://www.anquan.us/static/drops/web-7550.html
SSRF防护方法
1、防护措施
(黑名单)
(1)过滤10.0.0.0/8 、172.16.0.0/12、192.168.0.0/16、localhost私有地址、IPv6地址
(2)过滤file:///、dict://、gopher://、ftp:// 危险schema
(3)对返回的内容进行识别
(4)内网服务开启鉴权(Memcached, Redis, Elasticsearch and MongoDB)
2、最佳防护
(1)使用地址白名单
(2)对返回内容进行识别
(3)需要使用互联网资源(比如贴吧使用网络图片)而无法使用白名单的情况:首先禁用 CURLOPT_FOLLOWLOCATION;然后通过域名获取目标ip,并过滤内部ip;最后识别返回的内容是否与假定内容一致