hacktricks/pentesting-web/deserialization/basic-java-deserialization-...

3.9 KiB

Basic Java Deserialization (ObjectInputStream, readObject)

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 b 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:

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

This example was taken from https://medium.com/@knownsec404team/java-deserialization-tool-gadgetinspector-first-glimpse-74e99e493649

Conclusion

As you can see in this very basic example, the "vulnerability" here appears because the **readObject **function is calling other vulnerable functions.