hacktricks/src/pentesting-web/deserialization/basic-java-deserialization-objectinputstream-readobject.md

155 lines
8.5 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.

# Basic Java Deserialization with ObjectInputStream readObject
{{#include ../../banners/hacktricks-training.md}}
Bu POST'ta `java.io.Serializable` kullanarak bir örnek açıklanacak **ve neden `readObject()`'ın geçerli bir akış saldırgan kontrolündeyse son derece tehlikeli olabileceği** anlatılacak.
## Serializable
Java `Serializable` arayüzü (`java.io.Serializable`), sınıflarınızın **serileştirilmesi** ve **serileştirilmesinin geri alınması** için uygulaması gereken bir işaretçi arayüzüdür. Java nesne serileştirmesi (yazma) [`ObjectOutputStream`](http://tutorials.jenkov.com/java-io/objectoutputstream.html) ile yapılır ve serileştirilmenin geri alınması (okuma) [`ObjectInputStream`](http://tutorials.jenkov.com/java-io/objectinputstream.html) ile yapılır.
### Hatırlatma: Serileştirilmenin geri alınması sırasında hangi yöntemler örtük olarak çağrılır?
1. `readObject()` sınıfa özgü okuma mantığı (eğer uygulanmışsa ve *özel* ise).
2. `readResolve()` serileştirilen nesneyi başka bir nesne ile değiştirebilir.
3. `validateObject()` `ObjectInputValidation` geri çağırmaları aracılığıyla.
4. `readExternal()` `Externalizable` uygulayan sınıflar için.
5. Yapıcılar **çalıştırılmaz** bu nedenle gadget zincirleri yalnızca önceki geri çağırmalara dayanır.
O zincirdeki herhangi bir yöntem, saldırgan kontrolündeki verileri (komut yürütme, JNDI aramaları, yansıma vb.) çağırırsa, serileştirme rutini bir RCE gadget'ına dönüşür.
**Serileştirilebilir** olan bir **Person** sınıfı ile bir örneğe bakalım. Bu sınıf **readObject** fonksiyonunu **aşırı yükler**, böylece bu **sınıfın** **herhangi bir nesnesi** **serileştirildiğinde** bu **fonksiyon** **çalıştırılacaktır**.\
Örnekte, Person sınıfının **readObject** fonksiyonu, evcil hayvanının `eat()` fonksiyonunu çağırır ve bir Köpek'in `eat()` fonksiyonu (bir sebepten dolayı) **calc.exe**'yi çağırır. **Bu hesap makinesini çalıştırmak için bir Person nesnesini nasıl serileştirip serileştireceğimizi göreceğiz:**
**Aşağıdaki örnek <https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649> adresinden alınmıştır.**
```java
import java.io.Serializable;
import java.io.*;
public class TestDeserialization {
interface Animal {
public void eat();
}
//Class must implements Serializable to be serializable
public static class Cat implements Animal,Serializable {
@Override
public void eat() {
System.out.println("cat eat fish");
}
}
//Class must implements Serializable to be serializable
public static class Dog implements Animal,Serializable {
@Override
public void eat() {
try {
Runtime.getRuntime().exec("calc");
} catch (IOException e) {
e.printStackTrace();
}
System.out.println("dog eat bone");
}
}
//Class must implements Serializable to be serializable
public static class Person implements Serializable {
private Animal pet;
public Person(Animal pet){
this.pet = pet;
}
//readObject implementation, will call the readObject from ObjectInputStream and then call pet.eat()
private void readObject(java.io.ObjectInputStream stream)
throws IOException, ClassNotFoundException {
pet = (Animal) stream.readObject();
pet.eat();
}
}
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(String[] args) throws Exception {
// Example to call Person with a Dog
Animal animal = new Dog();
Person person = new Person(animal);
GeneratePayload(person,"test.ser");
payloadTest("test.ser");
// Example to call Person with a Cat
//Animal animal = new Cat();
//Person person = new Person(animal);
//GeneratePayload(person,"test.ser");
//payloadTest("test.ser");
}
}
```
### Sonuç (klasik senaryo)
Bu çok temel örnekte görüldüğü gibi, buradaki “zayıflık” **readObject()** metodunun **başka bir saldırgan kontrolündeki kodu çağırmasından** kaynaklanmaktadır. Gerçek dünyadaki gadget zincirlerinde, dış kütüphanelerde (Commons-Collections, Spring, Groovy, Rome, SnakeYAML, vb.) bulunan binlerce sınıf kötüye kullanılabilir saldırganın yalnızca *bir* erişilebilir gadget'a ihtiyacı vardır.
---
## 2023-2025: Java deserialization saldırılarında neler yeni?
* 2023 CVE-2023-34040: `checkDeserExWhen*` bayrakları etkinleştirildiğinde Spring-Kafka hata kayıt başlıklarının deserialization'ı, saldırgan tarafından yayımlanan konulardan keyfi gadget inşasına izin verdi. 3.0.10 / 2.9.11'de düzeltildi. ¹
* 2023 CVE-2023-36480: Aerospike Java istemcisi güvenilir sunucu varsayımı kırıldı kötü niyetli sunucu yanıtları, istemci tarafından deserialized edilen serileştirilmiş yükler içeriyordu → RCE. ²
* 2023 CVE-2023-25581: `pac4j-core` kullanıcı profili öznitelik ayrıştırması `{#sb64}` ile başlayan Base64 blob'larını kabul etti ve `RestrictedObjectInputStream` olmasına rağmen bunları deserialized etti. 4.0.0 veya üstü sürüme yükseltin.
* 2023 CVE-2023-4528: JSCAPE MFT Manager Service (port 10880) XML kodlu Java nesnelerini kabul etti ve bu da root/SYSTEM olarak RCE'ye yol açtı.
* 2024 Eski filtreleri atlayan Hibernate5, TomcatEmbed ve SnakeYAML 2.x sınıflarını içeren birden fazla yeni gadget zinciri ysoserial-plus(mod) eklendi.
## Uygulamanız gereken modern önlemler
1. **JEP 290 / Serileştirme Filtreleme (Java 9+)**
*Sınıfların bir izin listesi veya yasak listesi ekleyin:*
```bash
# Sadece DTO'larınızı ve java.base'ı kabul edin, diğer her şeyi reddedin
-Djdk.serialFilter="com.example.dto.*;java.base/*;!*"
```
Programatik örnek:
```java
var filter = ObjectInputFilter.Config.createFilter("com.example.dto.*;java.base/*;!*" );
ObjectInputFilter.Config.setSerialFilter(filter);
```
2. **JEP 415 (Java 17+) Bağlama Özel Filtre Fabrikaları** her yürütme bağlamı için (örneğin, her RMI çağrısı, her mesaj kuyruğu tüketicisi) farklı filtreler uygulamak için bir `BinaryOperator<ObjectInputFilter>` kullanın.
3. **Ham `ObjectInputStream`'i ağda açmayın** kod yürütme anlamı taşımayan JSON/Binary kodlamalarını tercih edin (Jackson `DefaultTyping` devre dışı bırakıldıktan sonra, Protobuf, Avro, vb.).
4. **Derinlikte Savunma sınırları** maksimum dizi uzunluğu, derinlik, referanslar ayarlayın:
```bash
-Djdk.serialFilter="maxbytes=16384;maxdepth=5;maxrefs=1000"
```
5. **Sürekli gadget taraması** tehlikeli bir gadget erişilebilir hale gelirse inşaatı başarısız kılmak için CI'nizde `gadget-inspector` veya `serialpwn-cli` gibi araçları çalıştırın.
## Güncellenmiş araçlar kılavuzu (2024)
* `ysoserial-plus.jar` > 130 gadget zinciri içeren topluluk çatallaması:
```bash
java -jar ysoserial-plus.jar CommonsCollections6 'calc' | base64 -w0
```
* `marshalsec` JNDI gadget üretimi için hala referans.
* `gadget-probe` ağ hizmetlerine karşı hızlı siyah kutu gadget keşfi.
* `SerialSniffer` `ObjectInputStream` tarafından okunan her sınıfı yazdıran JVMTI ajanı (filtreler oluşturmak için yararlıdır).
* **Tespit ipucu** filtre kararlarını ve reddedilen sınıfları günlüğe kaydetmek için `-Djdk.serialDebug=true` (JDK 22+) etkinleştirin.
## Güvenli `readObject()` uygulamaları için hızlı kontrol listesi
1. Metodu `private` yapın ve `@Serial` anotasyonunu ekleyin (statik analize yardımcı olur).
2. Kullanıcı tarafından sağlanan metodları asla çağırmayın veya metod içinde I/O gerçekleştirmeyin yalnızca alanları okuyun.
3. Doğrulama gerekiyorsa, deserialization'dan **sonra**, `readObject()` dışında gerçekleştirin.
4. Varsayılan serileştirme yerine `Externalizable` uygulamayı tercih edin ve açık alan okumaları yapın.
5. İç hizmetler için bile sertleştirilmiş bir `ObjectInputFilter` kaydedin (uzlaşma dayanıklı tasarım).
## Referanslar
1. Spring Security Advisory CVE-2023-34040 Java Deserialization in Spring-Kafka (Ağu 2023)
2. GitHub Security Lab GHSL-2023-044: Unsafe Deserialization in Aerospike Java Client (Tem 2023)
{{#include ../../banners/hacktricks-training.md}}