In the fast-moving world of web applications, caching plays a pivotal role in ensuring quick and efficient content delivery. However, as with most technologies, it comes with its own set of vulnerabilities. One of the most insidious threats in this realm is cache poisoning. This subtle yet powerful attack can manipulate what users see, disrupt functionality, and lead to severe security and performance issues, including denial-of-service (DoS) attacks. So, what exactly is cache poisoning, and why should you care? Let’s delve into how specific headers can be exploited to poison the cache.
What is Cache Poisoning??
Simply put, cache poisoning refers to the act of tampering with the cache’s contents, affecting either the user experience or even denying users access to the site entirely. Caches typically store static content like .css
, .jpg
, or .js
files to improve performance. Since these files are uniform for all users, caching them enhances speed and user experience.
However, if an attacker can alter the response code of these cached resources and inject malicious content, they can break the user interface, making the site unusable for users—a classic example of cache poisoning. But the attack doesn’t stop at UI disruption; it can be extended to more severe exploits like cross-site scripting (XSS) and malicious redirections.
Cache Keys: The Gateway to Poisoning
A critical concept to understand is cache keys. These are the headers that determine whether a request should be treated as identical to or distinct from previous requests. For example, if a cache key is based on the User-Agent
header, requests from Chrome and Firefox will be considered different. This is important because for an attacker to poison a cache for all users, they need to exploit headers that aren’t part of the cache key, allowing them to manipulate cached responses for everyone.
When the cache key of a new request matches that of a previous one, the cache serves the cached response generated for the original request. This continues until the cached response expires, making the poisoned content available to all users with matching cache keys.
Headers that could poison the cache
Here are some headers that, when used in requests, can trigger a 400 Bad Request
or 412 Precondition Failed
response code. Once these are cached, subsequent requests will receive the poisoned response until the cache expires:
Range: bytes=aaa
X-Amz-Server-Side-Encryption: test
Content-Length test: 0
Range: bytes=a
if-match: k
X-/%s: aaa
Max-Forwards: afafafafafafafa
X_HTTP_Method_Override: OPTIONS
X-Up-Devcap-Post-Charset: test
ño: ño
X-Up-Devcap-Post-Charset: test
X: {Add \x04 character here}
Content-Type: close
content-type: -*é§
However, it’s not just about receiving a 400
or 412
response. Sometimes, the cache may be poisoned with a 200 OK
response but with altered content. For example, a poisoned cache might deliver a 200 OK
response with a changed Content-Length
header, which can degrade user experience significantly.
A few examples, where the header would give 200 ok response but empty or changed response body.
X-middleware-prefetch: anyvalue
X-Http-Method-Override: HEAD
In some cases, the cache may be poisoned to cause server errors like 500 Internal Server Error
or 502 Bad Gateway
. Here are a few headers that can lead to such scenarios:
Request-Uuid: 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
X-Amz-test=1
Cache Poisoning and Malicious Redirects
Cache poisoning can also be used to redirect users to malicious sites. When cache is poisoned using certain headers, users visiting a legitimate site may unknowingly be redirected elsewhere. Examples of such headers include:
X-Forwarded-Scheme: https
X-Forwarded-Host: testexample.com
X-Forwarded_host: evil.com
XSS via cache poisoning
One of the most dangerous consequences of cache poisoning is the potential for XSS attacks, which can lead to account takeovers or other malicious actions. If user input is cached and the domain is vulnerable to cache poisoning, attackers can insert malicious payloads into the cache. These payloads are then triggered for every user who accesses the poisoned content until the cache expires.
Here are a few examples of headers that could facilitate XSS attacks via cache poisoning:
X-Forwarded-Prefix: ><img src=x onerror=alert(1)>
Cookie: port_id=xss</script><svg/onload=alert(document.domain)>
Conclusion
Cache poisoning may seem like a single vulnerability, but its potential impact can be far-reaching, extending to more severe security issues such as XSS, redirection, and DoS attacks. A single poisoned cache can compromise the experience of multiple users and, in certain cases, open the door to much larger exploits. This is why cache security is a critical aspect of web application security that should never be overlooked.
For further reading on cache poisoning and its impact, check out PortSwigger’s comprehensive blog on the topic.
I hope you enjoyed reading this! See you in the next one! Until then, Happy hunting.