本篇文章我们将详细的介绍一下SSRF的相关知识,包括原理、分类、攻击手法、修复方法等。
简介
什么是SSRF
SSRF (server-side request forgery) 服务端请求伪造,它主要会允许攻击者诱使服务器向一个开发人员预想之外的地址发起请求,比如一些内网环境。
可能会有人觉得这有什么危害呢,发起请求就发起呗。
这里我们需要明确一点,这个请求的发起方并不是攻击者,而是被攻击的应用所在的服务器,在一些内外网隔离的环境中,某些应用可能需要向公网提供服务,那么运维人员会将其端口映射到公网上面供用户访问(这里我们称这个服务为 A),但是对于统一局域网内的其他服务公网上的用户是访问不到的(比如有一个服务 B)。
这时候如果服务 A 有SSRF漏洞呢?
那攻击者就可以通过这个漏洞让 服务A 去访问 服务B,然后把数据返回给自己,就相当于 服务A 成为了访问 服务B 的跳板,那就可以用于探测内网设备等用途。
原理
原理其实也是开发人员对用户输入过于信任,没有进行响应的限制及校验,所以使得从其他应用获取数据的功能出现了漏洞。
危害
-
内网资源访问:攻击者可以利用SSRF漏洞发送请求到内部网络中,绕过防火墙,访问并互动与后端系统,包括数据库服务、HTTP服务、版本控制系统等,这可能导致敏感数据的泄露。
-
远程代码执行:在某些情况下,如果应用程序在处理用户提供的URL时不够严谨,攻击者可能利用SSRF漏洞执行远程代码,这可能导致服务器被完全控制。
-
服务拒绝(DoS)攻击:攻击者可以利用SSRF向内部系统发送大量请求,导致服务不可用或系统资源耗尽。
-
扫描内部网络:攻击者可以利用SSRF漏洞探测内网环境,识别网络结构和寻找其他潜在的安全漏洞。
-
文件读取:如果服务器配置不当,SSRF可能允许攻击者请求本地或远程文件,这可能导致敏感文件内容被读取。
测试方法
测试方法的话也没什么好说的,看到请求参数带 url 的就无脑上去试就好了
-
直接把如 www.baidu.com 这种网站输上去看看有没有成功访问
-
试一试特殊协议,比如 file://、 ftp:// dict://、gopher://
-
端口扫描,这个没啥说的 遍历就完了,如 http://target.com:22
-
利用URL解析差异,如
通过添加@符号重定向到其他地址,例如 http://[email protected]
用#来尝试忽略URL的一部分,例如 http://target.com#attacker.com
回环和本地地址 如 使用 http://127.0.0.1、http://localhost 或 http://[::1] 来尝试访问本地服务
绕过技巧
使用短URL或重定向服务来绕过验证。
IP地址八进制、十六进制或混淆形式。
添加无关查询参数或使用URL编码来混淆真正的请求。
防御方法
使用白名单:
仅允许应用程序发起到预先定义的、可信赖的域名或IP地址的请求
对于必须接受用户输入的情况,确保所有的输入都符合白名单中的条目
输入验证:
严格验证用户输入的URL格式,确保只有白名单中的URL能够通过
限制协议:
限制应用程序可用于发起请求的协议类型,通常仅允许http://和https://
案例详解
针对应用所在服务器的 SSRF
下面我们来看一个典型的 SSRF,这个没什么知识点,就简单看一下就行
任务简报
这个实验室的查看库存的地方存在一个 SSRF 漏洞,通过它访问 管理员界面 http://localhost/admin 并删除 carlos 用户即可
任务过程
先找到这个查看库存的地方看一下它的请求包
好 这就是一个典型到不能再典型的可能存在 SSRF 漏洞的注入点了,正常来说我们可以通过修改参数为 www.baidu.com 之类的方法去测试一下,但是这个靶场是不通公网的,所以这样明显是不会成功的,所以我们就直接拦截后修改成题目要求的 http://localhost/admin 即可
此时我们就可以看到管理员面板了,那我们之间点删除就好了
看起来不太行,提示我们需要登录管理员账号或在回环请求中才能使用管理员界面,那我们就看看它的删除请求是什么样子的
这里我们做一点小小的修改, payload http://localhost/admin/delete?username=carlos 然后我们再回到存在 SSRF 漏洞的位置重新提交
此时我们可以看到,原来的 carlos 已经被删除,只剩下了 wiener 用户,手工下班
可能出现的场景
看了上面的例子,可能有的同学会感觉有点莫名奇妙,什么人会设置这样的逻辑,本地请求就不用鉴权了吗?
下面是一些出现这种场景的原因:
-
鉴权与功能不是一个服务完成的。在实际的生产环境中,为了实现类似 sso (单点登录)这样的功能,其鉴权和功能可能是分布在不同的组件上的,当用户使用功能的时候肯定是需要鉴权的,但是当服务器本身去访问的时候就不一定了,如果程序员没有考虑到这种情况,很可能会出现绕过鉴权的问题,毕竟我访问我自己还需要问问我是不是我?
-
为了留一个后手用来实现灾难恢复。如果有一天服务崩掉了,恰巧运维把管理员密码给忘了,这种时候总不能什么都做不了吧,那就只能通过免登录的上机恢复了,当然这种情况下默认能进到机房或者能远程服务器的人是可靠的,所以他们就做了这样的一个逻辑处理,但是他们万万没想到还会存在 SSRF 这种东西。
针对其他后端系统的 SSRF
这种情况和上面的在利用上的区别仅在于如何发现同一局域网下有哪些服务器,同时开放了哪些端口
任务简报
这个实验室的查看库存的地方存在一个 SSRF 漏洞,通过它访问 管理员后台 192.168.0.X 网段,开放的接口是 8080,访问它并删除 carlos 用户即可
任务过程
这个靶场和上一个的区别不大,难点主要在怎么发现这个服务器,这个可以利用 burp 的 Intruder 模块,这里提示了相关的网段和开放的端口,可以节省很大的时间,实际中就需要耗费大量的时间在扫描上了,相关配置如下
之后我们就可以直接开扫了
看结果可以知道是 http://192.168.0.137:8080/admin,那后面的步骤就没有什么区别了,修改一下 payload 发送到 repeator 发送即可 payload http://192.168.0.137:8080/admin/delete?username=carlos
无回显 SSRF
无回显 SSRF(Blind SSRF)和 SQL 盲注之类的一样,这种类型的 SSRF 即便存在漏洞,但是服务器也不会给前端任何数据,它们只是偷偷的访问一下你给的网址,所以对于这种类型的 SSRF 的发现如果没有准备的话是比较困难的(OAST)
这个情况多数出现在 referer 头上,有的网站可能会追踪用户是从什么网站跳转到自己的站点的,同时访问一下那个网站看看它是包含什么内容,然后记录下来。
从测试角度上看,这种漏洞和正常的 SSRF 并没有什么区别,就是吧 payload 中的域名换成自己的,然后看看有没有访问记录就好了,但是要说这种漏洞改怎么利用,似乎就有点困难了。
毕竟想要让它在访问的你的受控站点的时候携带一些敏感数据,那需要对方存在一些严重的如命令执行之类的漏洞才能实现,这对于攻击者运气上的考验似乎有点大了。
绕过技巧
黑名单绕过
有些程序员为了预防 SSRF 也会做一些防御手段,比如设置一个黑名单,把 127.0.0.1 localhost 和一些敏感字段如 admin 放进去,然后对用户输入进行校验,但众所周知,黑名单总是容易绕过的:
-
使用十进制八进制的表示方法来代替原本的 127.0.0.1,如 2130706433、01770000001和127.1
-
如果对方的服务器可以通公网的话,你可以注册一个域名然后解析成 127.0.0.1,当然这个需要一些钞能力
-
如果是关键字检测是的话可以试试大小写绕过或者URL编码绕过
任务简报
开发者通过黑名单来防御 SSRF,突破它的防御并访问 http://localhost/admin 删除 carlos 用户,即为通关
任务过程
我们直接到注入点看一下是什么情况
可以看到是有安全检测的,我们用上面的绕过方式修改一下 payload 看看 http://localHoSt/aDmIn
可见成功绕过,那后面的也就没什么技术含量了 http://localHoSt/aDmIn/Delete?username=carlos 即可
白名单绕过
程序猿:既然上面的黑名单不安全,那我们使用白名单总行了吧?
其实也不见得,我们可以利用 URL解析中的不一致性来绕过,这里的不一致性指的是:不同的浏览器、库或应用程序在处理URL时的行为差异。URL(统一资源定位符)是互联网上资源的地址,它有一个标准的格式,包括协议、主机名、端口、路径、查询字符串等。然而,在实际中,由于历史原因、实现差异或者解析逻辑的不同,不同的软件可能会以不同的方式解析相同的URL。
所以我们来看一下有哪些平时不会用到的但又在URL规范中规定了的功能:
-
使用 @ 在URL 的主机名前嵌入凭据:https://expected-host:fakepassword@evil-host
-
使用 # 表示URL 片段:https://evil-host#expected-host
-
如果实现过滤器的代码处理URL编码字符的方式与执行后端HTTP请求的代码不同,可以通过URL编码字符来混淆URL解析代码,也可以尝试对字符进行双重编码;一些服务器递归地对它们接收到的输入进行URL解码,这可能导致进一步的差异从而实现绕过白名单限制
-
就是可以把上面的一起用出来
任务简报
开发者通过黑名单来防御 SSRF,突破它的防御并访问 http://localhost/admin 删除 carlos 用户,即为通关
任务过程
首先我们来了解一下如何判断网站是 黑名单策略还是白名单策略,我们先来看一下白名单的情况,原始参数是 stockApi=http%3A%2F%2Fstock.weliketoshop.net%3A8080%2Fproduct%2Fstock%2Fcheck%3FproductId%3D1%26storeId%3D1,我们这里输入 http://127.0.0.1
这里提示 库存检查的主机必须是 stock.weliketoshop.net,当然正常情况下网站不会这么直白的告诉我们,我这里也不会通过这个来分辨防御策略,所以我们继续往下试,因为如果是黑名单的话,它只会禁止一些特征明显的关键字,我们就随便编一个奇奇怪怪的网址就好了,比如 http://aaa.bbb.com
我们发现它的返回还是没有变化,那说明应该是 白名单 的防御策略。
下面我们看看 黑名单是什么样的情况吧,还是先看 http://127.0.0.1
这里提示触发了安全策略,我们还是不管,换成 http://aaa.bbb.com 看看效果
这次就和白名单的返回不一样了,服务器尝试了连接,但是当然是连不到的,所以也就可以断定是黑名单策略了
当然本节讲的是白名单的绕过,我们回到主题上来,前面说到我们可以利用 URL 解析的差异性来绕过 白名单检测,用在这个案例中,我们的思路就是让校验逻辑认为请求的是 stock.weliketoshop.net ,但实际上是另外一个主机,那应该怎么做呢,还记得我们上面的提到的 # 这个符号吧,它是一个片段标识符,它后面的内容不会被用作服务器通信,而是一个单纯的页面锚点,这里我们利用的也就是这个特性,先让我们试试 http://localhost:80#stock.weliketoshop.net
哎?好像不行啊,是它不支持吗,我们改成 @ 符试试 http://localhost:[email protected]
@ 符是可以的,那问题可能是出在 # 上面了,我们对它进行编码试试 http://localhost:80%[email protected](这个试过了也不行,直接上双重编码) http://localhost:80%[email protected],这里加上 @ 是为了让校验逻辑认为前面的部分是账号密码,但它实际上会被 # 注释掉成为片段的一部分,从而使 @ 失效
可见是可以访问了,那就加上要求的删除用户 http://localhost:80%[email protected]/admin/delete?username=carlo即可
黑白名单的区别
黑名单(Blocklist):
特征:黑名单防御会阻止已知的恶意请求,例如特定的IP地址、域名或URL模式。检测方法:如果某些特定的请求(例如请求本地网络IP地址或元数据URL)被阻止,而其他未知的或不常见的恶意请求仍然可以成功,这可能表明使用的是黑名单防御。白名单(Allowlist):
特征:白名单防御仅允许预定义的安全请求通过,即使是未知的恶意请求也会被阻止,因为它们不在允许列表中。检测方法:如果只有来自特定的、明确允许的域名或IP地址的请求可以成功,而试图从任何未经授权的域名或IP地址发起的请求都被拒绝,那么这可能表明使用的是白名单策略。
通过开放重定向绕过 SSRF 过滤器
除了上面的情况,我们还可能遇到请求的是统一域名下的某个路径,也就是相对路径,这种情况下前面的方法就不能用了,但是天无绝人之路,你又在这个站点上发现了一个开放重定向的漏洞,这似乎有可以利用一下。
思路就是让服务器自己访问这个含有重定向漏洞的URL,然后定向到内网
任务简报
库存检查的组件仅被允许访问本地的应用,找到一个开放重定向的功能,突破它的防御并访问 http://192.168.0.12:8080/admin 删除 carlos 用户,即为通关
任务过程
来到原来的地方看看是个什么情况
可以发现这里变成了相对路径,当然我们肯定不能就这么相信它,写进去看看
好吧 看来它没骗我们,现在找到了那个重定向的接口
可以看到这里有个重定向,我们再输进去看看是什么结果(这里主要看的是后台有没有限制重定向的域名)
可以看到,服务器对于这个地址并没有什么疑问,那就好说了,在检查库存的地方让它访问这里,然后就可以在服务端重定向到指定的内网机器,执行我们的payload了 /product/nextProduct?currentProductId=2%26path=http://192.168.0.12:8080/admin/delete?username=carlos(currentProductId 参数没什么用直接删掉,要不然后面的 & 会认为 path 参数和 stockApi 是同一级的参数,而不是 stockApi 中的值;当然也可以对 & 进行URL编码)
原文始发于微信公众号(隐雾安全):一篇文章学会ssrf
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论