XXE - XEE - XML External Entity
Last updated
Last updated
Learn & practice AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE) Learn & practice GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
XML es un lenguaje de marcado diseñado para el almacenamiento y transporte de datos, con una estructura flexible que permite el uso de etiquetas nombradas descriptivamente. Se diferencia de HTML al no estar limitado a un conjunto de etiquetas predefinidas. La importancia de XML ha disminuido con el auge de JSON, a pesar de su papel inicial en la tecnología AJAX.
Representación de Datos a través de Entidades: Las entidades en XML permiten la representación de datos, incluidos caracteres especiales como <
y >
, que corresponden a <
y >
para evitar conflictos con el sistema de etiquetas de XML.
Definición de Elementos XML: XML permite la definición de tipos de elementos, delineando cómo deben estructurarse los elementos y qué contenido pueden contener, que va desde cualquier tipo de contenido hasta elementos hijos específicos.
Definición de Tipo de Documento (DTD): Los DTD son cruciales en XML para definir la estructura del documento y los tipos de datos que puede contener. Pueden ser internos, externos o una combinación, guiando cómo se formatean y validan los documentos.
Entidades Personalizadas y Externas: XML admite la creación de entidades personalizadas dentro de un DTD para una representación de datos flexible. Las entidades externas, definidas con una URL, plantean preocupaciones de seguridad, particularmente en el contexto de ataques de Entidad Externa XML (XXE), que explotan la forma en que los analizadores XML manejan fuentes de datos externas: <!DOCTYPE foo [ <!ENTITY myentity "value" > ]>
Detección de XXE con Entidades de Parámetro: Para detectar vulnerabilidades XXE, especialmente cuando los métodos convencionales fallan debido a medidas de seguridad del analizador, se pueden utilizar entidades de parámetro XML. Estas entidades permiten técnicas de detección fuera de banda, como activar búsquedas DNS o solicitudes HTTP a un dominio controlado, para confirmar la vulnerabilidad.
<!DOCTYPE foo [ <!ENTITY ext SYSTEM "file:///etc/passwd" > ]>
<!DOCTYPE foo [ <!ENTITY ext SYSTEM "http://attacker.com" > ]>
En este ataque voy a probar si una simple declaración de NUEVA ENTIDAD está funcionando.
Intentemos leer /etc/passwd
de diferentes maneras. Para Windows, podrías intentar leer: C:\windows\system32\drivers\etc\hosts
En este primer caso, ten en cuenta que SYSTEM "**file:///**etc/passwd" también funcionará.
Este segundo caso debería ser útil para extraer un archivo si el servidor web está utilizando PHP (No es el caso de los laboratorios de Portswigger)
En este tercer caso, observa que estamos declarando el Element stockCheck
como ANY.
En aplicaciones basadas en Java, podría ser posible listar el contenido de un directorio a través de XXE con una carga útil como (solo pidiendo el directorio en lugar del archivo):
Un XXE podría ser utilizado para abusar de un SSRF dentro de una nube.
Usando la técnica comentada anteriormente puedes hacer que el servidor acceda a un servidor que controlas para mostrar que es vulnerable. Pero, si eso no funciona, tal vez sea porque las entidades XML no están permitidas, en ese caso podrías intentar usar entidades de parámetros XML:
En esta ocasión vamos a hacer que el servidor cargue un nuevo DTD con una carga útil maliciosa que enviará el contenido de un archivo a través de una solicitud HTTP (para archivos de varias líneas, podrías intentar exfiltrarlo a través de _ftp://_ usando este servidor básico, por ejemplo xxe-ftp-server.rb). Esta explicación se basa en el laboratorio de Portswigger aquí.
En el DTD malicioso dado, se llevan a cabo una serie de pasos para exfiltrar datos:
La estructura es la siguiente:
Los pasos ejecutados por este DTD incluyen:
Definición de Entidades de Parámetro:
Se crea una entidad de parámetro XML, %file
, que lee el contenido del archivo /etc/hostname
.
Se define otra entidad de parámetro XML, %eval
. Esta declara dinámicamente una nueva entidad de parámetro XML, %exfiltrate
. La entidad %exfiltrate
está configurada para realizar una solicitud HTTP al servidor del atacante, pasando el contenido de la entidad %file
dentro de la cadena de consulta de la URL.
Ejecución de Entidades:
Se utiliza la entidad %eval
, lo que lleva a la ejecución de la declaración dinámica de la entidad %exfiltrate
.
Luego se usa la entidad %exfiltrate
, lo que desencadena una solicitud HTTP a la URL especificada con el contenido del archivo.
El atacante aloja este DTD malicioso en un servidor bajo su control, típicamente en una URL como http://web-attacker.com/malicious.dtd
.
Carga Útil XXE: Para explotar una aplicación vulnerable, el atacante envía una carga útil XXE:
Este payload define una entidad de parámetro XML %xxe
e incorpora esta entidad dentro del DTD. Cuando es procesado por un analizador XML, este payload obtiene el DTD externo del servidor del atacante. El analizador luego interpreta el DTD en línea, ejecutando los pasos descritos en el DTD malicioso y llevando a la exfiltración del archivo /etc/hostname
al servidor del atacante.
En este caso, vamos a hacer que el servidor cargue un DTD malicioso que mostrará el contenido de un archivo dentro de un mensaje de error (esto solo es válido si puedes ver mensajes de error). Ejemplo de aquí.
Un mensaje de error de análisis XML, que revela el contenido del archivo /etc/passwd
, puede ser desencadenado utilizando un Documento Tipo de Definición (DTD) externo malicioso. Esto se logra a través de los siguientes pasos:
Se define una entidad de parámetro XML llamada file
, que contiene el contenido del archivo /etc/passwd
.
Se define una entidad de parámetro XML llamada eval
, incorporando una declaración dinámica para otra entidad de parámetro XML llamada error
. Esta entidad error
, cuando se evalúa, intenta cargar un archivo inexistente, incorporando el contenido de la entidad file
como su nombre.
Se invoca la entidad eval
, lo que lleva a la declaración dinámica de la entidad error
.
La invocación de la entidad error
resulta en un intento de cargar un archivo inexistente, produciendo un mensaje de error que incluye el contenido del archivo /etc/passwd
como parte del nombre del archivo.
El DTD externo malicioso puede ser invocado con el siguiente XML:
Al ejecutarse, la respuesta del servidor web debería incluir un mensaje de error que muestre el contenido del archivo /etc/passwd
.
Tenga en cuenta que el DTD externo nos permite incluir una entidad dentro de la segunda (eval
), pero está prohibido en el DTD interno. Por lo tanto, no puede forzar un error sin usar un DTD externo (generalmente).
¿Y qué pasa con las vulnerabilidades XXE ciegas cuando las interacciones fuera de banda están bloqueadas (las conexiones externas no están disponibles)?
Una laguna en la especificación del lenguaje XML puede exponer datos sensibles a través de mensajes de error cuando el DTD de un documento mezcla declaraciones internas y externas. Este problema permite la redefinición interna de entidades declaradas externamente, facilitando la ejecución de ataques XXE basados en errores. Tales ataques explotan la redefinición de una entidad de parámetro XML, originalmente declarada en un DTD externo, desde dentro de un DTD interno. Cuando las conexiones fuera de banda son bloqueadas por el servidor, los atacantes deben confiar en archivos DTD locales para llevar a cabo el ataque, con el objetivo de inducir un error de análisis para revelar información sensible.
Considere un escenario donde el sistema de archivos del servidor contiene un archivo DTD en /usr/local/app/schema.dtd
, definiendo una entidad llamada custom_entity
. Un atacante puede inducir un error de análisis XML revelando el contenido del archivo /etc/passwd
al enviar un DTD híbrido de la siguiente manera:
Los pasos descritos son ejecutados por este DTD:
La definición de una entidad de parámetro XML llamada local_dtd
incluye el archivo DTD externo ubicado en el sistema de archivos del servidor.
Ocurre una redefinición para la entidad de parámetro XML custom_entity
, originalmente definida en el DTD externo, para encapsular un exploit XXE basado en errores. Esta redefinición está diseñada para provocar un error de análisis, exponiendo el contenido del archivo /etc/passwd
.
Al emplear la entidad local_dtd
, se activa el DTD externo, abarcando la custom_entity
recién definida. Esta secuencia de acciones precipita la emisión del mensaje de error buscado por el exploit.
Ejemplo del mundo real: Los sistemas que utilizan el entorno de escritorio GNOME a menudo tienen un DTD en /usr/share/yelp/dtd/docbookx.dtd
que contiene una entidad llamada ISOamso
.
Como esta técnica utiliza un DTD interno, primero necesitas encontrar uno válido. Podrías hacer esto instalando el mismo SO / Software que está utilizando el servidor y buscando algunos DTDs predeterminados, o obteniendo una lista de DTDs predeterminados dentro de los sistemas y verificando si alguno de ellos existe:
Para más información, consulta https://portswigger.net/web-security/xxe/blind
En el siguiente increíble repositorio de github puedes encontrar rutas de DTDs que pueden estar presentes en el sistema:
Además, si tienes la imagen de Docker del sistema víctima, puedes usar la herramienta del mismo repositorio para escanear la imagen y encontrar la ruta de los DTDs presentes dentro del sistema. Lee el Readme del github para aprender cómo.
Para una explicación más detallada de este ataque, consulta la segunda sección de este increíble post de Detectify.
La capacidad de subir documentos de Microsoft Office es ofrecida por muchas aplicaciones web, que luego proceden a extraer ciertos detalles de estos documentos. Por ejemplo, una aplicación web puede permitir a los usuarios importar datos subiendo una hoja de cálculo en formato XLSX. Para que el analizador extraiga los datos de la hoja de cálculo, inevitablemente necesitará analizar al menos un archivo XML.
Para probar esta vulnerabilidad, es necesario crear un archivo de Microsoft Office que contenga una carga útil XXE. El primer paso es crear un directorio vacío al que se pueda descomprimir el documento.
Una vez que el documento ha sido descomprimido, el archivo XML ubicado en ./unzipped/word/document.xml
debe ser abierto y editado en un editor de texto preferido (como vim). El XML debe ser modificado para incluir la carga útil XXE deseada, a menudo comenzando con una solicitud HTTP.
Las líneas XML modificadas deben ser insertadas entre los dos objetos XML raíz. Es importante reemplazar la URL con una URL monitorizable para las solicitudes.
Finalmente, el archivo puede ser comprimido para crear el archivo malicioso poc.docx. Desde el directorio "descomprimido" creado previamente, se debe ejecutar el siguiente comando:
Ahora, el archivo creado puede ser subido a la aplicación web potencialmente vulnerable, y se puede esperar que aparezca una solicitud en los registros de Burp Collaborator.
El protocolo jar es accesible exclusivamente dentro de aplicaciones Java. Está diseñado para permitir el acceso a archivos dentro de un archivo PKZIP (por ejemplo, .zip
, .jar
, etc.), atendiendo tanto a archivos locales como remotos.
Para poder acceder a archivos dentro de archivos PKZIP es súper útil abusar de XXE a través de archivos DTD del sistema. Consulta esta sección para aprender cómo abusar de archivos DTD del sistema.
El proceso detrás de acceder a un archivo dentro de un archivo PKZIP a través del protocolo jar implica varios pasos:
Se realiza una solicitud HTTP para descargar el archivo zip desde una ubicación especificada, como https://download.website.com/archive.zip
.
La respuesta HTTP que contiene el archivo se almacena temporalmente en el sistema, típicamente en una ubicación como /tmp/...
.
Luego, se extrae el archivo para acceder a su contenido.
Se lee el archivo específico dentro del archivo, file.zip
.
Después de la operación, se eliminan cualquier archivo temporal creado durante este proceso.
Una técnica interesante para interrumpir este proceso en el segundo paso implica mantener la conexión del servidor abierta indefinidamente al servir el archivo del archivo. Las herramientas disponibles en este repositorio se pueden utilizar para este propósito, incluyendo un servidor Python (slow_http_server.py
) y un servidor Java (slowserver.jar
).
Escribir archivos en un directorio temporal puede ayudar a escalar otra vulnerabilidad que involucra un recorrido de ruta (como inclusión de archivos locales, inyección de plantillas, XSLT RCE, deserialización, etc).
En hosts de Windows, es posible obtener el hash NTML del usuario del servidor web configurando un controlador responder.py: