Insecure Deserialization foundations
In the world of web applications, data exchange is paramount. Often, complex objects containing user information or application state need to be transmitted and stored efficiently. Serialization and deserialization are the processes that enable this functionality. Serialization transforms objects into a streamlined byte stream suitable for storage or transmission, while deserialization reverses the process, reconstructing the original object on the receiving end.
Insecure deserialization is when user-controllable data is deserialized by a website. This potentially enables an attacker to manipulate serialized objects in order to pass harmful data into the application code.
It is even possible to replace a serialized object with an object of an entirely different class. Alarmingly, objects of any class that is available on the website will be deserialized and instantiated, regardless of which class was expected. For this reason, insecure deserialization is sometimes known as an “object injection” vulnerability.
An object of an unexpected class might cause an exception. By this time, however, the damage may already be done. Many deserialization-based attacks are completed before deserialization is finished. This means that the deserialization process itself can initiate an attack, even if the website’s own functionality does not directly interact with the malicious object. For this reason, websites whose logic is based on strongly typed languages can also be vulnerable to these techniques.
Understanding Serialization and Deserialization
![Insecure Deserialization foundations 1 serialization.drawio](https://blog.certcube.com/wp-content/uploads/2024/05/serialization.drawio.png)
Serialization: Serialization is the process of converting complex data structures, such as objects and their fields, into a “flatter” format that can be sent and received as a sequential stream of bytes. Serializing data makes it much simpler to:
- Write complex data to inter-process memory, a file, or a database
- Send complex data, for example, over a network, between different components of an application, or in an API call
Crucially, when serializing an object, its state is also persisted. In other words, the object’s attributes are preserved, along with their assigned values. For example, consider a Python class Person:
![Insecure Deserialization foundations 2 python serializatioon example 1](https://blog.certcube.com/wp-content/uploads/2024/05/python-serializatioon-example-1.png)
Deserialization: Deserialization is the process of restoring this byte stream to a fully functional replica of the original object, in the exact state as when it was serialized. The website’s logic can then interact with this deserialized object, just like it would with any other object.
Many programming languages offer native support for serialization. Exactly how objects are serialized depends on the language. Some languages serialize objects into binary formats, whereas others use different string formats, with varying degrees of human readability. Note that all of the original object’s attributes are stored in the serialized data stream, including any private fields. To prevent a field from being serialized, it must be explicitly marked as “transient” in the class declaration.
Be aware that when working with different programming languages, serialization may be referred to as marshalling (Ruby) or pickling (Python). These terms are synonymous with “serialization” in this context.
![Insecure Deserialization foundations 3 python Deserialization 1](https://blog.certcube.com/wp-content/uploads/2024/05/python-Deserialization-1.png)
In this example, the Person
object is deserialized from the person.pkl
file, reconstructing the original object with its attributes intact.
How do insecure Deserialization Vulnerabilities Arise?
Insecure deserialization happens when developers don’t realize how dangerous it can be to deserialize data from untrusted sources, like user input. Ideally, user input should never be deserialized at all.
Some developers might think they’re safe because they add checks to the deserialized data. But these checks are often not enough because it’s nearly impossible to anticipate every way the data can be manipulated. Also, these checks happen after the data has been deserialized, so they can’t prevent the attack effectively.
Another misconception is that deserialized objects are safe, especially with binary serialization. But attackers can still manipulate binary data, although it might be more challenging.
Deserialization attacks are also possible due to the many dependencies modern websites use. Attackers can exploit these dependencies to execute malicious code in unexpected places, making it hard to predict and prevent.
In short, it’s extremely difficult to deserialize untrusted input securely.
Now we understand insecure deserialization with a practical demo
First, we go Postswigger Lab Academy and open an insecure deserialization lab. Then access the lab and log in with the username and password we have. As well as simply checking attribute values, a website’s functionality might also perform dangerous operations on data from a deserialized object. In this case, you can use insecure deserialization to pass in unexpected data and leverage the related functionality to do damage.
For example, as part of a website’s “Delete user” functionality, the user’s profile picture is deleted by accessing the file path in the $user->image_location
attribute. If this $user
was created from a serialized object, an attacker could exploit this by passing in a modified object with the image_location
set to an arbitrary file path. Deleting their own user account would then delete this arbitrary file as well.
Then intercept the request.
![Insecure Deserialization foundations 4 intercept the request serialization](https://blog.certcube.com/wp-content/uploads/2024/05/intercept-the-request-serialization-1024x435.png)
Edit the serialized data so that the avatar_link
points to /home/carlos/morale.txt
. Remember to update the length indicator. The modified attribute should look like this:
![Insecure Deserialization foundations 5 decode the value](https://blog.certcube.com/wp-content/uploads/2024/05/decode-the-value.png)
Change the request line to POST /my-account/delete
and send the request. Your account will be deleted, along with Carlos’s morale.txt
file.
![Insecure Deserialization foundations 6 delete acuntchange cookie session](https://blog.certcube.com/wp-content/uploads/2024/05/delete-acuntchange-cookie-session.png)
![Insecure Deserialization foundations 7 solve the lab](https://blog.certcube.com/wp-content/uploads/2024/05/solve-the-lab-1024x454.png)
How to prevent insecure deserialization vulnerabilities?
Deserialization of user input should be avoided whenever possible due to the severe security risks it poses. When deserialization is necessary, it’s crucial to implement robust measures to ensure the data’s integrity and avoid potential exploits.
One way to protect against deserialization vulnerabilities is to incorporate a digital signature to verify the data’s integrity before deserialization. This helps ensure that the data has not been tampered with, but it’s essential to perform this check before starting the deserialization process.
Additionally, using generic deserialization features can be risky because serialized data contains all attributes of the original object, including potentially sensitive information. It’s safer to create your own class-specific serialization methods, allowing you to control which fields are exposed during deserialization.
It’s important to note that the vulnerability lies in the deserialization of user input, not in the subsequent handling of the data by gadget chains. Trying to eliminate all possible gadget chains is impractical due to the complex web of cross-library dependencies in most applications. Additionally, publicly documented memory corruption exploits can also make your application vulnerable regardless of your efforts to secure it.
Recent Comments