Today we’ll be exploiting the unserialize() function in PHP. The major lesson here is to NEVER unserialize() user input, and I’ll show you why. PHP.net describes the serialize() function as follows:
“Generates a storable representation of a value. This is useful for storing or passing PHP values around without losing their type and structure. To make the serialized string into a PHP value again, use unserialize().” They further state that, “When serializing objects, PHP will attempt to call the member function __sleep() prior to serialization. This is to allow the object to do any last minute clean-up, etc. prior to being serialized. Likewise, when the object is restored using unserialize() the __wakeup() [or __construct()] member function is called”.
According to OWASP:
“In order to successfully exploit a PHP Object Injection vulnerability two conditions must be met:
- The application must have a class which implements a PHP magic method (such as __wakeup or __destruct [or __construct) that can be used to carry out malicious attacks, or to start a ‘POP chain’.
- All of the classes used during the attack must be declared when the vulnerable unserialize() is being called, otherwise object autoloading must be supported for such classes.”
Well we’ve got a class called Logger that implements __construct() and __destruct(), and it’s what starts off the code, so it is ahead of the unserialize() function, see here:
Later we can see them unserialize() input via $_COOKIE[“drawing”]:
What we can do here is pass unserialize() a malicious Logger object that, for example, creates a “log file” call win.php and writes the following message in the “loge file:
<?php system(‘cat /etc/natas_webpass/natas27’);?>
To create the serialized version of the Logger object I edited the source code as follows:
As you can see, the $logFile field is set to “img/win.php”, and $exitMsg is set to our malicious php code. After the class definition I echoed out a serialized and then base64 encoded version of an instance of the Logger object. It must be base64 encoded because it will later be base64 decoded before being unserialized. The output looks like this:
That is what we will set the “drawing” field of our cookie to. When this is unserialized by the script, it will create an instance of Logger with the values we set above. This is because, as previously stated, when unserialize() is used it calls the __construct() function of that object. This should result in the creation of win.php in the img/ directory of their webserver, which will spit out our password. Let’s see:
We see some bullshit about “cannot use type Logger as array”, but the important thing is, was win.php created?