By Thiago Escobar

The Edge Side Includes markup language allows a page to be created from fragments. These fragments are interpreted on the cache server and perform actions in the process of creating the HTML page. The vulnerability occurs when it’s possible to inject these fragments arbitrarily.

The above description may seem confusing due to the introduction of different concepts. So let’s break it down. The Edge Side Includes technology aims to optimize the process of creating HTML documents through the use of caching servers. It’s important to understand the role of these servers for a better understanding of the context.

Cache servers

A cache server acts as an intermediary in the communication between the client and the server. When a request is made for certain content, the response is temporarily stored on the cache server. This means that if there’s a new request for the same content within that period, it won’t be necessary to make a new request to the application server, as the cache server already has the answer. This allows the content to be delivered faster to the end user. In addition, this approach reduces the load on the server, since the demand for resources is reduced, providing a more efficient and agile experience.

Edge Side Includes

Edge Side Includes (ESI) is an XML-based markup language that allows web pages to be dynamically composed using various fragments. Each fragment can be individually stored on the cache server, thus contributing to the efficiency of the page creation process. These fragments can then be requested separately from the application server.

The use of cache servers plays a crucial role in this context, reducing the response time to the client. By making use of ESI elements, the cache server can store and serve specific fragments, avoiding the need to reload the entire page with each request. This not only improves page loading speed for the end user, but also reduces the load on the application server’s resources.

In summary, Edge Side Includes is a tool for optimizing the delivery of web content, allowing a flexible approach to building pages by managing fragments and taking advantage of the benefits of caching servers. An example of a page built using fragments in Node.js is shown below.

The contents of the esi.html file can be seen next:

You can see that the “esi.html” page, sent as a response to the request from the “/esidemo” page, incorporates ESI fragments. These fragments are requested and inserted individually into the main page. Subsequently, the page, now made up of all the fragments, is sent to the user, as illustrated in the image. The creation flow of this page can be analyzed in more detail below:

Source: https://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Edge%20Side%20Include%20Injection%20Abusing%20-%20Dion%20Marcil.pdf

In the previous example, the “include” action was used, which makes a request and inserts the response into the main page. However, it’s important to note that there are other possible actions, as illustrated below:

Edge Side Includes Actions

The syntax of Edge Side Includes technology is as follows:

“<esi:[action] attributes=“value” />”

Among the possible actions, the most interesting for attacking cache servers are:

Include: This was the ESI action used in the previous examples, the “Include” element in ESI is responsible for forming pages through fragments. The cache server, through the ESI processor, makes requests to search for attributes and inserts them into the main page, before sending it to the end user. This allows the content to be dynamically assembled.

Vars: The vars element is the ESI element that allows variables to be added. These variables are interpreted by the cache server. The possibilities for variables are described below according to the official documentation.

Source: https://www.w3.org/TR/esi-lang/

– inline: In the oracle web cache documentation we have the following definition: “Marks a fragment as a separately cacheable fragment, embedded in the HTTP response of another object”. In practice, this element allows an entry to be overwritten by arbitrary data (illustrated in more detail in attacks using ESI Injection).

Note: The text above describes the most crucial actions for understanding the Edge Side Include Injection vulnerability, based on the official documentation. It’s important to highlight that each cache server has a specific set of tags that can be interpreted. In addition, some servers may implement their own ESI tags, broadening the possibilities.

Edge Side Include Injection

The Edge Side Include Injection vulnerability occurs when an attacker manages to insert arbitrary ESI tags to be interpreted on the cache server. The attack possibilities vary depending on the target cache server and its specific configuration.

Some cache servers, such as Varnish Cache, can have significant limitations. In the case of Varnish, it only accepts three ESI actions. On the other hand, servers like Oracle Web Cache have the ability to interpret all the official documentation and even add their own ESI actions.

During the ESI study, most of the labs were conducted using the Apache Traffic Server. This server accepts all the elements described in the official technology documentation, with the exception of a few specific topics:

The “include” action does not support the “alt” and “onerror” attributes

The “inline” action is not supported, which means that the overwriting of files mentioned above doesn’t exist

HTTP_COOKIE” is not supported as an ESI variable

“HTTP_USER_AGENT” is not supported as an ESI variable, although it’s possible to return the User-Agent as shown later.

Although “HTTP_HEADER” allows you to access request headers as variables, it’s not possible to retrieve the “Cookie” variable due to lack of support.

Practical example

Here we have a posts application, where a post made on the main page is reflected on the posts page, as illustrated below:

