Web Cache Poisoning

The cache sits between the server and the user, where it saves (caches) the responses to particular requests, usually for a fixed amount of time. If another user then sends an equivalent request, the cache simply serves a copy of the cached response directly to the user, without any interaction from the back-end. Websites are vulnerable to web cache poisoning if they handle unkeyed input in an unsafe way and allow the subsequent HTTP responses to be cached. This vulnerability can be used as a delivery method for a variety of different attacks.

Cache Keys: Subset of the request's components to determine whether there is a cached response. Unkeyed: Components of the request that are not included in the cache key.

Steps:

  • Identify a cache oracle

  • Adding cachebuster (make sure that they will only be served to you)

  • Identify and evaluate unkeyed inputs to generate harmful response (Param Miner, Guess headers)

  • Evaluate exactly how the website processes it, studying how the cache behaves.

  • Once you work out how to get a response cached that contains your malicious input, you are ready to deliver the exploit to potential victims.

Cachebuster

GET /?cachebuster=1 HTTP/1.1
Accept-Encoding: gzip, deflate, cachebuster
Accept: */*, text/cachebuster
Cookie: cachebuster=1
Origin: https://cachebuster.vulnerable-website.com
etc.

Identify Third-Party Cache

If you can identify that a specific third-party cache is being used, you can also consult the corresponding documentation. This may contain information about how the default cache key is constructed. You might even stumble across some handy tips and tricks, such as features that allow you to see the cache key directly.

Pragma: x-get-cache-key
Pragma: akamai-x-get-cache-key

Headers

Test requests with Param Miner, Guess headers

X-Forwarded-Host
X-Forwarded-Scheme
X-Original-Url
X-Host
X-Forwarded-Server
X-HTTP-Host-Override
Forwarded

We can test Host Header with:

  • 2 Host Header

  • Host: vulnerable-website.com:bad-stuff-here Host: notvulnerable-website.com Host: hacked-subdomain.vulnerable-website.com etc.

  •      Host: bad-stuff-here
    Host: vulnerable-website.com
  • Absolute URL in the request GET https://vuln-website/path HTTP/2

  • GET @private-intranet/example HTTP/1.1

  • Servers that only perform thorough validation on the first request they receive over the same connection.

In the responses you can have (possible)

Cache-Control: max-age=30
Age: 1
X-Cache: hit
Vary: User-Agent

The Vary header specifies a list of additional headers that should be treated as part of the cache key even if they are normally unkeyed.

Cache Key Flaws

  • Unkeyed port

  • Unkeyed query string

  • Unkeyed query parameters (All or only some, ex. utm_content)

  • Parameter Cloaking (? & ;)

  • Unkeyed HTTP method (pretty rare) or use "fat" GET (simply adding a body to a GET request). You can try also with X-HTTP-Method-Override: POST header if is unkeyed.

  • URL normalization (unexploitable XSS in path with unencoded> maybe have the same cached key to the URL-encoded %22)

Last updated