全面解析Web缓存利用:突破规则限制的技术探索

本文深入探讨了Web缓存利用中的关键技术,包括URL解析差异、缓存规则滥用、路径混淆攻击等,揭示了CDN和服务器解析不一致导致的安全风险,并提供了多种攻击与防御方法。

全面解析Web缓存利用:突破规则限制的技术探索

多年来,我们已经看到许多攻击利用Web缓存来劫持敏感信息或存储恶意负载。然而,随着CDN的普及,专有URL解析器之间的新差异表明我们只看到了冰山一角。

本文将探讨不同HTTP服务器和代理在解析特制URL时的行为,并探索RFC中导致路径混淆的模糊性。它还将介绍一系列新技术,可用于利用解析器差异,在无数网站和CDN提供商中实现任意Web缓存中毒和欺骗。

背景

Web缓存

Web缓存自互联网诞生以来就一直存在。该技术通过使用密钥对请求进行指纹识别来工作,在大多数情况下,密钥将使用请求URL的部分或全部部分构建,并将密钥与存储的静态响应映射。

近年来,大多数生产系统通过设置内容分发网络(CDN)来整合缓存,如CloudFlare、Akamai或CloudFront。CDN可以看作是一个分布在全球的Web缓存代理网络。它们提供静态响应,提高系统的效率和可扩展性。

本文重点研究不同应用服务器和CDN代理之间存在的URL解析差异,但相同技术可应用于任何类型的Web缓存,包括集成在源服务器本身的缓存。

中毒和欺骗

由于Web缓存在现代系统中扮演关键角色,研究人员一直在寻找利用它们存储动态信息的方法。这些信息可用于获取敏感数据或传递恶意负载。这些攻击通常针对两个过程之一:密钥生成或缓存规则分析。

计算密钥至关重要,因为每个具有相同指纹的请求都应生成相同的响应,无论何时发送或包含什么额外信息(如正文或额外标头)。如果响应根据特定标头的值而变化,则该值应成为密钥的一部分。存储旨在匹配错误密钥的恶意负载消息称为Web缓存中毒。

缓存规则旨在识别响应是否为静态并应存储。未能缓存静态资源可能会影响性能,但存储包含用于认证用户的敏感信息的动态响应可能对应用程序造成毁灭性影响。如果攻击者能够制作恶意请求以检索和缓存用户数据,他们可能能够劫持令牌和API密钥,可能导致完全账户接管。这被称为Web缓存欺骗。

URL差异

为了评估缓存规则、计算缓存密钥和映射端点处理程序,源服务器必须提取所请求资源的绝对路径。这是通过使用路径分隔符和规范化解析URL来完成的。

如果缓存和应用服务器的解析器不同,则可能利用差异来改变URL的含义。这可能使您能够控制存储哪些响应以及用于访问它们的密钥。

分隔符

URL RFC将某些字符定义为分隔符,例如分号或问号。然而,规范相当宽松,允许每个实现向此列表添加自定义字符。

这项研究表明,许多流行框架和HTTP服务器使用不同的字符作为分隔符。这可能在源服务器和缓存解析器之间创建路径混淆。

源分隔符

以下自定义分隔符用于各种应用服务器和框架:

  • Spring中的分号:在许多Java框架中,包括Spring,分号用作分隔符以包含矩阵变量。矩阵变量可以包含在每个路径段中,并不解释为绝对路径的一部分。

    • URL: /MyAccount;var1=val → 路径: /MyAccount
    • URL: /hello;var=a/world;var1=b;var2=c → 路径: /hello/world
  • Rails中的点:Ruby on Rails允许客户端发送带有格式化器扩展的路径,该扩展定义响应中返回的视图。这用于返回具有不同内容类型的不同响应。如果未使用扩展或服务器未识别扩展,则返回默认HTML视图。因此,点字符可以充当路径分隔符。

    • URL: /MyAccount.html → 路径: /MyAccount(默认HTML视图)
    • URL: /MyAccount.css → 路径: /MyAccount(CSS视图或错误(如果不存在))
    • URL: /MyAccount.aaaa → 路径: /MyAccount(默认HTML视图)
  • OpenLiteSpeed中的空编码字节:此HTTP服务器使用空编码字节作为经典分隔符来截断路径。

    • URL: /MyAccount%00aaa → 路径: /MyAccount
  • Nginx中的换行编码字节:当Nginx配置为重写请求路径时,编码的换行字节用作路径分隔符。重写规则必须映射前缀或URL,而不是整个路径名(这在Nginx中很常见)。

    • 规则: rewrite /user/(.*) /account/$1 break;
    • URL: /users/MyAccount%0aaaa → 路径: /account/MyAccount

检测源分隔符

  1. 识别不可缓存请求。寻找具有非幂等方法(如POST)的请求,或具有Cache-Control: no-store或Cache-Control: private标头的响应。响应(R0)将用于比较URL中有趣字符的行为。
  2. 发送相同的请求,但这次在路径末尾附加随机后缀,例如,如果原始路径为/home,则发送请求到/homeabcd。如果响应(R1)与R0相同,则使用不同端点重复步骤1和2。
  3. 发送与步骤2相同的请求,但在随机后缀前包含潜在分隔符。如果测试的分隔符是$,则路径应类似于/home$abcd。将此响应(R2)与基础响应(R0)比较。如果消息相同,则该字符或字符串用作分隔符。