Now that we know that the application reflects the values entered, let’s perform the test using a payload that is based on the HTML injection of the “<img>” tag. In this case, the payload initially interprets the ESI element and then makes a request to the attacker’s control server, containing the victim’s User-Agent (value corresponding to the ESI variable interpreted earlier), as shown below:

Note: this payload requires that the application is also vulnerable to XSS to demonstrate the idea that JavaScript helps with ESI Injection attacks (but it’s not necessary, as will be shown in later examples)

Practical example in APIs

In the previous example of the web scenario, it became clear that in order to perform ESI tag injection it’s necessary to insert the characters ‘<‘ and ‘>’, since the syntax of this technology follows this pattern. However, it’s important to note that some firewalls and security implementations may block this type of character, as they are interpreted as potential XSS (Cross-Site Scripting) or HTML injection attacks. In scenarios involving APIs, it’s less common to find checks of this type, since the content won’t be interpreted directly in the browser, but rather displayed to the user. However, even in the above scenario, it’s still possible to observe the occurrence of ESI injection. In the image below we can see the normal operation of an API that returns the capitals and their state from a country entered in the ‘place’ field:

If an invalid place is entered, you can see that the value of the “place” parameter is reflected in the response and the following message is returned by the API:

By injecting the ESI tag into the reflected parameter, it was possible to return the requested header in the ESI variable, as illustrated below:

Attacks

The previous examples have mainly dealt with simple ESI tag injections where the attacker takes non-sensitive information. However, it is important to point out the wide range of possibilities that this vulnerability can offer. Edge Side Include Injection can open the door to more critical attacks, such as session hijacking, Denial of Service, Server-Side Request Forgery, among others. It’s worth noting that the extent of these attacks will depend heavily on the specific configuration of the cache server.

Session Hijacking

In this article we’ll explore two possibilities for session hijacking, using the vars element to grab the “Cookie” and “Authorization” headers and using inline file overwriting.

1 – Information in the headers

The information present in the headers can vary in each application tested. In cases where sensitive information is found in the headers, we can use the ESI variable to return this data. In the example below, it was possible to retrieve the Authorization header, associated with a session token. Similar to the example used in the API, we can see that the ‘event’ parameter is being reflected in the response. This means that it’s possible to perform ESI injection and return the desired header as shown below:

To retrieve the “Cookie” header, the process follows a similar approach to the previous example. However, in the specific case of the Apache Traffic Server used in the examples, this type of attack is not feasible, as described in the documentation.

It’s interesting to note that, in the context of Cookies, even with the “HttpOnly” flag enabled, it’s still possible to obtain session cookies. This is because they aren’t being retrieved by executing JavaScript, but by the ESI interpreter replacing “esi:vars” with the requested value.

2 – Inline

As highlighted at the beginning of this article, the ability to overwrite files is enabled by the ‘inline’ action. Let’s consider a scenario in which an application requests the file ‘tempest.js’ at various points. By using “inline”, it becomes possible to overwrite this file, turning all the points at which it’s requested into potential attack points. An illustrative payload is shown below:

The attack in question consists of overwriting the requested Javascript file, in this case ‘tempest.js’, with the content seen in the image above. This code snippet behaves similarly to the one described in the Apache Traffic Server example, where the ESI variable is replaced by the requested header, and finally a request is made to ‘evil.com’.

Note: This example, like the Apache Traffic Server example, uses resources that are only possible in the web scenario, taking advantage of JavaScript execution.

Server-side Request Forgery (SSRF)

Let’s explore two ways of carrying out an SSRF attack. The first involves using the include with an external fragment, and we’ll also discuss CVE-2019-2438. However, the first scenario is not very common, since in the vast majority of cases, requests are only directed to hosts on an allowlist.

1 – Include with an external fragment

This first scenario is the most intuitive, as it captures the general idea of ESI Include by simply adding the external origin for that fragment. In this way, the injection flow follows the line described below:

As mentioned earlier, the cache server interpreting the ESI include element inserted in this snippet will make the request to evil.com. For a better understanding of the vulnerability, I recommend reading https://www.sidechannel.blog/server-side-request-forgery-ataque-e-defesa/

CVE-2019-2438 (Limited SSRF)

In the second case, we deal with one of the specific implementations highlighted at the beginning of the article, where the Oracle Web Cache server, in version 11.1.1.9.0, makes it possible to include headers in the request made by the “include” element through the “request_header” element, an example payload is illustrated below:

When the custom header is added, it’s embedded in the first line after the request line. In this way, it’s possible to add a new “host” header, the behavior in this scenario is described in the following article: “https://www.icir.org/vern/papers/host-of-troubles.ccs16.pdf”, as noted in the aforementioned article in some scenarios the request will be successful and the first host will be considered.

