Deserialization ya Msingi ya Java na ObjectInputStream readObject
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.
Katika chapisho hiki kutafafanuliwa mfano unaotumia java.io.Serializable na kwa nini kuandika upya readObject() kunaweza kuwa hatari sana ikiwa stream inayokuja inadhibitiwa na mshambulizi.
Serializable
Interface ya Java Serializable (java.io.Serializable) ni interface ya alama ambayo madarasa yako lazima yaitekeleze ikiwa yatawekwa kuwa serialized na deserialized. Ku-serialize (kuandika) vitu vya Java hufanywa na ObjectOutputStream na deserialization (kusoma) hufanywa na ObjectInputStream.
Kumbusho: Ni methods gani huitishwa kwa njia ya kimyakimya wakati wa deserialization?
readObject()– mantiki ya kusoma maalum kwa darasa (ikiwa imetekelezwa na private).readResolve()– inaweza kubadilisha object iliyodeserialized na nyingine.validateObject()– kupitia callbacks zaObjectInputValidation.readExternal()– kwa madarasa yanayotekelezaExternalizable.- Constructors hazitekelezwi – kwa hiyo gadget chains zinategemea tu callbacks zilizotajwa hapo juu.
Method yoyote katika mfuatano huo inayofikia kutumia attacker-controlled data (command execution, JNDI lookups, reflection, etc.) inageuza taratibu ya deserialization kuwa RCE gadget.
Tuchunguze mfano wa class Person ambayo ni serializable. Darasa hili linaandika upya function ya readObject, hivyo wakati kitu chochote cha darasa hili kitakapokuwa deserialized, function hii itaendeshwa.
Katika mfano, function ya readObject ya class Person inaita function eat() ya mnyama wake wa kipenzi na function eat() ya Dog (kwa sababu fulani) inaita calc.exe. Tutaona jinsi ya ku-serialize na ku-deserialize object ya Person ili kuendesha calculator hii:
Mfano ufuatao unatoka kwa 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");
}
}
Hitimisho (senario la jadi)
Kama unavyoona katika mfano huu wa msingi kabisa, “vulnerability” hapa inaonekana kwa sababu njia ya readObject() inaitisha code nyingine iliyodhibitiwa na mshambulizi. Katika real-world gadget chains, maelfu ya classes zilizomo katika maktaba za nje (Commons-Collections, Spring, Groovy, Rome, SnakeYAML, etc.) zinaweza kutumika vibaya – mshambulizi anahitaji tu one reachable gadget ili kupata code execution.
2023-2025: What changed in real-world Java deserialization bugs?
Matukio ya hivi karibuni ni ukumbusho mzuri kwamba ObjectInputStream bugs si tena tu “upload a .ser file to a legacy HTTP endpoint”:
- Broker / queue consumers: Spring-Kafka (
CVE-2023-34040) ilionyesha kwamba deserializing exception headers kutoka kwa attacker-controlled topics inatosha ikiwa consumer inawezeshwa vigezo visivyo vya kawaidacheckDeserExWhen*. - Client-side trust of remote servers: the Aerospike Java client (
CVE-2023-36480) ilideserialize objects zilizopokelewa kutoka kwa server. Jibu la vendor lilikuwa muhimu: clients mpya waliondoa Java runtime serialization/deserialization support badala ya kujaribu kuihifadhi nyuma ya filter dhaifu. - “Restricted” streams are often still too broad:
pac4j-core(CVE-2023-25581) ilijaribu kulinda deserialization kwaRestrictedObjectInputStream, lakini seti ya darasa zilizokubaliwa bado ilikuwa kubwa vya kutosha kufanya gadget abuse iwezekanavyo.
Somo la kushambulia ni kwamba mpaka wa kuamini hatari mara nyingi si “user uploads a blob”, bali “some component the developer considered trusted can inject bytes into a stream that eventually reaches readObject()”.
Ikiwa unahitaji low-noise reachability checks kabla ya kutumia muda kwenye utafiti wa gadget kamili, tumia kurasa maalum za Java kwa:
Java DNS Deserialization, GadgetProbe and Java Deserialization Scanner
readObject() anti-patterns that still create gadget entrypoints
Hata kama class yako yenyewe sio gadget ya wazi ya RCE, mifumo ifuatayo inatosha kufanya iwe exploitable wakati objects zinazodhibitiwa na mshambulizi zikiingizwa ndani ya graph:
- Kuita overridable methods au interface methods kutoka
readObject()(pet.eat()katika PoC hapo juu ni mfano wa kawaida). - Kufanya lookups, reflection, class loading, expression evaluation, au JNDI operations wakati wa deserialization.
- Kupitia attacker-controlled collections au maps, ambazo zinaweza kusababisha
hashCode(),equals(), comparators, au transformers kama athari za pembeni. - Kusajili
ObjectInputValidationcallbacks ambazo hufanya post-processing hatarishi. - Kudhani “private
readObject()” inatosha kama ulinzi. Inadhibiti tu dispatch semantics; haifanyi deserialization kuwa salama.
Modern mitigations you should deploy
- JEP 290 / Serialization Filtering (Java 9+) Tumia allow-list na mipaka ya graph ya wazi:
-Djdk.serialFilter="com.example.dto.*;java.base/*;maxdepth=5;maxrefs=1000;maxbytes=16384;!*"
- Apply a filter on every untrusted stream, not just globally:
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 Pendelea hii pale JVM moja inapo kuwa na muktadha kadhaa za deserialization (RMI, cache replication, message consumers, admin-only imports) na kila mmoja anayehitaji allow-list tofauti.
- Keep
readObject()boring Wito tudefaultReadObject()/ explicit field reads, kisha fanya ukaguzi mkali wa invariant. Usifanye I/O, logging inayoreferensa objects zinazodhibitiwa na mshambulizi, dynamic lookups, au method calls kwenye sub-objects zilizodeserialize. - If possible, remove Java native serialization from the design
The Aerospike fix ni mfano mzuri: wakati feature haisemi lazima, kuondoa matumizi ya
readObject()/writeObject()mara nyingi ni salama zaidi kuliko kujaribu kudumisha filters kamili milele.
Detection and research workflow
ysoserialbado ni msingi kwa validation ya gadget na probes za haraka za RCE/URLDNS.marshalsecbado inafaida wakati sink inageuka katika eneo la JNDI/LDAP/RMI.GadgetInspectorinafaa unapokuwa na target jars na unahitaji kutafuta application-specific gadget chains.- Java 17 iliongeza
jdk.DeserializationFlight Recorder event, ambayo inasaidia kuona mahaliObjectInputStreaminatumiwa kweli na kama filters zinawekwa.
Quick checklist for secure readObject() implementations
- Fanya method iwe
privatena weka annotations za serialization hooks kwa@Serialili compilers wazipate signatures zisizotangazwa vizuri. - Piga
defaultReadObject()kwanza isipokuwa kama una sababu thabiti ya kusoma mwenyewe object graph nzima. - Tumia kila nested object kama iliyo attacker-controlled hadi itakapothibitishwa.
- Kamwe usiite methods kwenye collaborators zilizodeserialize kutoka ndani ya
readObject(). - Panga code review pamoja na ukaguzi wa
ObjectInputFilter; “safe-lookingreadObject()code” haitoshi ikiwa stream bado inakubali classes za aina yoyote.
References
- OpenJDK JEP 415: Context-Specific Deserialization Filters
- GitHub Security Lab: GHSL-2022-085 / CVE-2023-25581 (
pac4j-coredeserialization leading to RCE)
Tip
Jifunze na fanya mazoezi ya AWS Hacking:
HackTricks Training AWS Red Team Expert (ARTE)
Jifunze na fanya mazoezi ya GCP Hacking:HackTricks Training GCP Red Team Expert (GRTE)
Jifunze na fanya mazoezi ya Azure Hacking:
HackTricks Training Azure Red Team Expert (AzRTE)
Support HackTricks
- Angalia mpango wa usajili!
- Jiunge na 💬 kikundi cha Discord au kikundi cha telegram au tufuatilie kwenye Twitter 🐦 @hacktricks_live.
- Shiriki mbinu za hacking kwa kuwasilisha PRs kwa HackTricks na HackTricks Cloud repos za github.


