Web cache poisoning involves two steps. First, the attacker must figure out how to get a response from the back-end server that includes a harmful payload. Then, the attacker must ensure that this response is saved in the cache and served to its intended targets.
In order to store the response on the server's cache, the attacker has to determine which components of the request are "cache keys " and which of them are "unkeyed". If a request includes a cache key that matches the cache key of a previous request, the cache will treat them as equivalent and will serve a copy of the previously generated response from the cache. This will happen for all subsequent requests with the same cache key until the cached response expires.
Note: Sending the header Pragma: akamai-x-get-cache-key can be used to display the cache key in the response headers.
Identify unkeyed inputs
The first step in launching a web cache poisoning attack is identifying unkeyed inputs, such as headers, that are ignored by the cache server when deciding whether to serve a cached response to the user. Hence, you can use the unkeyed inputs to inject your payload to elicit a "poisoned" response from the server. If this response is cached, it will be served to all users whose requests have the matching cache key.
The best way to identify unkeyed inputs is using the Burp Suite extension Param Miner. Right-click on a request you want to analyze and click on Extensions/Param Miner/Guess params/ and the thing you want to guess. The results will appear as Issues on the Target/Site Map section.
Moreover, you can also select the options "Add static/dynamic cache buster" and "Include cache busters in headers", which will then automatically add a cache buster to commonly keyed headers in any requests that you send using Burp's manual testing tools.
Another alternative is to detect how the cache and the back-end normalize the path of every request. Because the path of a request is often used as a cache key, you can try to exploit this by sending requests that hit the same endpoint. As an example, the following entries might all be cached separately but treated as equivalent to GET / on the back-end:
Apache: GET //
Nginx: GET /%2F
PHP: GET /index.php/xyz
.NET: GET /(A(xyz)/
Exploit the vulnerability
After identifying the unkeyed input, the next step is to analyze how the application processes, if it is being properly sanitized or if it is used to generate other data dynamically in order to create a harmful response.
After manipulating the user inputs to create a harmful response, it is time to store the response in the cache. To do so, you will need to find out which components of a request, like a file extension, content type, route and response header, are required in order to cache the request.