标题 : 如何:服务器端请求伪造 (SSRF)
日期 : 2023-07-17
服务器端请求伪造(简称 SSRF)是一个漏洞类别,描述了在攻击者控制下发出请求的服务器的行为。这篇文章将讨论影响、如何测试它、潜在的关键点、失败的缓解措施和警告。
在深入研究 SSRF 漏洞的影响之前,让我们花点时间了解一下该漏洞本身。在线应用程序碰巧需要外部资源。例如,当您在 Twitter 上发布此博文时,Twitter 上会显示此博文的头像。图像、标题和描述来自此页面返回的 HTML。为了下载该信息,Twitter 服务器会向该页面发出 HTTP 请求并提取所需的所有信息。直到最近,他们的链接扩展还容易受到 SSRF 漏洞的影响。
这篇文章将解释在哪些情况下这是一个安全漏洞以及如何利用它。
配置
当您可以让服务器向另一台服务器发出请求时,它可能是 SSRF。对于操作方法文章,通常最好在本地设置一个易受攻击的应用程序供您使用。为了这篇博文的目的,我们假设我们有一个运行以下 Ruby 代码的服务器:
require ‘sinatra’ require ‘open-uri’
get ‘/’ do format ‘RESPONSE: %s’, open(params[:url]).read end
要在本地运行此代码,请将其存储为 server.rb ,运行gem install sinatra ,然后运行ruby server.rb 。我使用了红宝石 2.3.3p222 。然后您可以在http://localhost:4567上使用它。不要在本地环回接口以外的任何设备上运行此命令,这会导致命令执行。
当有人请求http://localhost:4567/?url=https://google.com时,open()调用会获取https://google.com并将响应正文返回给客户端。
hack-box-01 $curl http://localhost:4567/\?url\=https://google.com
RESPONSE: <!doctype html><html itemscope=”” itemtype=”http://schema.org/WebPage” lang=”en”><head><meta content=”搜索世界上的信息,包括网页、图像、视频等。Google 有许多特殊功能可以帮助您准确找到所需的内容。” name=”description”><元内容=”noodp” name=”robots”><元内容=”text/html; charset=UTF-8″ http-equiv=”Content-Type”><元内容=”/ images/branding/googleg/1x/googleg_standard_color_128dp.png” itemprop=”image”><title>Google</title>
从互联网获取 URL 并不是那么令人兴奋,而且它本身也不是一个漏洞 – 因为它直接连接到互联网,所以任何人都可以访问它。现在让我们花点时间考虑一下局域网 (LAN)。互联网的很大一部分位于路由器和防火墙后面。这些路由器通常使用网络地址转换 (NAT) 将流量从内部 IP 子网路由到互联网并返回。
为了解释影响,请考虑使用 ruby 代码运行的服务器(IP 地址 10.0.0.3)与另一台服务器admin-panel (IP 地址 10.0.0.2)位于同一网络内。管理面板服务器在端口 80 上为站点提供服务,无需任何身份验证。路由器 (10.0.0.1) 将所有内部流量路由到互联网。对于此示例,内部服务器之间的流量没有任何防火墙规则。无法从 Internet 访问管理面板服务器。可以通过web-server.com访问 Web 服务器。
我们知道我们的 Web 服务器 10.0.0.3 处理我们发送给它的请求。管理面板服务器在端口 4567 上提供 HTTP 接口。现在让我们看看当我们通过 Web 服务器请求管理面板服务器时会发生什么:
hack-box-01 $curl http://web-server.com:4567/\?url\=http://10.0.0.2/
响应:<html><head><title>内部管理面板</title></head>…</html>
由于 Web 服务器实际上可以到达 10.0.0.2(内部管理面板服务器),因此它会向其发送 HTTP 请求,然后将响应反映给外界。您可以将其与网络代理进行比较,但被滥用以将外部流量代理到内部服务,反之亦然。
测试
现在您已经对该漏洞有了基本的了解,让我们深入了解如何测试它。在我发现的所有 SSRF 漏洞中,我认为拥有自己的可以连接回的服务器确实很有用。这将帮助您调试潜在的漏洞。我更喜欢使用DigitalOcean盒子,但无论你能找到什么可以转发来自互联网的流量的服务器都可以。
让我们通过让其 ping 到您控制的服务器来调试在http://web-server.com:4567/上运行的 SSRF 。首先,设置一个netcat监听器来查看传入的请求:
hack-box-1 $ nc -l -n -vv -p 8080 -k
监听 [0.0.0.0](系列 0,端口 8080)
这将侦听所有接口上端口 8080 上的连接,并向我们显示发送到它的所有流量。为了便于举例,我们假设hack-box-1的外部 IP 地址是 1.2.3.4。现在让 web-server.com ping 我们的服务器:
hack-box-01 $curl http://web-server.com:4567/\?url\=http://1.2.3.4:8080/
当您执行该命令时,您会注意到 netcat 侦听器中有一个 HTTP 请求:
hack-box-1 $ nc -l -n -vv -p 8080 -k 侦听 [0.0.0.0](系列 0,端口 8080) 接受来自 [masked] 端口 8080 [tcp/*] 的连接(系列 2,运动45982) GET / HTTP/1.1 接受编码: gzip;q=1.0,deflate;q=0.6,identity;q=0.3 接受: */* 用户代理: Ruby 主机: 1.2.3.4:8080
这会显示发送到您传递到url参数的 IP 地址/域名的 HTTP 请求。过去几年我见过的几乎所有 HTTP 库都遵循 HTTP 请求。如果您的服务器(本例中为 netcat 侦听器)将使用下面的 HTTP 响应进行响应,则 web-server.com 将遵循它,然后向http://10.0.0.2/发出请求。
HTTP/1.1 302 找到 位置:http://10.0.0.2/ 内容长度:0
您问为什么这很重要?我看到公司实施的缓解措施之一是限制服务器连接到内部服务或端口。但是,该限制通常不适用于 HTTP 重定向。考虑一下我们的服务器将像这样实现:
require ‘sinatra’ require ‘open-uri’
get ‘/’ do url = URI.parse params[:url]
停止 403 if url.host =~ /\A10\.0\.0\.\d+\z/
格式’响应:%s’,open(params[:url]).read end
此代码在发送请求之前解析 URL。如果传递的 URL 的主机与 IP 地址 10.0.0.[任何数字序列] 匹配,它将返回 HTTP 403 Forbidden 状态。有时有几种方法可以绕过这个问题:
要通过重定向访问http://10.0.0.2/,您的第一个请求将发送到您控制的服务器。从该服务器,您将重定向回http://10.0.0.2/。这将绕过上面代码中实现的缓解措施,因为它已经到达了open()方法。在上面的代码示例中,使用了主机黑名单方法。这可能是一个滑坡,因为作为开发人员,您必须考虑所有不同的旁路,但有时是必要的。当实现白名单时,如下面的代码示例所示,尝试查找白名单主机中的开放重定向漏洞。这可以帮助您转向站点的内部网络。重定向通常可以帮助您克服端口、主机、路径和协议限制。
require ‘sinatra’ require ‘open-uri’
get ‘/’ do url = URI.parse params[:url]
停止 403 除非 url.host == ‘web-server.com’
format ‘RESPONSE: %s’, open( params[:url]).读取 结束
以下是最容易出现 SSRF 漏洞的前 5 个无序功能:
- Webhooks:查找在某些事件发生时发出 HTTP 请求的服务。在大多数 Webhook 功能中,最终用户可以选择自己的端点和主机名。尝试向内部服务发送 HTTP 请求。
- PDF 生成器:尝试注入<iframe> 、<img> 、<base>或<script>元素或指向内部服务的CSS url()函数。
- 文档解析器:尝试发现文档是如何解析的。如果它是 XML 文档,请使用 PDF 生成器方法。对于所有其他文档,请查看是否有办法引用外部资源并让服务器向内部服务发出请求。
- 链接扩展:感谢 Mark Litchfield最近发现了 Twitter 链接扩展中的漏洞。
- 文件上传:不要上传文件,而是尝试发送 URL 并查看是否下载 URL 的内容。
影响
由于 Web 服务器可以访问管理面板,因为它们位于同一网络中,并且没有针对内部流量的附加防火墙规则,因此攻击者可以收集有关网络的附加信息并访问内部服务器和服务。这是一个合法的 SSRF 漏洞。并非所有 SSRF 漏洞都会向攻击者返回响应。这称为盲 SSRF 漏洞。这是一个代码示例:
要求“sinatra” 要求“open-uri”
获取“/”执行 打开参数[:url]
“完成” 结束
与博客文章中第一个代码示例的区别在于,此脚本将对传递给url参数的任何内容发出 HTTP 请求,但始终将完成的字符串返回给攻击者。如果发生这种情况,影响通常仅限于服务发现和端口扫描(见下文)。
暴露内部/防火墙系统
SSRF 漏洞的一个很好的演示是揭示一个无法通过互联网访问的系统。每当您想要实现这一目标时,请牢记该计划的政策并且不要超越任何界限。如果您确实想要查找内部服务,这里有您可以扫描服务的专用 IPv4 网络的列表:
- 10.0.0.0/8
- 127.0.0.1/32
- 172.16.0.0/12
- 192.168.0.0/16
技巧:要发现哪些网络是内部路由的,请尝试查看响应的时间差。未路由的网络通常会立即被路由器丢弃(时间略有增加)。内部防火墙规则通常会导致路由网络增加 RTT(更大的时间增加)。另外,请记住,路由器和交换机通常启用 HTTP 或 SSH 接口,因此首先在端口 22、80、443、8080 和 8443 上尝试 .1 和 .254 地址通常会获得成功。
服务发现和端口扫描
SSRF 漏洞有时可用于在本地网络中运行端口扫描。这可能有助于绘制基础设施的外观,并有助于计划利用其他漏洞。这通常是(盲)SSRF 最简单的演示。像上面所示的脚本在无法连接或未从服务器获得响应时会引发异常或返回错误。这可以帮助识别端口是“打开”(建立连接)还是“关闭”(连接被拒绝或连接超时)。
网址参数 | 响应 HTTP 状态 | 实时传输时间 | 结论 | http://127.0.0.1:22 | 200 | 10毫秒 | 端口已开放 | http://127.0.0.1:23 | 500 | 10毫秒 | 端口已关闭 | http://10.0.0.1/ | 500 | 30010毫秒 | 受防火墙保护或无法将流量路由到服务器 | http://10.0.0.1:8080/ | 500 | 10毫秒 | 端口关闭,流量路由到服务器 |
每个 SSRF 对开放和关闭端口的响应都不同。尝试映射标识符并据此检测开放和关闭的端口。上表是此类表格的示例。
提取 EC2 配置文件
这是我最喜欢的技巧之一。越来越多的公司将其部分基础设施托管在 Amazon EC2 上。Amazon 公开了一个内部服务,每个 EC2 实例都可以查询有关主机的实例元数据。这是 AWS 文档。如果您发现在 EC2 上运行的 SSRF 漏洞,请尝试请求http://169.254.169.254/latest/meta-data/。这将返回大量有用的信息,供您了解基础设施,并可能会泄露 Amazon S3 访问令牌、API 令牌等。您可能还需要下载http://169.254.169.254/latest/user-data/并解压缩数据。
枢轴
正如您可能猜到的那样,并非所有 SSRF 漏洞都使用 HTTP 协议。有时,可以指定不同的协议或通过重定向切换协议。将 SSRF 升级为远程代码执行 (RCE) 的一个很酷的方法是将异步作业推送到 Redis 队列上,然后由使用 gopher:// 协议的应用程序执行。许多 Redis 实例不使用任何形式的身份验证,这确实很方便。然而,考虑到您必须进行的调试,利用这一点值得有自己的博客文章。另一篇博文的内容!
与此同时,枢轴通常来自已发现的内部服务,这些服务允许您增加漏洞的影响,例如,当您发现未经身份验证的管理面板时。如果程序允许,请考虑如何使用内部服务来链接多个漏洞,以提高发现的影响。
快乐黑客!
乔伯特
ps – 这里描述的很多技术都可以使用我的 GitHub 个人资料上的这个存储库进行调试。去看看吧;欢迎 PR!
|