What is a Java Deserialization
A Java deserialization vulnerability occurs when a Java application deserializes untrusted data and is a seldom-mentioned yet massive Application Security issue.
During the deserialization process, the data is transformed from its stream of bytes (binary representation) into an object that the application can use.
This process is made possible by the Apache Commons Collection library. The name of the class that’s responsible for the transformation is InvokerTransformer.
Due to its utilization of a reflection method, the InvokerTransformer class is also responsible for the exploitability of Java deserialization.
According to a study by SANS Institute, deserialization vulnerabilities are the most common vulnerability in Java applications, accounting for 30% of all vulnerabilities detected.
Another study by Veracode found that 88% of applications tested during the first quarter of 2020 had deserialization vulnerabilities.
Deserialization vulnerabilities have affected all versions of Java since the early days and are still present. They allow attackers to inject malicious code into an application’s memory, providing unauthorized access to sensitive information.
What is deserialization, and what does it do?
Deserialization is the process of turning binary data back into an object. During serialization, an object’s state is transformed into a binary format to be written to a file, delivered over a network, or saved in a database. Deserialization requires reading the binary data and reassembling the object from it. It is the opposite of serialization.
Java has built-in support for serialization and deserialization through the java.io.Serializable interface. For an object to be serializable, it must implement this interface.
When an object is serializable, it can be read back into an object using the ObjectInputStream class and written to a binary format using the ObjectOutputStream class.
For example, consider the following class:
public class Person implements Serializable {
private String name;
private int age;
//constructor, getters, and setters
}
You can serialize an instance of this class as follows:
Person person = new Person("John", 25); FileOutputStream fos = new FileOutputStream("person.ser"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(person); oos.close();
And deserialize as follows:
FileInputStream fis = new FileInputStream("person.ser"); ObjectInputStream ois = new ObjectInputStream(fis); Person person = (Person) ois.readObject(); ois.close();
Identifying insecure deserialization exploits
When monitoring logs for insecure deserialization attempts, one should search for unusual or suspicious activity that could point to an active attack. Examples of what to look for are as follows:
- Unusual remote method invocations (RMI): If a program makes a disproportionately large number of RMI calls, this may be a sign that a hacker is attempting to take advantage of a deserialization flaw.
- Exploitation attempts: If an attacker is attempting to use a known deserialization vulnerability, it may be recorded in the logs. For instance, the logs might contain information that an attacker is trying to take advantage of a vulnerability known to exist in a particular library version.
- Unexpected class loading: The logs may contain information about an attacker trying to load a malicious class while deserialization is in progress. According to some theories, this might mean that someone is trying to run arbitrary code on the target system.
- Unusual access to sensitive data: Keep an eye out for unusual user access to information that shouldn’t be available. This access might be an example of a hacker executing arbitrary code.