【Academy】Web 缓存欺骗 ------ Web cache deception
Web 缓存欺骗 ------ Web cache deception
- 1. 概述
- 2. Web 缓存
- 2.1 缓存键
- 2.2 缓存规则
- 3. 构建 Web 缓存欺骗攻击
- 3.1 使用缓存破坏器
- 3.2 检测缓存的响应
- 4. 利用静态扩展缓存规则
- 4.1 路径映射差异
- 4.2 利用路径映射差异
- 4.3 分隔符差异
- 4.4 利用分隔符差异
- 4.5 分隔符解码差异
- 4.6 利用分隔符解码差异
- 5. 利用静态目录缓存规则
- 5.1 标准化差异
- 5.2 通过源服务器检测规范化
- 5.3 通过缓存服务器检测规范化
- 5.4 利用源服务器的规范化
- 5.5 利用缓存服务器的规范化
- 6. 利用文件名缓存规则
- 6.1 检测规范化差异
- 6.2 利用规范化差异
- 7. 防止 Web 缓存欺骗漏洞
1. 概述
Web 缓存欺骗是一种漏洞,使攻击者能够欺骗 Web 缓存来存储敏感的动态内容。这是由缓存服务器和源服务器处理请求的方式之间的差异引起的。
在 Web 缓存欺骗攻击中,攻击者诱使受害者访问恶意 URL,诱使受害者的浏览器对敏感内容发出模棱两可的请求。缓存将此错误解释为对静态资源的请求并存储响应。然后,攻击者可以请求相同的 URL 来访问缓存的响应,从而获得对私人信息的未经授权的访问。
注意
区分 Web 缓存欺骗和 Web 缓存中毒非常重要。虽然两者都利用缓存机制,但它们以不同的方式进行:
- Web 缓存中毒会操纵缓存键,将恶意内容注入缓存响应中,然后将其提供给其他用户。
- Web 缓存欺骗利用缓存规则来诱骗缓存存储敏感或私人内容,然后攻击者可以访问这些内容。
2. Web 缓存
Web 缓存是位于源服务器和用户之间的系统。当客户端请求静态资源时,请求首先被定向到缓存。如果缓存不包含资源的副本(称为缓存未命中),则请求将转发到源服务器,该服务器将处理并响应请求。然后,响应将发送到缓存,然后再发送给用户。缓存使用一组预配置的规则来确定是否存储响应。
当将来对同一静态资源发出请求时,缓存会将存储的响应副本直接提供给用户(称为缓存命中)。
缓存已成为交付 Web 内容的常见且关键的方面,尤其是随着内容交付网络 (CDN) 的广泛使用,CDN使用缓存将内容副本存储在世界各地的分布式服务器上。CDN 通过从离用户最近的服务器提供内容来加快交付速度,通过最小化数据传输距离来缩短加载时间。
2.1 缓存键
当缓存收到 HTTP 请求时,它必须确定是否有可以直接提供的缓存响应,或者是否必须将请求转发到源服务器。缓存通过从 HTTP 请求的元素生成“缓存键”来做出此决定。通常,这包括 URL 路径和查询参数,但它也可以包括各种其他元素,如标题和内容类型。
如果传入请求的缓存键与前一个请求的缓存键匹配,则缓存会认为它们是等效的,并提供缓存响应的副本。
2.2 缓存规则
缓存规则确定可以缓存的内容和缓存时间。缓存规则通常设置为存储静态资源,这些资源通常不会经常更改,并且可以在多个页面中重复使用。动态内容不会被缓存,因为它更有可能包含敏感信息,从而确保用户直接从服务器获取最新数据。
Web 缓存欺骗攻击利用缓存规则的应用方式,因此了解一些不同类型的规则非常重要,尤其是那些基于请求 URL 路径中定义的字符串的规则。例如:
- 静态文件扩展名规则 - 这些规则与请求资源的文件扩展名匹配,例如,
.css
用于样式表或.js
用于 JavaScript 文件。 - 静态目录规则 - 这些规则匹配以特定前缀开头的所有 URL 路径。这些通常用于定位仅包含静态资源的特定目录,例如
/static
或/assets
。 - 文件名规则 - 这些规则将特定文件名与 Web作普遍需要且很少更改的目标文件进行匹配,例如
robots.txt
和favicon.ico
。
缓存还可以根据其他条件(如 URL 参数或动态分析)实施自定义规则。
3. 构建 Web 缓存欺骗攻击
一般来说,构建基本的 Web 缓存欺骗攻击包括以下步骤:
-
确定返回包含敏感信息的动态响应的目标终端节点。在 Burp 中查看响应,因为某些敏感信息在呈现的页面上可能不可见。重点关注支持
GET
、HEAD
或OPTIONS
方法的终端节点,因为更改源服务器状态的请求通常不会缓存。 -
确定缓存和源服务器解析 URL 路径的方式存在差异。这可能是他们如何:
- 将 URL 映射到资源。
- 处理分隔符字符。
- 规范化路径。
-
制作一个恶意 URL,该 URL 利用差异来欺骗缓存以存储动态响应。当受害者访问 URL 时,他们的响应将存储在缓存中。然后,使用 Burp,您可以向同一 URL 发送请求,以获取包含受害者数据的缓存响应。请避免直接在浏览器中执行此作,因为某些应用程序会在没有会话的情况下重定向用户或使本地数据失效,这可能会隐藏漏洞。
我们将探索构建 Web 缓存欺骗攻击的一些不同方法。
3.1 使用缓存破坏器
在测试差异和测试 Web 缓存欺骗漏洞时,请确保您发送的每个请求都有不同的缓存key。否则,您可能会收到缓存的响应,这将影响您的测试结果。
由于 URL 路径和任何查询参数通常都包含在缓存键中,因此你可以通过向路径添加查询字符串并在每次发送请求时更改它来更改键。使用 Param Miner 扩展自动执行此过程。为此,安装扩展程序后,单击顶级 Param miner > Settings 菜单,然后选择 Add dynamic cachebuster。Burp 现在会为您发出的每个请求添加唯一的查询字符串。您可以在 Logger (记录器) 选项卡中查看添加的查询字符串。
3.2 检测缓存的响应
在测试期间,能够识别缓存的响应至关重要。为此,请查看响应标头和响应时间。
各种响应标头可能指示它已被缓存。例如:
X-Cache
标头提供有关是否从缓存提供响应的信息。典型值包括:X-Cache: hit
- 响应是从缓存中提供的。X-Cache: miss
- 缓存中没有针对请求键的响应,因此从源服务器获取了该响应。在大多数情况下,响应随后会被缓存。要确认这一点,请再次发送请求以查看值是否更新为命中。X-Cache: dynamic
- 源服务器动态生成内容。通常,这意味着响应不适合缓存。X-Cache: refresh
- 缓存的内容已过时,需要刷新或重新验证。
Cache-Control
标头可能包含指示缓存的指令,例如max-age
大于0
的public
。请注意,这仅表明资源是可缓存的。它并不总是表示缓存,因为缓存有时可能会覆盖此标头。
如果您注意到同一请求的响应时间存在很大差异,这也可能表明缓存提供的响应速度更快。
4. 利用静态扩展缓存规则
缓存规则通常通过匹配常见文件扩展名(如 .css
或 .js
)来定位静态资源。这是大多数 CDN 中的默认行为。
如果缓存和源服务器将 URL 路径映射到资源或使用分隔符的方式存在差异,则攻击者可能能够使用静态扩展名创建动态资源请求,该扩展名被源服务器忽略,但被缓存查看。
4.1 路径映射差异
URL 路径映射是将 URL 路径与服务器上的资源(如文件、脚本或命令执行)相关联的过程。不同的框架和技术使用一系列不同的映射样式。两种常见的样式是传统 URL 映射和 RESTful URL 映射。
传统 URL 映射表示指向位于文件系统上的资源的直接路径。下面是一个典型的示例:
http://example.com/path/in/filesystem/resource.html
http://example.com
指向服务器。/path/in/filesystem/
表示服务器文件系统中的目录路径。resource.html
是正在访问的特定文件。
相比之下,REST 样式的 URL 并不直接与物理文件结构匹配。它们将文件路径抽象为 API 的逻辑部分:
http://example.com/path/resource/param1/param2
http://example.com
指向服务器。/path/resource/
是表示资源的终端节点。param1
和param2
是服务器用于处理请求的路径参数。
缓存和源服务器将 URL 路径映射到资源的方式存在差异,可能会导致 Web 缓存欺骗漏洞。请考虑以下示例:
http://example.com/user/123/profile/wcd.css
- 使用 REST 样式 URL 映射的源服务器可能会将此解释为对端点的请求
/user/123/profile
并返回用户123
的配置文件信息,而忽略wcd.css
作为非重要参数。 - 使用传统 URL 映射的缓存可能会将此视为对位于
/user/123
下的/profile
目录中的名为wcd.css
的文件的请求。它将 URL 路径解释为/user/123/profile/wcd.css
。如果缓存配置为存储路径以.css
结尾的请求的响应,则它将缓存和提供配置文件信息,就像它是CSS
文件一样。
4.2 利用路径映射差异
要测试源服务器如何将 URL 路径映射到资源,请将任意路径段添加到目标终端节点的 URL。如果响应仍包含与基本响应相同的敏感数据,则表示源服务器抽象了 URL 路径并忽略了添加的分段。例如,如果将 /api/orders/123
修改为 /api/orders/123/foo
仍返回订单信息,则会出现这种情况。
要测试缓存如何将 URL 路径映射到资源,您需要修改路径以尝试通过添加静态扩展来匹配缓存规则。例如,将 /api/orders/123/foo
更新为 /api/orders/123/foo.js
。如果缓存了响应,则表示:
- 缓存使用静态扩展名解释完整的 URL 路径。
- 有一个缓存规则来存储以 .js 结尾的请求的响应。
缓存可能具有基于特定静态扩展的规则。尝试一系列扩展,包括 .css
、.ico
和 .exe
。
然后,你可以构造一个 URL,该 URL 返回存储在缓存中的动态响应。请注意,此攻击仅限于你测试的特定端点,因为源服务器通常对不同的端点有不同的抽象规则。
注意
Burp Scanner 会自动检测审计期间由路径映射差异引起的 Web 缓存欺骗漏洞。您还可以使用 Web Cache Deception Scanner BApp 来检测配置错误的 Web 缓存。
4.3 分隔符差异
分隔符指定 URL 中不同元素之间的边界。使用字符和字符串作为分隔符通常是标准化的。例如,?
通常用于将 URL 路径与查询字符串分开。但是,由于 URI RFC 非常宽松,因此不同的框架或技术之间仍然存在差异。
缓存和源服务器使用字符和字符串作为分隔符的方式存在差异,可能会导致 Web 缓存欺骗漏洞。请考虑示例 /profile;foo.css
:
- Java Spring 框架使用
;
字符添加称为矩阵变量的参数。因此,使用 Java Spring 的源服务器会将;
解释为分隔符。它会截断/profile
之后的路径并返回配置文件信息。 - 大多数其他框架不使用
;
作为分隔符。因此,不使用 Java Spring 的缓存可能会解释;
以及它之后的所有内容作为路径的一部分。如果缓存具有存储以.css
结尾的请求的响应的规则,则它可能会缓存和提供配置文件信息,就像它是 CSS 文件一样。
对于在框架或技术之间使用不一致的其他字符也是如此。考虑对运行 Ruby on Rails 框架的源服务器发出的这些请求,该框架使用 .
作为分隔符来指定响应格式:
/profile
- 此请求由默认 HTML 格式化程序处理,该格式化程序返回用户配置文件信息。/profile.css
- 此请求被识别为 CSS 扩展。没有 CSS 格式化程序,因此不接受请求并返回错误。/profile.ico
- 此请求使用 .ico 扩展,Ruby on Rails 无法识别该扩展。默认 HTML 格式化程序处理请求并返回用户配置文件信息。在这种情况下,如果缓存配置为存储以.ico
结尾的请求的响应,它将缓存和提供配置文件信息,就像它是静态文件一样。
编码字符有时也可以用作分隔符。例如,考虑 request/profile%00foo.js
:
- OpenLiteSpeed 服务器使用编码的 null
%00
字符作为分隔符。因此,使用 OpenLiteSpeed 的源服务器会将路径解释为/profile
。 - 大多数其他框架如果 URL 中存在
%00
会以错误响应。然而,如果缓存使用 Akamai 或 Fastly,它会将%00
及其后的所有内容解释为路径。
4.4 利用分隔符差异
你或许可以利用分隔符差异向缓存所看到的路径添加一个静态扩展,但对源服务器无效。要做到这一点,你需要确定一个字符,该字符被源服务器用作分隔符,但不被缓存使用。
首先,查找源服务器用作分隔符的字符。通过向目标终端节点的 URL 添加任意字符串来启动此过程。例如,将 /settings/users/list
修改为 /settings/users/listaaa
。当您开始测试分隔符时,您将使用此响应作为参考。
注意
如果响应与原始响应相同,则表示请求正在重定向。您需要选择其他终端节点进行测试。
接下来,在原始路径和任意字符串之间添加可能的分隔符,例如 /settings/users/list;aaa
:
- 如果响应与基本响应相同,则表示
;
字符用作分隔符,源服务器将路径解释为/settings/users/list
。 - 如果它与具有任意字符串的路径的响应匹配,则表示
;
字符不用作分隔符,源服务器将路径解释为/settings/users/list;aaa
一旦你确定了源服务器使用的分隔符,请测试缓存是否也使用这些分隔符。为此,在路径末尾添加一个静态扩展名。如果响应被缓存,这表明:
- 缓存不使用分隔符,并使用静态扩展名解释完整的 URL 路径。
- 有一个缓存规则来存储以
.js
结尾的请求的响应。
确保测试所有 ASCII 字符和一系列常见扩展名,包括 .css
、.ico
和 .exe
。使用 Burp Intruder 快速测试这些字符。要防止 Burp Intruder 对分隔符字符进行编码,请在 Payloads (负载) 侧面板的 Payload encoding (负载编码) 下关闭 Burp Intruder 的自动字符编码。
然后,您可以构建一个触发静态扩展缓存规则的漏洞。例如,考虑有效负载 /settings/users/list;aaa.js
. 源服务器使用 ;
作为分隔符:
- 缓存将路径解释为:
/settings/users/list;aaa.js
- 源服务器将路径解释为:
/settings/users/list
源服务器返回存储在缓存中的动态配置文件信息。
由于分隔符通常在每个服务器中一致地使用,因此您通常可以在许多不同的端点上使用此攻击。
注意
受害者的浏览器可能会在将请求转发到缓存之前处理一些分隔符。这意味着某些分隔符不能在漏洞利用中使用。例如,浏览器对 {
、}
、<
和 >
等字符进行 URL 编码,并使用 #
截断路径。
如果缓存或源服务器对这些字符进行解码,则有可能在漏洞利用中使用编码版本。
4.5 分隔符解码差异
网站有时需要在 URL 中发送包含在 URL 中具有特殊含义的字符(如分隔符)的数据。为了确保这些字符被解释为数据,通常会对它们进行编码。但是,某些解析器会在处理 URL 之前对某些字符进行解码。如果解码了分隔符,则可以将其视为分隔符,从而截断 URL 路径。
缓存和源服务器解码的分隔符的差异可能会导致它们解释 URL 路径的方式存在差异,即使它们都使用与分隔符相同的字符也是如此。请考虑示例 /profile%23wcd.css
,它使用 URL 编码的 #
字符:
- 源服务器将
%23
解码为#
。它使用#
作为分隔符,因此它将路径解释为/profile
并返回配置文件信息。 - 缓存还使用
#
字符作为分隔符,但不解码%23
。它将路径解释为/profile%23wcd.css
。如果.css
扩展有缓存规则,它将存储响应。
此外,某些缓存服务器可能会对 URL 进行解码,然后使用解码后的字符转发请求。其他服务器首先根据编码的 URL 应用缓存规则,然后解码 URL 并将其转发到下一个服务器。这些行为还可能导致缓存和源服务器解释 URL 路径的方式出现差异。请考虑示例 /myaccount%3fwcd.css
:
- 缓存服务器根据编码路径
/myaccount%3fwcd.css
应用缓存规则,并决定存储响应,因为.css
扩展存在缓存规则。然后,它将%3f
解码为?
,并将重写的请求转发到源服务器。 - 源服务器收到请求
/myaccount?wcd.css
。它使用?
字符作为分隔符,因此它将路径解释为/myaccount
。
4.6 利用分隔符解码差异
你或许可以利用解码差异,通过使用编码分隔符向路径添加一个静态扩展名,这个路径是缓存可见的,但源服务器不可见。
使用你用于识别和利用分隔符差异的相同测试方法,但使用一系列编码字符。确保你还测试编码的不可打印字符,特别是%00
、%0A
和%09
。如果这些字符被解码,它们也可以截断 URL 路径。
5. 利用静态目录缓存规则
Web 服务器通常将静态资源存储在特定目录中。缓存规则通常通过匹配特定的 URL 路径前缀(如 /static
、/assets
、/scripts
或 /images
)来定位这些目录。这些规则也可能容易受到 Web 缓存欺骗的攻击。
注意
要利用静态目录缓存规则,您需要了解路径遍历攻击的基础知识。
5.1 标准化差异
标准化涉及将 URL 路径的各种表示形式转换为标准化格式。这有时包括解码编码字符和解析点段,但不同的解析器之间差异很大。
缓存和源服务器在规范化 URL 方式上的差异可能会使攻击者能够构建一个路径遍历有效载荷,每个解析器对其的解释都不同。考虑以下示例/static/..%2fprofile
:
- 解码斜杠字符并解析点段的源服务器将规范化路径到
/profile
并返回配置文件信息。 - 不解析点段或解码斜杠的缓存会将路径解释为
/static/..%2fprofile
。如果缓存存储带有/static
前缀的请求的响应,它将缓存并提供配置文件信息。
如上述示例所示,路径遍历序列中的每个点段都需要进行编码。否则,受害者的浏览器会在将请求转发到缓存之前对其进行解析。因此,可利用的规范化差异要求缓存或源服务器对路径遍历序列中的字符进行解码,并解析点段。
5.2 通过源服务器检测规范化
为了测试源服务器如何规范化 URL 路径,请向带有路径遍历序列和路径开头的任意目录的不可缓存资源发送请求。为了选择不可缓存的资源,请查找像POST这样的非幂等方法。例如,将/profile
修改为/aaa/..%2fprofile
:
- 如果响应与基本响应匹配并返回配置文件信息,则表示路径已被解释为
/profile
。源服务器对斜杠进行解码并解码点段。 - 如果响应与基本响应不匹配,例如返回 404 错误消息,则表示路径已被解释为
/aaa/..%2fprofile
。源服务器要么不解码斜杠,要么不解析点段。
注意
在测试规范化时,首先仅对点段中的第二个斜杠进行编码。这很重要,因为一些内容分发网络(CDN)会匹配静态目录前缀后的斜杠。
你也可以尝试对完整的路径遍历序列进行编码,或者对点而不是斜杠进行编码。这有时会影响解析器是否解码序列。
5.3 通过缓存服务器检测规范化
您可以使用几种不同的方法来测试缓存如何规范化路径。首先确定潜在的静态目录。在 Proxy > HTTP history (代理 HTTP 历史记录) 中,查找具有常见静态目录前缀和缓存的响应的请求。通过将 HTTP 历史记录筛选条件设置为仅显示具有 2xx 响应和脚本、图像和 CSS MIME 类型的消息,专注于静态资源。
然后,您可以选择具有缓存响应的请求,并在静态路径的开头使用路径遍历序列和任意目录重新发送请求。选择响应包含缓存证据的请求。例如,/aaa/..%2fassets/js/stockCheck.js
:
- 如果响应不再缓存,则表示缓存在将路径映射到终端节点之前未对路径进行规范化。它显示存在基于
/assets
前缀的缓存规则。 - 如果响应仍被缓存,这可能表示缓存已将路径规范化到
/assets/js/stockCheck.js
。
您还可以在目录前缀后添加路径遍历序列。例如,将 /assets/js/stockCheck.js
修改为 /assets/..%2fjs/stockCheck.js
:
- 如果响应不再缓存,则表示缓存在规范化期间解码斜杠并解析点段,将路径解释为
/js/stockCheck.js
。它显示存在基于/assets
前缀的缓存规则。 - 如果响应仍被缓存,这可能表示缓存尚未解码斜杠或解析点段,将路径解释为
/assets/..%2fjs/stockCheck.js
。
请注意,在这两种情况下,响应都可能由于其他缓存规则(例如基于文件扩展名的缓存规则)而被缓存。要确认缓存规则是否基于静态目录,请将目录前缀后的 path 替换为任意字符串。例如,/assets/aaa
。如果响应仍处于缓存状态,则确认缓存规则基于 /assets
前缀。请注意,如果响应似乎没有缓存,这不一定排除静态目录缓存规则,因为有时 404 响应不会缓存。
注意
如果不尝试利用漏洞,您可能无法明确确定缓存是否解码点段并解码 URL 路径。
5.4 利用源服务器的规范化
如果源服务器解析编码的点段,但缓存没有解析,您可以尝试根据以下结构构建有效负载来利用差异:
/<static-directory-prefix>/..%2f<dynamic-path>
例如,请考虑有效负载 /assets/..%2fprofile
:
缓存将路径解释为:/assets/..%2fprofile
源服务器将路径解释为:/profile
源服务器返回存储在缓存中的动态配置文件信息。
5.5 利用缓存服务器的规范化
如果缓存服务器解析编码的点段,但源服务器没有解析,您可以尝试根据以下结构构建有效负载来利用差异:
/<dynamic-path>%2f%2e%2e%2f<static-directory-prefix>
注意
当缓存服务器利用规范化时,对路径遍历序列中的所有字符进行编码。使用编码字符有助于避免使用分隔符时的意外行为,并且无需在静态目录前缀后使用未编码的斜杠,因为缓存将处理解码。
在这种情况下,仅靠路径遍历不足以进行漏洞利用。例如,考虑缓存和源服务器如何解释有效负载 /profile%2f%2e%2e%2fstatic
:
- 缓存将路径解释为:
/static
- 源服务器将路径解释为:
/profile%2f%2e%2e%2fstatic
源服务器可能会返回错误消息,而不是配置文件信息。
要利用此差异,您还需要确定源服务器使用但缓存未使用的分隔符。通过将可能的分隔符添加到动态路径后的有效负载中来测试可能的分隔符:
- 如果源站使用分隔符,它将截断 URL 路径并返回动态信息。
- 如果缓存不使用分隔符,它将解析路径并缓存响应。
例如,请考虑有效负载 /profile;%2f%2e%2e%2fstatic
。源服务器使用 ;
作为分隔符:
- 缓存将路径解释为:
/static
- 源服务器将路径解释为:
/profile
源服务器返回存储在缓存中的动态配置文件信息。因此,您可以将此负载用于漏洞利用。
6. 利用文件名缓存规则
某些文件(如 robots.txt
、index.html
和 favicon.ico
是 Web 服务器上的常见文件。由于更改不频繁,它们通常会被缓存。缓存规则通过匹配确切的文件名字符串来定位这些文件。
要确定是否存在文件名缓存规则,请为可能的文件发送 GET 请求,并查看响应是否已缓存。
6.1 检测规范化差异
要测试源服务器如何规范化 URL 路径,请使用用于静态目录缓存规则的相同方法。有关更多信息,请参阅通过源服务器检测规范化。
要测试缓存如何规范化 URL 路径,请发送一个请求,其中包含路径遍历序列和文件名前的任意目录。例如,/aaa%2f%2e%2e%2findex.html
:
- 如果缓存了响应,则表示缓存会将路径规范化为
/index.html
。 - 如果未缓存响应,则表示缓存不会解码斜杠并解析点段,而是将路径解释为
/profile%2f%2e%2e%2findex.html
。
6.2 利用规范化差异
因为只有当请求与确切的文件名匹配时,响应才会被缓存,所以只有在缓存服务器解析编码的点段而源服务器不解析时,才能利用差异。使用与静态目录缓存规则相同的方法——只需将静态目录前缀替换为文件名。有关更多信息,请参阅利用缓存服务器的规范化。
7. 防止 Web 缓存欺骗漏洞
您可以采取一系列措施来防止 Web 缓存欺骗漏洞:
- 始终使用
Cache-Control
标头来标记动态资源,使用指令no-store
和private
进行设置。 - 配置您的 CDN 设置,以便您的缓存规则不会覆盖
Cache-Control
标头。 - 激活 CDN 针对 Web 缓存欺骗攻击的任何保护。许多 CDN 允许您设置缓存规则,以验证响应
Content-Type
是否与请求的 URL 文件扩展名匹配。例如,Cloudflare 的 Cache Deception Armor。 - 验证源服务器和缓存解释 URL 路径的方式之间是否没有任何差异。