Access Lab : https://portswigger.net/web-security/deserialization/exploiting/lab-deserialization-arbitrary-object-injection-in-php
Understanding the Concept
What are Magic Methods?
Magic methods are special methods in object-oriented programming languages that are automatically invoked under specific circumstances without needing to be explicitly called by the programmer. These methods are indicated by double underscores (__) either as a prefix or surrounding the method name.
Why are They Called “Magic”?
They’re called “magic” because they work behind the scenes, performing tasks automatically without the programmer needing to directly call them.
How are Magic Methods Used?
Developers use magic methods to define custom behavior for certain events or operations related to their classes. For example, initializing objects, handling property access, and serialization/deserialization.
Examples of Magic Methods:
__construct(): This method is called automatically when an object is created. It’s commonly used to initialize object properties.
class MyClass { public function __construct() { echo "Object created!"; } } $obj = new MyClass(); // Output: Object created!
__get() and __set(): These methods are invoked when getting or setting inaccessible properties, allowing developers to control property access.
class MyClass { private $data = []; public function __get($name) { return $this->data[$name]; } public function __set($name, $value) { $this->data[$name] = $value; } } $obj = new MyClass(); $obj->name = "John"; // Invokes __set() method echo $obj->name; // Invokes __get() method to retrieve "John"
__toString(): This method is called when an object is treated as a string. It’s useful for converting objects to string representations.
class MyClass { public function __toString() { return "This is MyClass"; } } $obj = new MyClass(); echo $obj; // Output: This is MyClass
Magic Methods and Serialization:
One important aspect of magic methods, especially in the context of security, is their usage during serialization and deserialization.
In PHP, when an object is serialized using serialize()
and then deserialized using unserialize()
, the __wakeup()
magic method is invoked if it’s defined. This allows the class to perform any necessary cleanup or initialization after deserialization.
class MyClass {
private $data;
public function __construct($data) {
$this->data = $data;
}
public function __wakeup() {
// Additional initialization after deserialization
echo "Object has been deserialized!";
}
}
$obj = new MyClass("Hello");
$serialized = serialize($obj);
$deserialized = unserialize($serialized); // Invokes __wakeup() method
Similarly, in Java, during deserialization using ObjectInputStream.readObject()
, a class can define a readObject()
method with specific visibility and signature to act as a magic method. This allows the class to control how its fields are deserialized.
import java.io.*;
class MyClass implements Serializable {
private String data;
public MyClass(String data) {
this.data = data;
}
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
// Additional initialization after deserialization
System.out.println("Object has been deserialized!");
in.defaultReadObject();
}
}
Security Implications:
While magic methods themselves aren’t inherently risky, they can become dangerous when they handle data controlled by an attacker, especially during deserialization. Attackers can manipulate serialized data to automatically trigger specific methods when certain conditions are met, potentially leading to security vulnerabilities.
Therefore, developers should be cautious when dealing with classes containing magic methods, especially in scenarios involving serialization and deserialization. It’s important to validate and sanitize any data received from serialized objects to prevent exploitation.
Objective
This lab uses a serialization-based session mechanism and is vulnerable to arbitrary object injection as a result. To solve the lab, create and inject a malicious serialized object to delete the morale.txt
file from Carlos’s home directory. You will need to obtain source code access to solve this lab.
You can log in to your own account using the following credentials: wiener:peter
Solution
- Log in to your own account and notice the session cookie contains a serialized PHP object:
This step involves accessing a website and logging in with your credentials. Once logged in, you inspect the session cookie using browser developer tools or a proxy tool like Burp Suite. The session cookie might contain serialized PHP data, which is a way to store complex data structures in a format that can be easily transmitted between different systems.
- Notice that the website references the file /libs/CustomTemplate.php:
By exploring the website’s source code or sitemap, you identify a PHP file named CustomTemplate.php located in the /libs directory. This file is referenced or included in the website’s codebase.
- Right-click on the file and select “Send to Repeater” in Burp Suite:
Burp Suite is a popular cybersecurity tool used for testing web applications. Within Burp Suite, you use the “Repeater” tool to manually modify and send HTTP requests. By sending the CustomTemplate.php file to the Repeater tool, you can analyze and manipulate the requests associated with it. - In Burp Repeater, notice that you can read the source code by appending a tilde (~) to the filename in the request line:
Burp Repeater allows you to manipulate various components of an HTTP request, including filenames. By appending a tilde (~) character to the filename in the request, you can potentially access the corresponding source code of the PHP file.
- In the source code, notice the CustomTemplate class contains the __destruct() magic method:
Upon examining the source code of CustomTemplate.php, you discover that it defines a PHP class called CustomTemplate. This class includes a special magic method called __destruct(), which is automatically invoked when an object of the class is destroyed or goes out of scope.
The __destruct() method invokes the unlink() method on the lock_file_path attribute, deleting the file on this path:
Within the __destruct() method of the CustomTemplate class, there is a call to the unlink() function. This function is used to delete a file specified by its path. The path to the file is stored in the lock_file_path attribute of the CustomTemplate object.This code is vulnerable to a deserialization attack because it utilizes the
__destruct()
magic method, which is automatically invoked when an object is destroyed or goes out of scope. In this case, the__destruct()
method is intended to remove a lock file associated with the template file.Here’s how the vulnerability can be exploited:
- An attacker can manipulate the data stored in a cookie, which is then deserialized into an object of the
CustomTemplate
class. This deserialization occurs when theunserialize()
function is called with the cookie data. - When the object is serialized, the
__destruct()
method is included in the serialized data. - After the object is used and no longer needed, PHP automatically calls the
__destruct()
method. - If the attacker controls the cookie data and can manipulate the template file path, they can cause the
unlink()
function to be executed, leading to the deletion of arbitrary files on the server.
To illustrate this, consider the following scenario:
// Attacker-controlled cookie data $cookieData = 'O:13:"CustomTemplate":2:{s:17:"template_file_path";s:9:"index.php";s:14:"lock_file_path";s:17:"index.php.lock";}'; // Deserialize the cookie data into an object $template = unserialize($cookieData); // PHP automatically calls the __destruct() method when $template goes out of scope
In this scenario, if the attacker sets the cookie data to manipulate the template file path to something like
/var/www/html/config.php
, the__destruct()
method would executeunlink('/var/www/html/config.php')
, resulting in the deletion of theconfig.php
file.To mitigate this vulnerability, it’s important to avoid using user-controlled data in methods like
unlink()
within the__destruct()
method. Additionally, validating and sanitizing user input, as well as implementing proper access controls, can help prevent such attacks.- An attacker can manipulate the data stored in a cookie, which is then deserialized into an object of the
In Burp Decoder, use the correct syntax for serialized PHP data to create a CustomTemplate object:
Using Burp Decoder, you construct a serialized PHP object representing an instance of the CustomTemplate class. This object includes the lock_file_path attribute set to a specific file path, such as /home/carlos/morale.txt. Serialized PHP data consists of type labels (e.g., “s” for string), length indicators, and corresponding data values.
//Payload
O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}
- Object Type:
O:14:"CustomTemplate":1
: This indicates that the object being serialized belongs to the classCustomTemplate
and it has one attribute. - Attribute:
s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";
: This specifies the attributelock_file_path
with the value/home/carlos/morale.txt
. However, notice that thetemplate_file_path
attribute is missing, so its value would remain null or uninitialized. - Base64 and URL-encode the object and save it to your clipboard:
Once you’ve constructed the serialized PHP object, you encode it using Base64 encoding to ensure it can be safely transmitted over HTTP. Additionally, you URL-encode the Base64-encoded string to handle special characters. The resulting encoded string is copied to your clipboard for later use.
- Send a request containing the session cookie to Burp Repeater:
You initiate an HTTP request to the target website, ensuring that the session cookie containing the serialized PHP object is included in the request headers. This request is intercepted and displayed within Burp Repeater for further manipulation. - Replace the session cookie with the modified one in your clipboard:
In Burp Repeater, you replace the original session cookie with the modified one containing the serialized PHP object with the altered lock_file_path attribute. This ensures that when the request is sent to the server, it will execute the desired actions defined within the __destruct() method.
- Send the request:
With the modified session cookie in place, you send the manipulated request to the server using Burp Repeater. The server processes the request, which triggers the automatic invocation of the __destruct() method on the CustomTemplate object, resulting in the deletion of Carlos’s file specified by the lock_file_path attribute.
The error message you received, “PHP Fatal error: Uncaught Exception: Invalid user in /var/www/index.php:7,” suggests that an exception was thrown at line 7 of the index.php
file due to an “Invalid user” issue. However, despite the exception, the file specified in the lock_file_path
attribute (/home/carlos/morale.txt
) was still deleted.
This behavior can occur due to the way exceptions are handled in PHP. When an exception is thrown, it interrupts the normal execution flow of the script and triggers the exception handling mechanism. In PHP, uncaught exceptions typically result in a fatal error being displayed, along with a stack trace showing the path to the point where the exception was thrown.
However, it’s important to note that even though an exception was thrown and the script terminated prematurely, any code that was executed before the exception occurred will still have taken effect. In this case, the deletion of the file specified in lock_file_path
likely happened before the exception was thrown.
By following these steps, an attacker could exploit a vulnerability in the website’s codebase to delete files on the server, potentially causing harm or disrupting its functionality. This highlights the importance of secure coding practices and thorough security testing to identify and mitigate such vulnerabilities.
One reply on “Insecure Deserialization Lab 4 : Arbitrary object injection in PHP”
Aman April 29, 2024 at 11:26 am
Amazing Writeup, Helped alot.