实用的 HTTP 标头走私:通过反向代理攻击 AWS - 嘶吼 RoarTalk – 回归最本质的信息安全,互联网安全新媒体,4hou.com

实用的 HTTP 标头走私:通过反向代理攻击 AWS

xiaohui 技术 2021-11-24 11:55:00
收藏

导语:本文提出了一种新的识别标题走私的技术,并演示了标题走私如何导致缓存攻击、IP限制绕过和请求走私。

现代 Web 应用程序通常依赖于多台服务器链,它们相互转发HTTP请求。这种转发创建的攻击面越来越受到关注,包括最近流行的缓存攻击和请求走私漏洞。最近的请求走私研究,已经开发出新的方法来隐藏链中某些服务器的 HTTP 请求标头,同时让其他服务器看到它们——这种技术被称为“标头走私”。本文提出了一种新的识别标题走私的技术,并演示了标题走私如何导致缓存攻击、IP限制绕过和请求走私。

Web 应用程序使用的 HTTP 服务器链通常可以建模为由两个组件组成:

◼直接处理来自用户请求的“前端”服务器,这些服务器通常会处理缓存和载荷平衡,或充当 Web 应用程序防火墙 (WAF);

◼前端服务器将请求转发到的“后端”服务器,这是应用程序的服务器端代码运行的地方;

1.jpg

上述模型仅是一个简化,可能有多个前后端服务器,现实中可能有多个前端和后端服务器,而前端和后端服务器本身通常是多个服务器链。

后端服务器通常依赖前端服务器在 HTTP 请求标头中提供的准确信息,例如“X-Forwarded-For”标头中的客户端 IP 地址或“Content-Length”标头中的请求正文长度。为了准确地提供这些信息,前端服务器必须过滤掉客户端提供的这些标头的值,这些值是不可信的。

使用标头走私,可以绕过此过滤并将信息发送到它视为受信任的后端服务器。我将展示这如何导致绕过 AWS API Gateway 中的 IP 限制,以及一个易于利用的缓存攻击问题。然后,我将讨论如何调整用于发现这些漏洞的方法,以基于多个“Content-Length”标头(CL)安全地检测请求走私。

本研究开发的用于识别标头走私漏洞的方法决定了是否可以对标头应用“突变”,使其能够在不被前端服务器识别或处理的情况下潜入后端服务器。突变只是对标头的混淆。以下示例是“Content-Length”标头的变体版本:

2.png

这个方法依赖于这样一个事实:当发送一个带有无效的“Content-Length”标头的请求时,大多数web服务器都会返回一个漏洞:

请求

3.png

响应

4.png

该方法还依赖于在“Content-Length”标头的常规形式和变异形式发送有效值和无效值时对响应的比较。我们首先将常规“Content-Length”标头中的有效和无效值发送到目标:

请求

5.png

响应

6.png

请求

7.png

响应

8.png

由于在“Content-Length”标头中包含垃圾值会导致响应不同,我们可以推断链中至少有一个服务器正在解析这个标头。

此服务器链允许通过在标头名称中的空格后附加字符将标头走私到后端。因此,当我们将请求中的“Content-Length”替换为“Content-Length abcd”并再次发送请求时,我们得到以下结果:

请求

9.png

响应

10.png

请求

11.png

响应

12.png

在比较来自常规和变异的“Content-Length”标头的响应时,有三件重要的事情需要注意。第一个是每个标头中的无效值与有效值引起的响应不同。这表明链中至少有一个服务器将这些标头中的每一个解析为“Content-Length”标头。

其次,当每个标头文件中包含一个有效值时,会返回相同的响应:

请求

13.png

响应

14.png

请求

15.png

响应

16.png

这表明变异标头的存在并没有阻止任一服务器正常解析请求,这种检查对于确保突变不会使请求完全无效非常重要。

最后要注意的重要一点是,与常规标头相比,每个标头中的无效值会导致变异标头中的不同响应:

请求

17.png

响应

18.png

请求

19.png

响应

20.png

这表明,这些漏洞很可能源自链中的不同服务器。换句话说,前端服务器不会像解析常规的“Content-Length” 标头一样解析变体后的“Content-Length”标头,而后端服务器由于存在标头走私,则可以。

示例

绕过限制

◼AWS API 网关 IP 限制

