Temel Java Deserializasyonu ObjectInputStream readObject ile
Tip
AWS Hacking öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın:HackTricks Training Azure Red Team Expert (AzRTE)
Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna, telegram grubuna katılın, X/Twitter üzerinde @hacktricks_live hesabını takip edin veya LinkedIn sayfasını ve YouTube kanalını kontrol edin.
- HackTricks ve HackTricks Cloud github depolarına PR göndererek hacking tricks paylaşın.
Bu yazıda java.io.Serializable kullanan bir örnek ve gelen stream saldırgan kontrollüyse readObject()’i override etmenin neden son derece tehlikeli olabileceği açıklanacaktır.
Serializable
Java Serializable interface (java.io.Serializable), sınıflarınızın serileştirilmesi ve deserileştirilmesi gerekiyorsa uygulamanız gereken bir marker interface’dir. Java obje serileştirme (yazma) ObjectOutputStream ile, deserileştirme (okuma) ise ObjectInputStream ile yapılır.
Hatırlatma: Deserileştirme sırasında hangi yöntemler dolaylı olarak çağrılır?
readObject()– sınıfa özgü okuma mantığı (uygulanmış ve private ise).readResolve()– deserileştirilmiş nesnenin başka bir nesne ile değiştirilmesine izin verir.validateObject()–ObjectInputValidationcallback’leri aracılığıyla.readExternal()–Externalizableuygulayan sınıflar için.- Constructor’lar çalıştırılmaz – bu nedenle gadget chains tamamen önceki callback’lere dayanır.
Zincirdeki herhangi bir yöntem saldırgan kontrollü veriyi (command execution, JNDI lookups, reflection, vb.) çağırırsa deserileştirme rutini bir RCE gadget’ına dönüşür.
Bir class Person örneği görelim; bu sınıf serializable’dır. Bu sınıf readObject fonksiyonunu overwrite eder, bu yüzden bu sınıf’a ait herhangi bir nesne deserileştirilirken 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 Dog’ın eat() fonksiyonu (her ne sebepten) calc.exe çağırır. Bir Person nesnesini nasıl serialize ve deserialize edip bu hesap makinesini çalıştıracağımızı göreceğiz:
The following example is from https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649
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 basit örnekte görebileceğiniz gibi, buradaki “vulnerabilitiy” readObject() metodunun attacker-controlled başka kodları çağırması nedeniyle ortaya çıkıyor. Gerçek dünyadaki gadget chains’lerde, dış kütüphanelerde (Commons-Collections, Spring, Groovy, Rome, SnakeYAML, vb.) bulunan binlerce sınıf suistimal edilebilir — saldırganın kod çalıştırmak için ulaşabileceği tek bir gadget yeterlidir.
2023-2025: Gerçek dünyada Java deserialization hatalarında neler değişti?
Son vakalar, ObjectInputStream hatalarının artık sadece “eski bir HTTP endpoint’ine .ser dosyası yükleme” olayı olmadığını hatırlatıyor:
- Broker / queue consumers: Spring-Kafka (
CVE-2023-34040) gösterdi ki, saldırgan kontrolündeki topic’lerden gelen exception header’larını deserialize etmek yeterli olabiliyor eğer consumer olağandışıcheckDeserExWhen*bayraklarını etkinleştiriyorsa. - Client-side trust of remote servers: Aerospike Java client (
CVE-2023-36480) sunucudan alınan nesneleri deserialize ediyordu. Vendor cevabı dikkat çekiciydi: yeni client’lar, zayıf bir filtrenin arkasında korumaya çalışmak yerine Java runtime serialization/deserialization desteğini kaldırdı. - “Restricted” streams genellikle hâlâ çok geniş oluyor:
pac4j-core(CVE-2023-25581) deserialization’ıRestrictedObjectInputStreamile korumaya çalıştı, ancak kabul edilen sınıf kümesi gadget abuse’i mümkün kılacak kadar geniş kaldı.
Ofansif ders şu ki, tehlikeli trust boundary çoğu zaman kullanıcı bir blob yüklüyor değil, geliştiricinin güvenilir saydığı bir bileşenin readObject()’e ulaşan bir akıma byte enjekte edebilmesi şeklindedir.
Tam gadget araştırmasına zaman harcamadan önce düşük-gürültülü erişilebilirlik kontrollerine ihtiyacınız varsa, Java’ya özel sayfaları kullanın:
Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner
readObject()’un hala gadget giriş noktaları yaratan anti-pattern’leri
Sınıfınız kendisi açık bir RCE gadget’ı olmasa bile, aşağıdaki kalıplar saldırgan kontrollü nesneler grafiğe gömüldüğünde onu exploitable hale getirmeye yeterlidir:
readObject()içinden override edilebilir metodları veya interface metodlarını çağırmak (pet.eat()yukarıdaki PoC’de klasik örnektir).- Deserialization sırasında lookup’lar, reflection, class loading, ifade değerlendirme veya JNDI işlemleri yapmak.
- Saldırgan kontrollü koleksiyonlar veya map’ler üzerinde yineleme yapmak; bu yan etki olarak
hashCode(),equals(), comparator’ları veya transformer’ları tetikleyebilir. - Tehlikeli post-processing yapan
ObjectInputValidationcallback’lerini kaydetmek. - “private
readObject()yeterlidir” varsayımı. Bu sadece dispatch semantiğini kontrol eder; deserialization’ı güvenli hale getirmez.
Uygulamanız gereken modern mitigasyonlar
- JEP 290 / Serialization Filtering (Java 9+)
Bir allow-list ve açık grafik sınırları kullanın:
-Djdk.serialFilter="com.example.dto.*;java.base/*;maxdepth=5;maxrefs=1000;maxbytes=16384;!*"
- Her güvenilmeyen stream’e filtre uygulayın, sadece global olarak değil:
try (var ois = new ObjectInputStream(input)) {
var filter = ObjectInputFilter.Config.createFilter(
"com.example.dto.*;java.base/*;maxdepth=5;maxrefs=1000;!*"
);
ois.setObjectInputFilter(filter);
return (Message) ois.readObject();
}
- JEP 415 (Java 17+) Context-Specific Filter Factories
Aynı JVM’de birden fazla deserialization bağlamı (RMI, cache replication, message consumers, admin-only imports) varsa ve her birinin farklı bir allow-list’e ihtiyacı varsa bunu tercih edin. readObject()’u sıkıcı tutun
SadecedefaultReadObject()/ açık alan okumalarını çağırın, sonra sıkı invariant kontrolleri yapın. I/O yapmayın, saldırgan kontrolündeki nesneleri dereference eden loglama, dinamik lookup’lar veya deserialized alt-nesneler üzerinde metod çağrıları yapmayın.- Mümkünse, Java native serialization’ı tasarımdan kaldırın
Aerospike düzeltmesi iyi bir modeldir: özellik gerekli değilse,readObject()/writeObject()kullanımını silmek, mükemmel filtreleri sonsuza dek sürdürmeye çalışmaktan genelde daha güvenlidir.
Detection and research workflow
ysoserialgadget doğrulama ve hızlı RCE/URLDNS probe’ları için temel kalmaya devam ediyor.marshalsecsink JNDI/LDAP/RMI alanına kaydığında hâlâ faydalı.- Hedef jar’larınız varsa ve uygulamaya özgü gadget zincirleri aramanız gerekirse
GadgetInspectorişe yarar. - Java 17,
jdk.DeserializationFlight Recorder event’ini ekledi; bu,ObjectInputStream’in gerçekten nerede kullanıldığını ve filtrelerin uygulanıp uygulanmadığını görmek için faydalıdır.
Güvenli readObject() implementasyonları için hızlı kontrol listesi
- Metodu
privateyapın ve serialization hook’larını@Serialile annotate edin ki derleyiciler yanlış beyan edilmiş imzaları yakalayabilsin. - Tam nesne grafını manuel okumak için güçlü bir nedeniniz yoksa önce
defaultReadObject()’ı çağırın. - Her iç içe nesneyi doğrulanana kadar saldırgan kontrollü olarak ele alın.
readObject()içinde deserialized işbirlikçiler (collaborators) üzerinde metot çağırmayın.- Kod incelemesini bir
ObjectInputFilterincelemesi ile eşleştirin; “güvenli görünenreadObject()kodu” akış hâlâ rastgele sınıfları kabul ediyorsa yeterli değildir.
Referanslar
- OpenJDK JEP 415: Context-Specific Deserialization Filters
- GitHub Security Lab: GHSL-2022-085 / CVE-2023-25581 (
pac4j-coredeserialization leading to RCE)
Tip
AWS Hacking öğrenin ve pratik yapın:
HackTricks Training AWS Red Team Expert (ARTE)
GCP Hacking öğrenin ve pratik yapın:HackTricks Training GCP Red Team Expert (GRTE)
Az Hacking öğrenin ve pratik yapın:HackTricks Training Azure Red Team Expert (AzRTE)
Değerlendirme yolları (ARTA/GRTA/AzRTA) ve Linux Hacking Expert (LHE) için tam HackTricks Training kataloğuna göz atın.
HackTricks'i Destekleyin
- abonelik planlarını kontrol edin!
- 💬 Discord grubuna, telegram grubuna katılın, X/Twitter üzerinde @hacktricks_live hesabını takip edin veya LinkedIn sayfasını ve YouTube kanalını kontrol edin.
- HackTricks ve HackTricks Cloud github depolarına PR göndererek hacking tricks paylaşın.


