Web cache poisoning attacks exploit the trust web servers place in user-supplied input to inject malicious content into the cache, which is then served to unsuspecting users.
Let’s see this in action with Burp Suite, the de facto standard for web security testing. We’ll simulate an attack against a hypothetical e-commerce site, example.com, which uses a CDN with a caching layer.
Imagine example.com has a feature where product descriptions can be dynamically loaded based on a URL parameter, like example.com/products?id=123. The server might also use this id parameter to generate absolute URLs within the page, perhaps for canonical links or social sharing.
Here’s a simplified example.com response for GET /products?id=123:
<!DOCTYPE html>
<html>
<head>
<title>Product 123</title>
<link rel="canonical" href="http://example.com/products?id=123">
<!-- Other meta tags -->
</head>
<body>
<h1>Awesome Product</h1>
<p>This is the description for product 123.</p>
<!-- Other content -->
</body>
</html>
The core idea of cache poisoning here is to make the server generate a response that includes a malicious URL, but only when a specific, attacker-controlled input is present. The CDN, seeing this response and assuming it’s a legitimate, cacheable asset, will store it. Subsequent requests for the same URL (even from legitimate users) will then be served the poisoned version from the cache.
The Attack Flow:
-
Identify a Cacheable Endpoint: Find a URL that the CDN is configured to cache. Often, these are static assets like
/css/style.cssor/js/app.js, but dynamically generated content can also be cached if the caching rules are misconfigured. For our example, let’s assume/products?id=123is cached. -
Find Input That Influences Outbound URLs: Look for parameters that the server uses to construct absolute URLs within the HTML response. In our example, the
idparameter influences thehrefof the canonical link. Other common places includeog:url,<script src="...">,<link href="...">, or evenContent-Locationheaders. -
Craft the Malicious Payload: The goal is to make the server generate a URL that, when fetched by the victim’s browser, executes arbitrary code or redirects them. A common technique is to inject a URL that points to an attacker-controlled server, but uses a protocol that browsers interpret as executable. For instance,
javascript:alert('XSS')is a classic, but more sophisticated attacks might usedata:URIs or other schemes.Let’s say we want to inject a malicious
javascript:URL into the canonical link. We need to craft anidparameter that the server will use to buildhttp://example.com/products?id=...where the...part is ourjavascript:payload.The problem is, the server might sanitize input. If we try
id=javascript:alert('XSS'), the server might just outputhttp://example.com/products?id=javascript:alert('XSS'), which isn’t directly executable by the browser as a canonical link.The trick is to find input that causes the server to misinterpret the parameter. What if the server is vulnerable to Host Header injection or similar tricks, and it uses the
Hostheader to construct URLs?Let’s assume the server actually constructs the canonical URL like this:
href="http://<Host Header Value>/products?id=<id Parameter Value>".Now, we can craft a request:
- Host Header:
evil.com:8080(or any domain we control) - URL Parameter:
id=products?id=123(this is a bit of a trick, we’re trying to make the final URL look likehttp://evil.com:8080/products?id=products?id=123)
The server, when processing
GET /products?id=products?id=123withHost: evil.com:8080, might generate:<link rel="canonical" href="http://evil.com:8080/products?id=products?id=123">This isn’t quite right. The attacker wants to inject a
javascript:URI scheme.A more direct approach: What if the server blindly trusts a parameter and uses it directly in a
Locationheader or a meta-refresh tag, and the CDN caches these redirects?Let’s consider a different scenario:
example.com/login. If the server redirects to a?next=parameter, and this redirect is cached:GET /login?next=http://evil.com/malicious_pageAnd the server responds with:
HTTP/1.1 302 Found Location: http://evil.com/malicious_page Cache-Control: public, max-age=3600 Vary: Cookie, User-AgentIf the CDN caches this 302 response for
/login?next=..., then any user requesting/login(without thenextparameter) would be redirected toevil.com. This is a classic cache poisoning.Using Burp Suite:
-
Proxy Traffic: Configure your browser to use Burp Suite as a proxy. Navigate to
example.com. -
Identify Target URL: Find a URL that seems cacheable (e.g.,
/products?id=123). -
Send to Repeater: Right-click the request in Burp’s Proxy History and select "Send to Repeater."
-
Identify Influencing Parameter: In Repeater, modify the
idparameter. Observe how the response changes. Look for parameters that affect absolute URLs or redirects. -
Craft the Poisoned Request:
-
Let’s assume the
Hostheader is the vector. We want to injectjavascript:alert(1)into a URL. -
Modify the
Hostheader in Burp’s Repeater toattacker-controlled.com. -
Modify the
idparameter to something likeproducts?id=123&js=javascript:alert('XSS'). The goal is to get the server to generate something like<link rel="canonical" href="http://attacker-controlled.com/products?id=123&js=javascript:alert('XSS')">. This won’t work directly. -
The Real Trick: The server often uses a different parameter or a combination to build URLs. Let’s say the server uses the
X-Forwarded-Hostheader to construct URLs and also caches responses based on theHostheader. -
Poisoned Request Example:
- URL:
/index.html(a URL that is cached by the CDN) - Headers:
GET /index.html HTTP/1.1 Host: example.com X-Forwarded-Host: evil.com:8080 // ... other headers - The server, upon receiving this, might generate HTML containing links like:
<link rel="canonical" href="http://evil.com:8080/index.html"> - If the CDN caches the response for
/index.htmland incorrectly includes theX-Forwarded-Hostin its cache key or simply caches the HTML response containing the forged URL, subsequent requests for/index.htmlwill serve this poisoned HTML.
- URL:
-
-
Identify Cache Key: Crucially, you need to understand what constitutes the cache key for the CDN. If the CDN only uses the URL path (
/index.html) as the key, but the server generates different content based on headers likeX-Forwarded-Host, then you have a cache poisoning vulnerability. Burp Suite’s "Cacheability" tab can help analyze this. -
Trigger the Poison: Send the crafted request. Then, immediately make a normal request for the same URL (
/index.html) through Burp. Check the response. If it contains the malicious URL (e.g.,http://evil.com:8080/index.html), you’ve poisoned the cache. -
Verify: Try accessing the poisoned URL directly in your browser (not through Burp). If the malicious URL is rendered or executed, the attack is successful. For
javascript:alert('XSS'), you’ll see an alert box. For a redirect, your browser will navigate away.
- Host Header:
The next hurdle you’ll face is understanding how different CDNs implement their cache invalidation and how to bypass specific WAF rules designed to detect these kinds of header manipulations.