要同时测试多个可能的分隔符,可以使用Burp Intruder和包含所有ASCII字符的单词列表。确保测试字符的未编码和URL编码版本。

检测缓存分隔符

缓存服务器通常除了问号外不使用分隔符。可以使用静态请求和响应测试此点:

  1. 通过寻找响应从缓存中检索的证据来识别可缓存请求。例如,通过响应时间分析,或寻找值为hit的X-Cache标头。此响应(R0)将用于比较URL中有趣字符的行为。
  2. 发送相同的请求,URL路径后缀后跟可能的分隔符和随机值。GET /static-endpoint
  3. 将响应与R0比较。如果消息相同,则该字符或字符串用作分隔符。

规范化

URL解析器被缓存和源服务器用于提取路径以进行端点映射、缓存密钥和规则。首先,识别路径分隔符以定位路径名的开始和结束。一旦提取路径,通过解码字符和删除点段将其规范化为绝对形式。

编码

有时,需要发送分隔符字符以供应用程序解释而不是HTTP解析器。对于这种情况,URI RFC定义了URL编码,允许对字符进行编码以避免修改路径名的含义。

许多HTTP服务器和代理,包括Nginx、Node、CloudFlare、CloudFront和Google Cloud,在解释路径名之前解码某些分隔符字符。更糟糕的是,这个过程不一致。这意味着即使没有任何自定义配置,相同的URL在最流行的CDN和源服务器中也会有不同的含义。

此外,RFC未指定应如何转发或重写请求。许多代理解码URL并使用解码值转发消息。如果发生这种情况,下一个解析器可能使用解码字符作为分隔符。因此,如果代理收到以下请求,%3F字符将转换为问号符号: “/myAccount%3Fparam” → “/myAccount?param”

还有许多其他编码由不同的缓存代理支持。尽管大多数默认不使用,但可以配置CDN如CloudFlare或CloudFront以应用自定义转换并为缓存或访问控制目的解码路径。

检测解码行为

要测试字符是否被解码,比较基础请求与其编码版本。例如: /home/index → /%68%6f%6d%65%2f%69%6e%64%65%78 注意:单独编码每个字符可能有用,因为有时特定字符(如斜杠或其他保留字符)不被解码。

如果响应与基础响应相同且未从缓存获取(无缓存命中标头),则源服务器在使用路径之前解码路径。

如果响应可缓存,则可以检测缓存解析器的解码行为。发送原始请求后跟编码版本。如果两个响应包含相同的缓存标头,则意味着第二个是从代理获取的,并且密钥在比较之前被解码。

点段规范化

URI RFC还定义了如何处理URL中的点段,并提供了简单算法来规范化路径。虽然此功能对于从相对路径引用任何资源至关重要,但它也是许多漏洞的来源。

通过利用解析器之间的差异来修改缓存规则的行为并获得特制密钥,可以开发利用点段规范化。即使流行的HTTP服务器如Apache和Nginx完全不同的解析URL,这意味着不可能使用相同的缓存代理而不存在路径混淆漏洞。

检测点段规范化

以下技术可用于检测缓存和源服务器的点段规范化。这些测试可以使用编码路径遍历负载扩展以了解是否应用了特殊解码。为此,使用相同的请求/响应并将点段替换为编码版本。

要检测源服务器中的规范化,向已知路径发出不可缓存请求(或带有缓存破坏器的请求),然后发送带有路径遍历序列的相同消息: GET /home/index?cacheBuster GET /aaa/../home/index?cacheBuster 或 GET /aaa..\home/index?cacheBuster 如果响应相同,则意味着路径在映射资源之前被规范化。这可能在源服务器发生或在代理转发之前发生。无论哪种方式,点段被解析并可用于引用现有资源。

要检测Web缓存中的规范化,重复相同过程但使用可缓存响应,并比较X-Cache和Cache-Control标头以验证资源是否从缓存内存获取。

规范化差异

以下表格说明了不同HTTP服务器和Web缓存代理如何规范化路径/hello/..%2fworld。有些将路径解析为/world,而其他根本不规范化它。

任意Web缓存欺骗

当Web缓存从源服务器接收响应时,它必须决定资源是否为静态并因此应存储。这涉及将预定义的可定制规则应用于请求和响应。

本节重点研究使用URL确定响应是否应缓存的规则。这些在生产环境中很流行,大多数CDN默认包含其中一些规则。

可以利用解析差异来利用缓存规则,存储动态响应并劫持为受害者生成的敏感信息。关于如何使用URL映射中的差异创建路径混淆的详细解释可以在Omer Gil的白皮书《Web缓存欺骗攻击》中找到。

本白皮书重点研究其他类型的差异,可用于劫持任何任意响应,而不仅仅是那些在源服务器具有特殊端点映射的响应。

限制

由于攻击者需要生成由受害者浏览器使用的链接,负载必须仅包含安全URL字符 - 浏览器在发送之前不会编码的字符。

要可视化此场景,将浏览器视为通过编码某些字符和删除段来重写请求URL的代理。

静态扩展

大多数CDN提供商,如CloudFlare和Akamai,存储具有静态扩展的资源的响应。这意味着如果请求的路径以字符串如.js或.css结尾,缓存代理将响应视为静态。它存储响应并用于服务请求相同路径的其他客户端。

每个CDN或缓存代理定义其自己的识别静态扩展列表。下图显示了CloudFlare列出的那些:

利用静态扩展

当字符被源服务器用作分隔符但缓存不使用

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计