A8 Insecure Deserialization (2017)
A8 Insecure Deserialization
Insecure Deserialization is a vulnerability which occurs when untrusted data is used to abuse the logic of an application, inflict a denial of service (DoS) attack, or even execute arbitrary code upon it being deserialized. It also occupies the #8 spot in the OWASP Top 10 2017 list.
In order to understand what insecure deserialization is, we first must understand what serialization and deserialization are.
What is Serialization?
Serialization refers to a process of converting an object into a format which can be persisted to disk (for example, saved to a file or a datastore), sent through streams (for example stdout), or sent over a network. The format in which an object is serialized into, can either be binary or structured text (for example XML, JSON YAML…). JSON and XML are two of the most commonly used serialization formats within web applications.
What is Deserialization?
Deserialization, on the other hand, is the opposite of serialization, that is, transforming serialized data coming from a file, stream, or network socket into an object.
Web applications make use of serialization and deserialization on a regular basis and most programming languages even provide native features to serialize data (especially into common formats like JSON and XML). It’s important to understand that safe deserialization of objects is normal practice in software development. The trouble, however, starts when deserializing untrusted user input.
Most programming languages offer the ability to customize deserialization processes. Unfortunately, it’s frequently possible for an attacker to abuse these deserialization features when the application is deserializing untrusted data which the attacker controls. Successful insecure deserialization attacks could allow an attacker to carry out denial-of-service (DoS) attacks, authentication bypasses, and remote code execution attacks.
JSON is a format that encodes objects in a string. Serialization means to convert an object into that string, and deserialization is its inverse operation.
When transmitting data or storing them in a file, the data are required to be byte strings, but complex objects are seldom in this format. Serialization can convert these complex objects into byte strings for such use. After the byte strings are transmitted, the receiver will have to recover the original object from the byte string. This is known as deserialization.
Say, you have an object
{foo: [1, 4, 7, 10], bar: "baz"}
serializing into JSON will convert it into a string:
'{"foo":[1,4,7,10],"bar":"baz"}'
which can be stored or sent through wire to anywhere. The receiver can then deserialize this string to get back the original object. {foo: [1, 4, 7, 10], bar: "baz"}.
Example Attack Scenarios
Scenario #1:
A React application calls a set of Spring Boot microservices. Being functional programmers, they tried to ensure that their code is immutable. The solution they came up with is serializing user state and passing it back and forth with each request. An attacker notices the "R00" Java object signature, and uses the Java Serial Killer tool to gain remote code execution on the application server.
Scenario #2:
A PHP forum uses PHP object serialization to save a "super" cookie, containing the user's user ID, role, password hash, and other state:
a:4:{i:0;i:132;i:1;s:7:"Mallory";i:2;s:4:"user";i:3;s:32:"b6a8b3bea87fe0e05022f8f3c88bc960";}
An attacker changes the serialized object to give themselves admin privileges: a:4:{i:0;i:1;i:1;s:5:"Alice";i:2;s:5:"admin";i:3;s:32:"b6a8b3bea87fe0e05022f8f3c88bc960";}
How To Prevent Insecure Deserialization
The only safe architectural pattern is not to accept serialized objects from untrusted sources or to use serialization mediums that only permit primitive data types.
If that is not possible, consider one of more of the following:
Implementing integrity checks such as digital signatures on any serialized objects to prevent hostile object creation or data tampering.
Enforcing strict type constraints during deserialization before object creation as the code typically expects a definable set of classes. Bypasses to this technique have been
demonstrated, so reliance solely on this is not advisable.
Isolating and running code that deserializes in low privilege environments when possible.
Log deserialization exceptions and failures, such as where the incoming type is not the expected type, or the deserialization throws exceptions.
Restricting or monitoring incoming and outgoing network connectivity from containers or servers that deserialize.
Monitoring deserialization, alerting if a user deserializes constantly.
No comments