Denial of Service (CVE-2018-1000024 and CVE-2018-1000027)

Both CVEs affect the Squid cache server in versions before 4.0.23, and both are related to pointer errors. In programming, a pointer is a variable that stores the memory address of another variable. It provides a means of accessing and manipulating data directly in memory.

CVE-2018-1000024 – Incorrect Pointer Handling vulnerability (CVSS 7.4)

The Incorrect Pointer Handling vulnerability in ESI Response Processing can result in Denial of Service for all clients using the proxy. The attack can occur when a remote server delivers an HTTP response with a valid but unusual ESI syntax.

CVE-2018-1000027 – NULL Pointer Dereference vulnerability (CVSS 6.8)

The Null Pointer Dereference vulnerability, like the vulnerability described above, can cause denial of service for all clients using the proxy, in this case the problem occurs in the processing of the X-Forwarded-For HTTP Response header. This attack appears to be exploitable via a remote HTTP server that responds with an X-Forwarded-For header to certain types of HTTP requests

Detection

To detect the vulnerability, you should look for information that indicates the use of this technology, such as cache server headers that accept the use of ESI or more actively by injecting ESI tags, in which case we recommend testing using the “<!- esi->” element, since it is interpreted by the vast majority of cache servers (if not all).

In the example below, you can see that, in a similar way to the scenario previously illustrated, this API reflects the inserted value when it isn’t found. Therefore, it’s possible to verify the possibility of ESI injection through the aforementioned element. The following images illustrate this.

As can be seen in the second image, the ESI element was interpreted on the cache server, resulting in the output ‘foobar’ for the user. 

In the context of an API, this test is quite simple. However, in the web scenario, the ESI element resembles an HTML comment. For the demonstration, we will use the same lab as before in the web scenario, in order to illustrate a detection scenario in this context. Below you can see an attacker’s arbitrary submissions with an ESI element first and then an HTML comment.

Below you can see the inspected HTML code sent to the user

As you can see, the HTML comment is still present in the HTML source code of the page, while the ESI element has been interpreted and subsequently sent to the end user. In other words, for the end user, there is no indication of the presence of this element on the page.

In this way it’s possible to confirm that the ESI tag is being interpreted on the cache server, it’s also possible to test for specific tags, but there’s a possibility that the cache server studied doesn’t accept the desired action and results in a false negative.

Correction/Mitigation

The ESI injection vulnerability arises mainly from inadequate configurations on cache servers. As such, it’s crucial to configure them correctly. In addition, Edge Side Include Injection is an XML-based markup language, which makes it possible to detect it from the OWASP ModSecurity Core Rule Set, which is a set of generic attack detection rules.

ESI Injection is correlated with other vulnerabilities, such as Cross-Site Scripting (XSS) and Server-Side Request Forgery (SSRF). It’s important to deal with these vulnerabilities to reduce the potential impact of ESI Injection and to follow good security practices, such as regularly updating the technologies used.

Real case

On the HackerOne platform, a real case highlights the risks of ESI Injection (Edge Side Includes). The incident involved an account takeover attack that exploited an ESI injection vulnerability, allowing session cookies to be extracted via the following payload ‘<esi:vars>$(HTTP_HEADER{Cookie})</esi:vars>’. In addition, a Reflected XSS vulnerability contributed to the theft of cookies. The combination of these flaws allowed attackers to perform “account takeover” and compromise the platform’s security, as mentioned throughout this article, Javascript helps in attacks involving ESI. Full details of the incident and corrective actions can be found in the HackerOne report, via the following link: https://hackerone.com/reports/1073780.

References

2018 Beyond XSS: Edge Side Include Injection. Available at: <https://gosecure.ai/blog/2018/04/03/beyond-xss-edge-side-include-injection/>

2019 ESI Injection Part 2: Abusing specific implementations. Available at:<https://gosecure.ai/blog/2019/05/02/esi-injection-part-2-abusing-specific-implementations/>

Apache Traffic Server ESI Plugin. Available at: <https://docs.trafficserver.apache.org/admin-guide/plugins/esi.en.html>

ESI Language Specification 1.0. Available at: <https://www.w3.org/TR/esi-lang/>

ESI Injection paper published during Black Hat USA 2018. Available at: <https://i.blackhat.com/us-18/Wed-August-8/us-18-Dion_Marcil-Edge-Side-Include-Injection-Abusing-Caching-Servers-into-SSRF-and-Transparent-Session-Hijacking-wp.pdf>