In this POST it's going to be explained an example using java.io.Serializable.
Serializable
The Java Serializable interface (java.io.Serializable is a marker interface your classes must implement if they are to be serialized and deserialized. Java object serialization (writing) is done with the ObjectOutputStream and deserialization (reading) is done with the ObjectInputStream.
Lets see an example with a class Person which is serializable. This class overwrites the readObject function, so when any object of this class is deserialized this function is going to be executed.
In the example, the readObject function of the class Person calls the function eat() of his pet and the function eat() of a Dog (for some reason) calls a calc.exe. We are going to see how to serialize and deserialize a Person object to execute this calculator:
importjava.io.Serializable;importjava.io.*;publicclassTestDeserialization {interfaceAnimal {publicvoideat(); }//Class must implements Serializable to be serializablepublicstaticclassCatimplementsAnimal,Serializable { @Overridepublicvoideat() {System.out.println("cat eat fish"); } }//Class must implements Serializable to be serializablepublicstaticclassDogimplementsAnimal,Serializable { @Overridepublicvoideat() {try {Runtime.getRuntime().exec("calc"); } catch (IOException e) {e.printStackTrace(); }System.out.println("dog eat bone"); } }//Class must implements Serializable to be serializablepublicstaticclassPersonimplementsSerializable {privateAnimal pet;publicPerson(Animal pet){this.pet= pet; }//readObject implementation, will call the readObject from ObjectInputStream and then call pet.eat()privatevoidreadObject(java.io.ObjectInputStream stream)throwsIOException,ClassNotFoundException { pet = (Animal) stream.readObject();pet.eat(); } }publicstaticvoidGeneratePayload(Object instance,String file)throwsException {//Serialize the constructed payload and write it to the fileFile f =newFile(file);ObjectOutputStream out =newObjectOutputStream(new FileOutputStream(f));out.writeObject(instance);out.flush();out.close(); }publicstaticvoidpayloadTest(String file) throwsException {//Read the written payload and deserialize itObjectInputStream in =newObjectInputStream(new FileInputStream(file));Object obj =in.readObject();System.out.println(obj);in.close(); }publicstaticvoidmain(String[] args) throwsException {// Example to call Person with a DogAnimal animal =newDog();Person person =newPerson(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"); }}
Conclusion
As you can see in this very basic example, the "vulnerability" here appears because the readObject function is calling other vulnerable functions.