Insecure Deserialization With PHP Type Juggling
Privilege escalation with insecure deserialization with PHP type Juggling
In this blog, we will take a look at how insecure deserialization occurs along with how to exploit it by PHP type juggling in the end for escalation the privileges of a low end user.
Insecure Deserialization
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 to 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.
Reasons
Insecure deserialization typically arises because there is a general lack of understanding of how dangerous deserializing user-controllable data can be. Ideally, user input should never be deserialized at all.
However, sometimes website owners think they are safe because they implement some form of additional check on the deserialized data. This approach is often ineffective because it is virtually impossible to implement validation or sanitization to account for every eventuality. These checks are also fundamentally flawed as they rely on checking the data after it has been deserialized, which in many cases will be too late to prevent the attack.
PHP Serialization Format
Although there are serialization formats for every languages but in this blog we'll take a look at how PHP serialization works. The challenge is related to that
PHP uses a mostly human-readable string format, with letters representing the data type and numbers representing the length of each entry. For example, consider a User
object with the attributes:
When serialized, this object may look something like this:
This can be interpreted as follows:
O:4:"User"
- An object with the 4-character class name"User"
2
- the object has 2 attributess:4:"name"
- The key of the first attribute is the 4-character string"name"
s:6:"carlos"
- The value of the first attribute is the 6-character string"carlos"
s:10:"isLoggedIn"
- The key of the second attribute is the 10-character string"isLoggedIn"
b:1
- The value of the second attribute is the boolean valuetrue
The native methods for PHP serialization are serialize()
and unserialize()
. If you have source code access, you should start by looking for unserialize()
anywhere in the code and investigating further.
Modifying serialized data types with Type Juggling.
To better understand how PHP Type Juggling works behind the scenes, refer to my other blog
pagePHP Type JugglingNow onsider a case where this loose comparison operator is used in conjunction with user-controllable data from a deserialized object. This could potentially result in dangerous logic flaws
Let's say an attacker modified the password attribute so that it contained the integer 0
instead of the expected string. As long as the stored password does not start with a number, the condition would always return true
, enabling an authentication bypass. Note that this is only possible because deserialization preserves the data type. If the code fetched the password from the request directly, the 0
would be converted to a string and the condition would evaluate to false
.
Be aware that when modifying data types in any serialized object format, it is important to remember to update any type labels and length indicators in the serialized data too. Otherwise, the serialized object will be corrupted and will not be deserialized.
Example
Access the lab from the below link.
Objective -> This lab uses a serialization-based session mechanism and is vulnerable to authentication bypass as a result. To solve the lab, edit the serialized object in the session cookie to access the administrator
account. Then, delete Carlos.
You can log in to your own account using the following credentials: wiener:peter
Before we begin, configure burp suite to listen and capture requests in the background.
Login with the credentials provided
Check the Burp history. Take a look at the GET /my-account.
The request contains a session cookie that appears to be URL and Base64-encoded. Copy the string and paste it in Burp decoder.
It is a PHP serialized object. Send the request to repeater.
Go to the Inspector on the right. Then click on cookie-session
Now do the following:
Update the length of the
username
attribute to13
.Change the username to
administrator
.Change the access token to the integer
0
. As this is no longer a string, you also need to remove the double-quotes surrounding the value.Update the data type label for the access token by replacing
s
withi
.
Apply the changes. We can the the value of cookie-session changes, take a note of it. Then send the request.
From the response it seems that we have access to admin panel. Right click -> Show response in browser -> Copy&Paste the URL
For ease of consistency, open devtools then paste the modified cookie-session. Refresh the page. Navigate to admin panel.
Delete the user.
Lab solved 🔥
Last updated