在跨漏洞赏金计划扫描时,我注意到使用 AWS API Gateway 创建的 API 允许通过在空格后将字符附加到标头名称来进行标头走私,例如,将“X-My-Header: test”变异为“X-My-Header abcd: test”。我还注意到前端服务器正在重写“X-Forwarded-For”标头。

API Gateway 允许你使用以下资源策略来限制 API 访问某些 IP 地址:

21.png

此策略将访问限制为仅接受来自 IP 地址 1.2.3.4和私有范围 10.0.0.0/8 的请求。来自其他 IP 地址的请求遇到漏洞:

请求

22.png

响应

23.png

不出所料,简单地向请求添加“X-Forwarded-For”标头与 AWS 的安全控制不匹配:

要求

24.png

回复

25.png

然而,当应用一个允许标头信息走私到这个标头信息的突变时,就会授予访问权限:

请求

26.png

响应

27.png

这允许绕过 IP 限制,但在实际情况下可能很难实现。来自私有范围的地址是显而易见的猜测,但如果这些不被允许,那么就很难猜测一个已被授予访问权限的IP地址。

请求

28.png

响应

29.png

事实证明,在请求中添加标头“x - forward - for abcd: z”可以在API网关中绕过AWS资源策略的IP限制。

AWS Cognito速率限制

在渗透测试期间,我在 AWS Cognito 中发现了一个类似但非常小的漏洞。 Cognito 是一个身份验证提供程序,你可以将其集成到你的应用程序中以帮助处理身份验证。

在短时间内向“ConfirmForgotPassword”或“ForgotPassword”目标发出五次请求后,我的IP地址被暂时封锁。但是,在请求中添加“X-Forwarded-For:[0x0b]z”允许再发出 5 个请求。不幸的是,不可能在此标头中循环不同的值或有效的 IP 地址继续获得五次尝试,这意味着此漏洞的影响很小。然而,它仍然是一个很好的例子,说明如何使用头部走私来绕过速率限制。

缓存攻击

在我向AWS报告后,他们立即修复了IP限制绕过。当重新测试时,我注意到我仍然可以使用相同的变体将标头走私到后端服务器,这让我想知道是否还有其他有趣的标头值得尝试。

API 网关可能在内部使用了一些很有趣的标头,但我无法识别其中的任何一个。真正引人注目的是”Host”标头,如果我试图将这个标头偷偷传递到后端服务器会发生什么。

我使用 API Gateway 设置了两个 API:一个“受害者”API 和一个“攻击者”API:

请求

30.png

响应

31.png

请求

32.png

响应

33.png

当在常规“Host”标头旁边包含一个变异的“Host”标头时,就会出现有趣的行为:

请求

34.png

响应

35.png

API 网关正在从变异的“Host”标头中指定的 API 返回响应。这与大多数 Web 服务器的行为形成对比,后者不会将变异的“Host”标头视为“Host”标头,而是从常规“Host”标头中获取主机。当这样的服务器充当 API 网关前的缓存时,这会变得很有趣,因为它会缓存上述请求的结果,就好像它是对“victim.i.long.lat”的请求一样,即使响应是来自“attacker.i.long.lat”API。

36.jpg

为了演示这一点,我使用“AllViewer”请求策略在 API 网关前面设置了 CloudFront,这会导致所有标头都被转发。发送上述请求,然后请求“https://victim.i.long.lat/a”,显示攻击者API的响应已经存储在受害者API的缓存中:

请求

37.png

响应

38.png

请求

39.png

响应

40.png

这种缓存攻击很容易被利用,因为攻击者可以设置自己的API并返回任意路径的任意内容。这允许他们完全覆盖受害者缓存中的任何条目,有效地允许他们完全控制受害者API的内容。

请求走私

在 Black Hat USA 2020 上,Amit Klein 提出了一个基于 2 个“Content-Length”标头的请求走私(“CL.CL”请求走私)。当使用在同一连接中发送的以下请求将 Squid 用作 Abyss Web 服务器前的反向代理时,可能会触发该漏洞:

41.JPG

第一个请求以绿色显示,包含两个“Content-Length”标头,一个是变异的,另一个是未变异的。 Squid 只会解析未变异的标头文件,并将第一个请求的主体长度取为 33 字节,以蓝色显示。 Squid 然后将第二个请求作为红色显示的请求——对“/doesntexist”的“GET”请求。

