Web Cache Poisoning

General

Web cache poisoning is an advanced technique whereby an attacker exploits the behavior of a web server and cache so that a harmful HTTP response is served to other users.

Fundamentally, web cache poisoning involves two phases. First, the attacker must work out how to elicit a response from the back-end server that inadvertently contains some kind of dangerous payload. Once successful, they need to make sure that their response is cached and subsequently served to the intended victims.

A poisoned web cache can potentially be a devastating means of distributing numerous different attacks, exploiting vulnerabilities such as XSS, JavaScript injection, open redirection, and so on.

Tools

  • Param Miner - PortSwigger

    This extension identifies hidden, unlinked parameters. It's particularly useful for finding web cache poisoning vulnerabilities.

Discovery: Check HTTP headers

Usually, when a response was stored in the cache there will be a header indicating so, you can check which headers you should pay attention to in this post: HTTP Cache headers.

Discovery: Caching 400 code

If you are thinking that the response is being stored in a cache, you could try to send requests with a bad header, which should be responded to with a status code 400. Then try to access the request normally and if the response is a 400 status code, you know it's vulnerable (and you could even perform a DoS). A badly configured header could be just \: as a header. Note that sometimes these kinds of status codes aren't cached so this test will be useless.

Discovery: Identify and evaluate unkeyed inputs

You could use Param Miner to brute-force parameters and headers that may be changing the response of the page. For example, a page may be using the header X-Forwarded-For to indicate the client to load the script from there:

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

Elicit a harmful response from the back-end server

With the parameter/header identified check how it is being sanitised and where is it getting reflected or affecting the response from the header. Can you abuse it anyway (perform an XSS or load a JS code controlled by you? perform a DoS?...)

Get the response cached

Once you have identified the page that can be abused, which parameter/header to use and how to abuse it, you need to get the page cached. Depending on the resource you are trying to get in the cache this could take some time, you might need to be trying for several seconds. The header X-Cache in the response could be very useful as it may have the value miss when the request wasn't cached and the value hit when it is cached. The header Cache-Control is also interesting to know if a resource is being cached and when will be the next time the resource will be cached again: Cache-Control: public, max-age=1800 Another interesting header is Vary. This header is often used to indicate additional headers that are treated as part of the cache key even if they are normally unkeyed. Therefore, if the user knows the User-Agent of the victim he is targeting, he can poison the cache for the users using that specific User-Agent. One more header related to the cache is Age. It defines the times in seconds the object has been in the proxy cache.

When caching a request, be careful with the headers you use because some of them could be used unexpectedly as keyed and the victim will need to use that same header. Always test a Cache Poisoning with different browsers to check if it's working.

Exploiting Examples

  1. Find an un-keyed input for a Cache Poisoning

    Values: User-Agent
    Values: Cookie
    Header: X-Forwarded-Host
    Header: X-Host
    Header: X-Forwarded-Server
    Header: X-Forwarded-Scheme (header; also in combination with X-Forwarded-Host)
    Header: X-Original-URL (Symfony)
    Header: X-Rewrite-URL (Symfony)
  2. Cache poisoning attack - Example for X-Forwarded-Host un-keyed input (remember to use a buster to only cache this webpage instead of the main page of the website)

    GET /test?buster=123 HTTP/1.1
    Host: target.com
    X-Forwarded-Host: test"><script>alert(1)</script>
    
    HTTP/1.1 200 OK
    Cache-Control: public, no-cache
    [..]
    <meta property="og:image" content="https://test"><script>alert(1)</script>">

Web Cache Deception

Exploit

  1. Browser requests http://www.example.com/home.php/non-existent.css.

  2. Server returns the content of http://www.example.com/home.php, most probably with HTTP caching headers that instruct to not cache this page.

  3. The response goes through the proxy.

  4. The proxy identifies that the file has a css extension.

  5. Under the cache directory, the proxy creates a directory named home.php, and caches the imposter "CSS" file (non-existent.css) inside.

Methodology of the attack - example

  1. Normal browsing, visit home : https://www.example.com/myaccount/home/

  2. Open the malicious link : https://www.example.com/myaccount/home/malicious.css

  3. The page is displayed as /home and the cache is saving the page

  4. Open a private tab with the previous URL : https://www.paypal.com/myaccount/home/malicous.css

  5. The content of the cache is displayed

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

Tools

# https://github.com/Hackmanit/Web-Cache-Vulnerability-Scanner
wcvs -u https://url.com
# https://github.com/s0md3v/Arjun
python3 arjun.py -u https://url.com --get 
python3 arjun.py -u https://url.com --post
# https://github.com/maK-/parameth
python parameth.py -u https://example.com/test.php
# https://github.com/devanshbatham/ParamSpider
python3 paramspider.py --domain example.com
# https://github.com/s0md3v/Parth
python3 parth.py -t example.com

Last updated