Web Cache Poisoning: Turning Low-Impact Flaws into High-Severity Attacks

Web Cache Poisoning: Turning Low-Impact Flaws into High-Severity Attacks

Introduction

Web cache poisoning is a sophisticated technique attackers use to force caching servers to store and serve a malicious response to unsuspecting users. This attack is most commonly chained with a self-Cross-Site Scripting (self-XSS) vulnerability, transforming a low-impact finding (which typically only affects the user who executes the payload) into a high-impact stored XSS that can be served to any user who visits the cached page.


Understanding Basic Caching Servers

To grasp the concept of web cache poisoning, it is essential to first understand how caching servers work.

In simple terms, caching servers operate by saving a user’s request and the corresponding server response, then serving that saved response to subsequent users when they call the same endpoint. This mechanism is used to prevent the same resource from being called repeatedly on the main web server, thus avoiding redundant work and improving performance.

The web server only gets contacted if the response is not found in the caching server. For example, if the endpoint test.com/cat.php is called 100 times:

  1. The server answers the first request and saves the response to the caching server.
  2. The other 99 requests will be answered directly by the caching server using the saved response from the first request.

As illustrated above, “User 1” makes a request to example.com/kop?somthing=ok. Since the response is not found in the caching server, the request is forwarded to the web server, which provides the response. Next, users 2 and 3 make the exact same request. This time, the response is found in the caching server, so the web server is not contacted, and the old, saved response is shown instead.

The Role of Cache Keys

How exactly does the caching server determine if two requests are identical? The answer lies in cache keys.

A cache key is an index entry that uniquely identifies an object in a cache. You can customize cache keys by specifying which parts of an incoming request—such as a query string or specific headers—should be used to differentiate objects in the cache.

Typically, only the following components of an HTTP request are used as default cache keys:

  • The Request Method (e.g., GET, POST)
  • The Path (e.g., /embed/v4.js)
  • The Host (e.g., play.vidyard.com)

Everything else would typically be discarded when determining if two requests are the same, unless explicitly stated otherwise.

Example: If we look at a sample request, the cache keys might be:

  • GET /embed/v4.js?_=1605995211298
  • Play.vidyard.com

It is important to look for the Vary header in the HTTP response. The Vary header explicitly informs the caching server that additional headers are also used as part of the cache key.

In the sample HTTP response shown, the Vary header specifies that X-ThumbnailAB, X-China, Accept-Language, and Accept-Encoding headers are also used as cache keys. These values are important to note. For example, if the User-Agent is also used as a cache key, a new cache entry would need to be created for every unique User-Agent header, reducing the efficiency of the cache.


The Web Cache Poisoning Attack

The fundamental goal of web cache poisoning is straightforward: if an attacker can somehow inject malicious content into an HTTP response that gets cached, the same malicious response will be served to all other users who request that same endpoint. While the name may sound complex, the process is actually relatively easy to find and exploit when the conditions are right.

The attack follows a three-step methodology:

  1. Find Unkeyed Input: We need to find input parameters (in the URL or headers) that do not cause the caching server to consider the request different. Since this input is not used by the caching server to determine uniqueness, it is called “unkeyed”.
  2. Determine Impact: The next step is to determine the impact the unkeyed input has on the server. Can it be used to exploit an open redirect vulnerability, a self-XSS vulnerability, or some other flaw?
  3. Check Cacheability and Exploit: Finally, you need to confirm if the page is cacheable using the unkeyed input. If it is, you should be able to exploit other users when they view the publicly cached page.

Step 1: Finding Unkeyed Input with Param Miner

The first crucial step, finding unkeyed input, can be accomplished in Burp Suite using the “Param Miner” plugin. Once this plugin is downloaded, you can easily initiate a scan by right-clicking on a request and choosing “Param Miner”.

Next, the attack configuration will be displayed. While you can change the settings, the default options are often sufficient. You can also use the “Guess headers” button if you are only interested in unkeyed values in the headers, or “Guess GET parameters” if you are interested in URL parameters.

After hitting “OK,” the attack will start. You can view your results under the Extender tab in Burp Suite.

In the example above, the X-forward-scheme header was found, and the results show that it is not used as a key by the caching server. Suppose this header is also vulnerable to a self-XSS flaw. Under normal conditions, an attacker could only exploit themselves. However, if the self-XSS payload is cached by the application, other users will be able to view the cached page if it is publicly accessible.

Step 2: Checking for Cache Status and Forcing a Cache Miss

When an HTTP response is received, security testers look for certain headers that indicate if the response came from the cache.

  • The X-Cache header is a strong indicator. If it is set to hit, the page was served from the cache. If it is set to miss, the page was not served from the cache.
  • The Age header is another indicator. This value contains the number of seconds the page has been cached for.

Obviously, for the attack to work, we need the malicious payload to be newly cached. Executing the payload on an endpoint that is already cached will not work, as the old response will be served.

However, as mentioned earlier, the path is normally used when determining if a page has been cached or not. Therefore, adding a random, unique GET parameter to the request should cause the response to be treated as a new, unique resource and force a cache miss.

As you can see, changing a non-critical GET parameter (e.g., changing test=1 to test=2) causes the response to be considered a new resource by the server. This conclusion is drawn from the fact that the X-Cache header is set to miss and the Age header is set to 0.

We now know that we can force the server to cache a new response by incrementing the test parameter.

Step 3: Poisoning the Cache

The final step is to combine the findings:

  1. Add the self-XSS payload to the vulnerable, unkeyed header (e.g., X-forward-scheme).
  2. Increment the unique GET parameter (e.g., changing test=2 to test=3) one more time to force a cache miss and create a new entry.
  3. Send the request.

Upon successful execution, the self-XSS payload will be cached by the server. Anyone who subsequently views that specific endpoint will cause the XSS payload to trigger, effectively turning a simple self-XSS vulnerability into a persistent (stored) XSS that affects all users.

Summary

Web cache poisoning is a powerful yet relatively accessible vulnerability. The process for exploitation is systematic:

  1. Find an unkeyed value using a tool like the Param Miner plugin.
  2. Determine if you can exploit the unkeyed value in some way (e.g., self-XSS, open redirect).
  3. Ensure you can make the server cache the malicious HTTP response (typically by adding a unique query parameter to force a cache miss).
  4. Test to see if your exploit worked by having another user access the cached resource.

Normally, security professionals often dismiss self-XSS vulnerabilities as low-impact, but with the technique of web cache poisoning, they can be elevated to high-impact stored XSS.

Total
1
Shares

Leave a Reply

Previous Post
API Documentation: A Hacker's Goldmine for Vulnerability Hunting

API Documentation: A Hacker’s Goldmine for Vulnerability Hunting

Next Post
Web Cache Deception: Tricking the Caching Server to Expose Private Data

Web Cache Deception: Tricking the Caching Server to Expose Private Data

Related Posts