另一方面,Abyss 将解析变异和未变异的“Content-Length”标头,并从变异标头中获取 0 字节的值。因此,它认为第二个请求是以蓝色开头的请求——对“/a.html”的“GET”请求。

42.jpg

这样做的总结果是,Abyss 以“/a.html”的内容响应,而 Squid 将此响应缓存到路径“/doesntexist”,从而导致缓存攻击。

Klein 的研究特别有趣,因为它表明 CL.CL 请求走私存在于现代系统中,他提出了一种使用超时安全检测请求走私的简单方法,该方法基于“内容长度”和“传输编码”标头(“CL.TE”和“TE.CL”请求走私)。此方法试图使后端期待比前端转发更多的内容,从而触发后端超时。通过首先扫描 CL.TE 请求走私,可以在测试易受攻击的系统时将影响其他用户请求的风险降至最低。

对 CL.CL 请求走私执行相同操作的尝试可能类似于以下情况:

43.png

对于前端读取未变异的“Content-Length”标头而后端读取变异版本的易受攻击的系统,这通常会导致超时。尽管在 Squid 和 Abyss 设置的情况下,不会导致超时,因为 Abyss 不会在回复“POST”请求之前等待正文发送。

当这个请求被发送到一个易受攻击的系统时,危险就来了,其中前端读取变异的标头,后端读取未变异的版本。前端服务器将转发“z”正文,后端服务器将其视为下一个请求的开始。然后套接字就被攻击了,并且由于后端服务器将请求方法视为例如“zGET”,因此另一个用户的请求失败的可能性很高。

如果我们不知道前端服务器将解析哪个“Content-Length”标头,我们既有可能会在易受攻击的系统中导致超时,也有可能发生套接字攻击,可能导致另一个用户的请求失败。

可以稍微修改用于检测标头走私的方法,以创建安全的 CL.CL 请求走私检测方法。以下示例展示了如何使用这种修改后的方法来检测 Squid 和 Abyss 中的 Klein 漏洞。

首先,使用正在测试的“Content-Length”标头对向目标系统发送 "baseline" 请求:

请求

44.png

响应

45.png

下一步是再发送两次相同的请求,在每个“Content-Length”标头中都有一个垃圾值:

请求

46.png

响应

47.png

请求

48.png

响应

49.png

比较 3 个响应,我们注意到:

包含垃圾值的请求都触发了与"baseline"响应不同的响应,这表明至少有 1 个服务器正在解析每个标头的值。

对包含垃圾值的请求的响应是不同的。这表明漏洞来自不同的服务器,因此链中的不同服务器正在解析不同版本的“Content-Length”标头。

这些情况表明潜在的 CL.CL 请求走私,当调查超出这一点时,重要的是要知道前端服务器正在解析哪个标头,以最大限度地减少使套接字攻击和影响其他用户的机会。

这可以通过发送带有单个未变异的“Content-Length”标头的请求并观察产生的漏洞来实现:

请求

50.png

响应

51.png

由于前端服务器几乎肯定会解析此请求中的“Content-Length”标头,因此产生的漏洞很可能是由前端服务器生成的。通过将此漏洞与该过程中早期生成的漏洞进行比较,我们看到它与在同一请求中发送标头“Content-Length: z”和“Content-Length abcd: 0”时生成的漏洞相同。因此,前端服务器解析未变异的“Content-Length”标头,后端服务器解析变异的1。

这些请求仅表明存在潜在的请求走私漏洞,尽管还远未确定。例如,许多服务器会处理两种形式的“Content-Length”标头,但是当它们具有不同的值时就会出现漏洞,从而无法进行请求走私。

缓解措施

防御这些类型的漏洞可能有些复杂,因为它们依赖于 Web 服务器之间实现的差异,而不是 1 个 Web 服务器中的特定漏洞。

前端服务器应避免转发格式奇怪的标头,这是 AWS 通过 API 网关采用的方法,包括编写测试来验证这种行为。这也阻止了 Cloudflare 在缓存攻击示例中使用,因为它们不会转发名称中带有空格的任何标头。

本文翻译自:https://www.intruder.io/research/practical-http-header-smuggling如若转载,请注明原文地址
  • 分享至
取消

感谢您的支持,我会继续努力的!

扫码支持

打开微信扫一扫后点击右上角即可分享哟

发表评论