Insecure Deserialization
Another topic that is in the OWASP top 101. Insecure deserialization is encoded data sent between components of an application, is unpacked and processed in an unsafe way.
This presents a high severity risk, as commonly the methods used to deserialize object have access to either the interpreter used to process the web page (for example PHP, Node, Python), or the operating system itself. This can lead to Remote Code Execution and either server compromise, such as the attacker getting a remote shell.
Note
I am also going to have a brief section on XML External Entitities here, While they are a seperate vulnerblity in the OWASP top 10, they are close enough in the way they work, its worthwhile discussing here.
Transferring data
To understand this problem, we need to consider how data is transferred between programs.
Many communications protocols will not support the full range of byte values that may compose an object. Therefore we will need to encode the data into a format suitable for transmission. (For example ASCII)
Once transmitted, we can reverse the encoding operation, to get our original objects back.
Transferring data, Serialisation.
We use things like classes to give our data structure and make it easier to process. However, when it comes to transferring these classes between systems, it is difficult as we cannot easily represent the internal data structure in a binary stream.
Therefore we convert the objects into a flat format which is (usually), some kind of ASCII representation of the class. Having into a format suitable for transport across the communications protocols, we can then transmit it without loss.
Example
JSON (JavaScript Object Notation)2, is commonly used to transfer data in web applications. It works by converting objects into a set of key, value pairs.
For example consider the following Object that represents a person.
Class Person:
name = "Dan"
topic = "6005CEM"
week = 10
admin = False
The represention of this in JSON would be something like this
{"Dan": {"name": "Dan", "topic": "6005CEM", "week": 10, "admin": False}}
Example
XML is another commonly used serialisation language While it does its job, its (in my opinion) far too vebose.
However, it does give some advantages over JSON, there are some extra features (such as XPATH), the ability to define object structures, and define the mark-up used in the parser, that may (in some instances) mean its a more useful choice.
Our XML representation of the Person Object above looks something like this.
<person>
<name>Dan</name>
<topic>6005CEM</topic>
<week>10</week>
<admin>False</admin>
</person>
Other examples of generalised serialisation languages include
- CSV Comma separated files
- YAML A Superset of JSON
- BSON Binary JSON, used in things like Mongo
- Protocol Buffers Googles own serialisation
There are also Language specific serialisation such as Pythons pickle, or Rubys marshal
Transferring data: Deserialization
Having encoded and transferred our data, we need some way to turning it back into the original objects.
The deserialization process uses some parser to convert the received string back into a copy of the original object.
Insecure Deserialization
Having established what the serialisation process is, lets look at how it can be broken.
If the user has control of the data being sent between the devices, then it can be manipulated, to modify the desterilisation process.
Modifying Session Values
For our first example, lets consider how we could change the behaviour of a program. Lets imagine our application stores serialised session data inside a cookie, local storage, or something else a user can modify.
document.cookie = "session = {"user": {"name": "Dan", "topic": "6005CEM", "week": 10, "admin":False}}"
An attacked could simply modify the "admin" parameter of the serialised data, to give themselves administrative rights.
While putting data in a session cookie, or local storage may seem like a Bad Idea, there are ways of making it safe. For example we can sign the cookie with a cryptographic hash function, or have other ways of detecting whether the data has been tampered with. However, as with all things crypto, this does rely on the secret key used to sign the cookie not being leaked. If you do use this approach consider the types of data you are storing in the cookie, and avoid putting and secret information there.
Optional: Flask Signed Cookies
Consider the following flask session cookie.
TODO Put the Damn Cookie Here.....
Can you
- Decode the Cookie Parameters
- Post a new cookie on Aula
#SecretCookies
with your username- Search For the info on how the signing process works.
- You will need to find the Secret Key
Injecting new Objects
Another deserialization based attack is Object Injection.
Many serialisation protocols support the creation of new objects. Therefore an
attacker may be able to create a new object on the server by manipulating the
data.
Example
Lets say we have an online shopping application that passes data to the payment system via serialisation.
The data sent may look like this.
cart = [{"object1": {"name": "legit1", cost:10},
"object2": {"name": "legit2", cost:20}.
}]
When deserialised, the total cost is calculated by adding the cost values together.
It is possible we could create a new entry in the server by sending something like
cart = [{"object1": {"name": "legit1", cost:10},
"object2": {"name": "legit2", cost:20}.
"evil" : {"name": "evil", cost: -30}
}]
In this case the logic to calcualate the cost is effected. Meaning we get our shopping for free.
Another danger with Object Injection is where the deserialization function allows the creation of any object type it knows about. In this case we can inject a new object of an unexpected type into the application.
Example
Consider the shopping cart example above.
If we know the structure of the application (either by leaking the source code or through some other form of OS-INT (like Github)) we may be able to add new items.
Lets say there are also user objects:
{username: 'foo@bar.net', name: 'Bob Howard'....}
We could inject these as part of our cart application query to insert a new user.
cart = [{"object1": {"name": "legit1", cost:10},
"object2": {"name": "legit2", cost:20}.
{username: 'foo@bar.net', name: 'Bob Howard'....}
}]
Summary
In this article we have had a brief look at Insecure deserialization. In the next section we will examine some practical examples of how this can be used, and look at getting Remote Code Execution.