🧱

A8 Insecure Deserilialization - Rebuilt

Introduction

Threat Agents / Attack VectorsSecurity weaknessImpacts
This vulnerability enjoys the added complexity of not really being able to copy and paste payloads but attackers will rather have to learn how to recognize these objects and how to exploit them without a checklist.As more and more tools are being developed to detect this vulnerability, we can find more and more entry points for our attack.These flaws can lead to business logic vulnerabilities, data modification that is unauthorised and even remote code execution. As can be seen, the business impact can very quite wildely.

Insecure serialization has historically been seen as a super hard to grasp vulnerability, almost like a black box but while it does contain it’s challenges, so does every other issue type on the OWASP top 10. serialization is a technique used to convert an object into a byte stream for it to be stored somewhere or passed on to another system. As these serialized objects undergo deserialization, dangerous issues might arise. This issue is often referred to as “Marshalling” and “Unmarshalling”. Let’s have a look at this issue type from the Top 10 OWASP.

What is serialization?

First we will need to  get into Serialization, it is a process that occurs in applications when data needs to be transmitted and stored. This can be a very useful technique because two applications might have a completely different internal structure.

What Is Insecure Deserialization and how does it work?

While objects might be serialized to store or transfer them, at some point they might need to be deserialized again. In this deserialization logic, vulnerabilities might reside. The biggest problem with this algorithm is that the deserialization process does not discriminate as it will deserialize any object that the application might have access to. The attacker might modify attributes of the object or even insert a new one entirely. The serialization process might leave the application vulnerable in a number of ways depending on the applications logic and the object that is serialized. We will look at a few examples but please know there are more ways to exploit this vulnerability.

Via parameters

One example, let’s say our object contains the attribute “isSuperUser:false”. An attacker might simply deserialize the object to change the attribute before serializing it again. The server will then take this new object and treat the user as a SuperUser. This is only one of the examples of how insecure deserialization can occur however.

we need to be aware that attackers might just as well add a parameter they suspect the server uses as a property for example, if the server does use isSuperUser as an attribute of the serialised object, it might still accept it when deserializing it.

Via the logic of the application

For this example I want to bring up functionality that is meant to update a user's profile settings. As part of this functionality there exists a call to update a user's social media links. Normally the user can only specify the username part of the URI (for example in https://twitter.com/theXSSrat the user might normally only be able to edit the /theXSSrat part) but as part serialised object, the user can find the full URL.

After editing the URL to the users own attack servers they notice a request coming in which means a blind SSRF has been triggered by abusing business logic. This full URL should never be in the object in the first place and the attackers were able to abuse it.

Via magic events

We first of all need to start by explaining what a magic event is because that might not be clear to everyone. A magic event is a method in a programming language that gets called automatically. For example in PHP we have the following magic method: __sleep(). The problem with these magic methods is that they might be vulnerable to attacks if they handle data. This can happen through deserialized objects for example.

Via the insertion of objects

Besides the examples we have seen before, which rely heavily on insertion or adaptation of data, we can also insert arbitrary objects sometimes. This is possible because in object oriented programming, the methods that an object can access are delegated by it’s parent class. This means for example that normally, a user object has no access to the yet unreleased functionality to make a user admin. This resides on the URI /makeAdmin.php. The attacker can send a serialized object belonging to the class makeAdmin to a non expecting endpoint to change their profile picture which also expects a serialized object. The problem is that for deserialization the code does not care about what object is passed to it. It will happily deserialize it and while it may cause an error due to unexpected parameters, the damage is done and the user made themselves admin.

Types of Insecure Deserialization

We have already looked at a few examples but these can all be brought under one of three types of Insecure Deserialization.

This is also known as stored insecure deserialization because it requires the attacker to enter  an attack vector which will get stored and later on deserialized. This is often verbose, as it gives back error information if it fails and the desired result if it does not but it can also happen that the attack vector is triggered later where the attacker themselves have no access to. This would be classified as blind deserialization attacks

Blind deserialization attacks occur when attackers send an attack vector to an application which does get stored but the attacker is not able to trigger the attack vector due it being triggered from a back-end system for example. These types of vulnerabilities are hard to detect and require the attacker to have in-depth knowledge of the application as they need to know what object to test.

It’s called deferred because the attack vector will be executed by a secondary system that’s made to clean up unused objects such as garbage collection in java or file.close() in PHP.

Examples of unsafe deserialization

The first example we will go over is a CVE that has been found in an application called “Concrete5”. This application had a logfile that was checked on existing. However this log file appears to have a serialised object which could be injected with objects allowing for arbitrary PHP code execution.

More information can be found over at https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2021-36766

A second example we can find is pretty straight forward. The user object has been serialised and contains the account type. Initially this is set to “user” but it can be deserialized and changed to admin before serialising and sending it to the server again.

a:4:{i:0;i:132;i:1;s:7:”user-1”;i:2;s4:”user”;i3;s32:”b6a8b3bea87fe0e05022f8f3c88bc960”;}

When changing the parameter in bold to admin and serialising it again, the attacker can pass it on the server and elevate their privileges.

a:4:{i:0;i:132;i:1;s:7:”user-1”;i:2;s4:”admin”;i3;s32:”b6a8b3bea87fe0e05022f8f3c88bc960”;}

How to detect Insecure Deserialization?

Detection of this vulnerability will depend on what programming language is being used. Every language has their own way of indicating serialised objects so we have to learn how to recognise them per language. We have to ensure that we check all the data that is being used by the application and when we identify an object, we can try to deserialize it ourselves and see if we can exploit it.

How can I prevent Insecure Deserialization

The first tip is the simplest of all but it’s not easy to implement, all serialisation should be avoided and we should opt for a much simpler data format but this is not always possible. When organisations use a lot of serialisation already, it’s hard to faze it out but it’s recommended to also go over to simpler data formats. These are formats like JSON and XML.

If we do have to use serialisation however, we have to verify all the user controlled data and we need to make sure it contains sane data that can not be abused. For example, a user should never be able to change their own account type to admin. We also need to be aware that there have been proof of concepts on how to bypass this kind of use of strict constraints on type and parameters.

One strategy we can also take is to keep our serialization code into a sandbox or low privilege environment to lower any eventual impact that might follow a successful hack.

Like the “insufficient monitoring and logging” chapter of the OWASP top 10, we need to comply with that and make sure that we log any exceptions that occur while deserialization and investigate it later.

It also helps to ensure the API security or other security mechanisms check all incoming and outgoing data for the correct parameters and it being the correct object.

Tools to protect against Insecure Deserialization.

There are several top tools availale to use which help us in our battle against this issue type. Some will be more lanuage specific such as Java Deserialization Scanner which is a burp suite extension. Burp suite pro tends to indicate serialised objects as well which might be sufficient for some.

I have personally used ysoserial as well which is a great tool to help generate Proof of concepts for insecure deserialisation.

FindBugs plugin is an application that will also help us find vulnerabilities.

Furthermore there is Jinfinity which is a toold designed to fill up the memory of your target, this causing a DoS attack.

Serianalyzer is a java specific tool which will perform static code analysis.

Lastely we have the option to use Serializekiller script which will scan for the default set of ports but you can configure it to work for all ports.

Conclusion

This issue type has many complexities but they are not something that can’t be foreseen or tested for. We need to train testers to recognise serialised objects and to exploit them. It would help the cybersecurity community immensely.