8. HTTP Cache Basics and Cache Poisoning
1. HTTP CACHING
Caching is a mechanism designed to decrease the server load and speed up the loading of web pages. A cache saves copies of server responses and serves them to users upon their repeating requests.
The cache can operate locally in the user’s browser, or there are also intermediate caches: caching proxies, load balancers, CDNs, web servers. Our lesson is devoted specifically to intermediate caches.
In case of a browser cache, when a user requests some data, the browser first checks if the requested data is cached and not expired, then the cache serves the user the cached version of data. In case of an intermediate cache, the same logic is applied: first, the cache checks if the requested data is saved and not expired, and then serves it to users. It also allows serving data when the server is down.
Usually static content like images, stylesheets, or scripts is cached.
2. CACHING HEADERS
Caching mechanisms use the following standard HTTP headers.
In the right pane, click the directive you want to explore, and the description will appear instantly.
Cache-Control
This general header defines the behavior of caching mechanisms through directives. Directives allow disabling of caching or fine-tuning of the caching behavior (e.g. specifying what kind of caching providers can cache the response, defining cache storage period, managing usage of the stale cache).
Pragma
This header with the no-cache directive is equal to the Cache-Control: no-cache header. It is used for the backward compatibility with HTTP/1.0 caching mechanisms. The header is not supported by some user agents, thus using Cache-Control header as a reliable caching mechanism is more preferable.
Age
This header specifies the number of seconds a response has been stored in an intermediate cache.
Expires
This header sets the date and time when the ached response becomes expired.
ETag and Precondition headers (If-*)
These headers are used to validate the freshness of cached data. ETag header value stores a version of the resource and If-* headers define additional conditions of ETag verification.
3. CACHE KEYS
When a cache receives a request for some resource, it needs to check if it has already saved a copy of this resource and can return it to the user immediately, or it needs to forward the request to the application server.
Identifying whether the user requests the same resource that is already stored in the cache can be tricky. Caches solve this problem by using the concept of cache keys. Some component of the HTTP request can be set as keys (in cache settings).
When a request comes to the cache server, it checks first which headers of that request are keyed. Then it takes all those keyed headers with their values together and calculates the hash. After that this hash is used to search through the cached responses (responses are stored together with hashes of keyed headers of respective requests).
In the right pane, you can see the animated diagram of the cache using keyed headers to calculate the hash for the incoming request and retrieve the correct cached response to the user. Note that it is a simplified description, and it might be not valid for all existing caching software.
4. ATTACK INTRODUCED
The general idea of the Cache Poisoning attack is to make the cache save the resource that contains some malicious data and then serve it to users that request this resource. This attack allows performing a further XSS attack, defacing a page, redirecting a user to an arbitrary domain and bypassing access control mechanisms.
In this lesson, we will talk about basic Cache Poisoning using the unkeyed HTTP request components. During this attack, the hacker will send some malicious content in the unkeyed request header, hoping that it will be used in the response, cached and then served to other users of the application requesting the same resource.
5. VULNERABLE APPLICATION
The vulnerable application pane loads the online shopping application LotsOfGoods.me. It uses X-Script-Source custom header to pass a domain name to the server, where this name will be used to generate the URL to run the counter script on the page. This header is unkeyed, so the cache doesn’t use it for identification purposes.
6. VULNERABILITY DETECTED
Bob is a hacker looking for possibilities for an attack on a yet-another shopping application. He is using his Burp Suite Param Miner plug-in against the LotsOfGoods.me application to find out which components (headers, cookies) of the HTTP request are unkeyed. In the scanning results, he sees that there is an unkeyed parameter in the request: X-Script-Source header.
The name of this header implies that it contains some information that allows detecting the path to the folder that contains scripts, and this path is probably used somewhere in the code of the page.
7. VULNERABILITY TESTED
Bob analyzes the code of the web page and finds out that the domain name passed in the X-Script-Source header is used to create an URL of the counter script that is used on the page. Now Bob needs to test how far he can go with the exploitation of that unkeyed request component.
On his malicious server, he creates the folder structure that is the same as in the legitimate script link and puts there his malicious script that steals user cookies.
The only thing he needs to do next is to put the name of his malicious server into the X-Script-Source header of the intercepted request.
Copy and paste the following domain name into the X-Script-Source header of the intercepted HTTP request:https://bobsevilserver.me
7. VULNERABILITY TESTED
Bob analyzes the code of the web page and finds out that the domain name passed in the X-Script-Source header is used to create an URL of the counter script that is used on the page. Now Bob needs to test how far he can go with the exploitation of that unkeyed request component.
On his malicious server, he creates the folder structure that is the same as in the legitimate script link and puts there his malicious script that steals user cookies.
The only thing he needs to do next is to put the name of his malicious server into the X-Script-Source header of the intercepted request.
We can see that Bob’s cookie appeared in his server log. This means that Bob had successfully triggered an XSS. But he cannot attack users with this kind of XSS because he is not able to make users change the header value while requesting lotsofgood.com. But he can achieve his goal by performing cache poisoning.
8. VULNERABILITY EXPLOITED
To poison cache with his malicious request, Bob needs to make sure that he sends it to the application right after the current cached response expires. To define the correct time, he uses the values of the Age header and max-age directive of the Cache-Control header of the server response.
9. MALICIOUS RESULT
Now each user that will request the LotsOfGoods.me homepage in the next 2400 seconds will receive Bob’s malicious response from the cache server. The script will be executed in their browsers, and their cookies will be stolen.
To check whether Bob’s attack was successful, copy and paste the following command into the console:cat /var/log/apache2/access.log
As you can see, the users that come to the LotsOfGoods.me webpage keep receiving the poisoned page from the cache, and Bob gets access to their cookies
10. REMEDIATION
Manipulating unkeyed HTTP request component, an attacker can do a lot of harm if these components influence the page content. To prevent cache poisoning, you should do the following:
1. Cache only static data.
2. If you are using some third-party service for caching, check which security controls against cache poisoning it provides.
3. Do not trust any data from header directives of the HTTP requests. Always consider it tainted by default.
4. When you cache a page, make sure that all the headers of the HTTP request that influence the page content – are keyed. And vice versa, if some header is unkeyed, don’t use it in any business logic that implies influencing the page content.
5. Check if your caching mechanism or framework is configurable to prevent cache poisoning.
In the right pane, you can see that in case the header containing the data that influences the page content is keyed, even if the malicious response was cached, it will never be served to users that make legitimate requests.