Web安全基础篇——SSRF服务器端请求伪造

Web安全基础篇——SSRF服务器端请求伪造
AudienceSSRF
SSRF (Server Side Request Forgery:服务器端请求伪造)是一种由攻击者构造特殊形成的请求,并且由指定服务器端发起恶意请求的一个安全漏洞。由于业务运行的服务器处于内外网边界, 并且可通过利用当前的这台服务器,根据所在的网络,访问到与外部网络隔离的内网应用,所以一般情况下,SSRF漏洞的攻击目标是攻击者无法直接访问的内网系统。
SSRF漏洞的形成大多是由于服务端提供了,从其他服务器应用获取数据的功能而没有对目标地址做过滤和限制。例如,黑客操控服务端从指定URL地址获取网页文本内容,加载指定地址的图片,下载等, 利用的就是服务端请求伪造,SSRF漏洞可以利用存在缺陷的WEB应用作为代理攻击远程和本地的服务器。
漏洞危害
- 对内网进行端口扫描和主机存活探测等敏感信息收集
- 攻击内外网其他存在漏洞的web应用(主要是Get参数攻击)
- 造成内外网DDOS攻击
- 通过file://读取本地任意文件,通过
dict
协议获取服务器端服务,通过http
协议探测web应用等等。
漏洞出现点
转码服务
通过URL地址把原地址的网页内容调优使其适合手机屏幕浏览。由于手机屏幕大小的关系,直接浏览网页内容的时候会造成许多不便,因此有些公司提供了转码功能,把网页内容通过相关手段转为适合手机屏幕浏览的样式。例如百度、腾讯、搜狗等公司都有提供在线转码服务。
分享
通过URL地址分享文章,例如如下地址:
如:http://share.XXX.com/index.php?url=http://127.0.0.1
通过URL参数的获取来实现点击链接的时候跳到指定的分享文章。如果在此功能中没有对目标地址的范围做过滤与限制则就存在着SSRF漏洞。
在线翻译
通过URL地址翻译对应文本的内容。提供此功能的国内公司有百度、有道等。
图片加载与下载
通过URL地址加载或下载图片
如:http://image.xxx.com/image.php?image=http://127.0.0.1
图片加载存在于很多的编辑器中,编辑器上传图片处,有的是加载远程图片到服务器内。还有一些采用了加载远程图片的形式,本地文章加载了设定好的远程图片服务器上的图片地址,如果没对加载的参数做限制可能造成SSRF。
图片、文章收藏功能
如:http://title.xxx.com/title?title=file://etc/passwd
例如title参数是文章的标题地址,代表了一个文章的地址链接,请求后返回文章是否保存,收藏的返回信息。如果保存,收藏功能采用了此种形式保存文章,则在没有限制参数的形式下可能存在SSRF。
参数中的关键字
使用抓包工具进行抓包,然后查找参数关键字,如果包含类似以下的关键字,那有可能存在SSRF漏洞。
1 | share |
SSRF中支持的协议
当我们发现SSRF漏洞后,首先要做的事情就是测试所有可用的URL协议。
http/https协议
当前应用获取用户传递过来的URL参数后端发送请求,并且将最终的请求结果返回到HTML前端页面。如果该服务器阻止对外部站点发送HTTP请求,或启用了白名单防护机制,只需使用如下所示的URL Schema就可以绕过这些限制。
file协议
使用 file 协议进行的任意文件读取算是 ssrf 最简单的利用方式了。这种URL Schema可以尝试从文件系统中获取文件。
1 | http://example.com/ssrf.php?url=file://C:/Windows/win.ini |
dict协议
词典网络协议,允许客户端在使用过程中访问更多字典。Dict服务器和客户机使用TCP端口2628。这种URL Scheme能够引用允许通过DICT协议使用的定义或单词列表。漏洞代码没有屏蔽回显的情况下,可以利用dict协议获取ssh等服务版本信息。
dict协议在SSRF漏洞中主要用来探测内网主机、探测端口的开放情况和指纹信息。
使用方式:
1 | dict://serverip:port/命令:参数 |
如载荷:curl -v http://example.com/ssrf.php?dict://127.0.0.1:6379/info
。如果ssrf.php
中加上一行屏蔽回显的代码curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
,那么这种方式就失效了,和gopher一样,只能利用nc监听端口,反弹传输数据了。
dict协议后跟的命令可以直接被某些服务执行,比如redis。向服务器的端口请求为命令:参数
,并在末尾自动补上\r\n
(CRLF),为漏洞利用增加了便利。dict协议执行命令要一条一条执行。
使用条件:
dict 协议不支持换行符,没有办法进行换行,相当于一次只能执行一条命令,所以不能用来攻击那些需要交互的应用(比如需要认证的 redis)。必须是redis未设密码的情况下才可利用dict执行命令,否则即便知道密码也无法进行其他操作。因为在每一次发送命令的同时都需要进行身份认证,即第一次发送auth qianxun
通过认证,第二次发送get name
时还是提示要密码认证,说明redis是无记忆的。而dict只能一次执行一条命令,所以无法操作。
gopher协议
gopher 协议是一个在http协议诞生前用来访问Internet 资源的协议可以理解为http 协议的前身或简化版,虽然很古老但现在很多库还支持gopher 协议而且gopher 协议功能很强大。它可以实现多个数据包整合发送,然后gopher 服务器将多个数据包捆绑着发送到客户端,这就是它的菜单响应。比如使用一条gopher 协议的curl 命令就能操作mysql 数据库或完成对redis 的攻击等等。gopher 协议使用tcp 可靠连接。gopher 协议在jdk8 中就被移除了。gopher协议在SSRF的利用中一般用来攻击redis,mysql,fastcgi,smtp等服务。
gopher url格式:
1 | gopher://<host>:<port>/path |
如果要访问服务器上的文件,则直接写路径即可,如要请求 Gopher 服务器上的 /example/file.txt 文本文件,可以使用以下 URL 格式:
1 | gopher://example.com:端口/example/file.txt |
在SSRF中,很多时候我们只能通过url去发送get请求,而如果使用gopher协议,则可以对内网发送post请求,服务器会解析gopher的内容是Get还是Post。
GET提交
需要保留头部信息:
- 路径:
GET /name.php?name=benben HTTP/1.1
- 目标IP地址:
Host:172.250.250.4
。
编码:url=gopher://172.250.250.4:80/_GET%20/name.php%3fname=benben%20HTTP/1.1%0d%0AHost:%20172.250.250.4%0d%0A
。
URL编码:
- 空格:%20
- 问号:%3f
- 换行符:%0d%0A
注意:
- 回车换行要变为%0d%0a,但如果直接用工具转,可能只会有%0a。
- 在HTTP包的最后要加%0d%0a,代表消息结束(具体可研究HTTP包结束)。
- URL编码改为大写,冒号注意英文冒号。
- 如果使用BP发包需要进行两次url编码。
- GET提交最后需要增加一个换行符。
POST提交
需要保留头部信息:
- POST
- Host
- Content-Type:根据提交的类型定。
- Content-Length:内容的长度。
可以抓包后使用如下脚本将数据包转换为gopher协议格式。需要根据具体情况修改生成payload。
1 | import urllib.parse |
产生SSRF漏洞的函数
file_get_contents
使用file_get_contents函数从用户指定的url获取图片。然后把它用一个随即文件名保存在硬盘上,并展示给用户。
1 |
|
fsockopen()
使用fsockopen函数实现获取用户制定url的数据(文件或者html)。这个函数会使用socket跟服务器建立tcp连接,传输原始数据。
1 |
|
curl_exec()
使用curl发送请求获取数据。
1 |
|