10-02-2020 / From 0 to pentesting hero

PHP PHAR - file_exists can be dangerous

Today in "from 0 to pentesting hero" we will talk about a function that checks if a file with the given name exists on the hard drive.

Could such a simple functionality be harmful?

Let's look at an example of application:

<?php
class aplikacja {
	function __construct($name) {
		$this->name = './pliki/'.$name;
		if (strpos($this->name, "..") !== false) {
			die('HACKER');
		}
		if (file_exists($name)) {
			echo 'USUNIETO';
		} else {
			echo 'PLIK NIE ISTNIEJE';
		}
	}
	function __destruct() {
		echo 'EXPLOIT'.$this->name;
	}
}
new aplikacja($_GET['p']);

We check if the file provided by the user can be found on the hard disk in the files directory.

We use the file_exists function.

Of course - we are aware of the path traversal attack - where the user could use a dot and slash to check for the existence of files outside the files directory.

Hence, we check if there are two dots in the string given by the user.

If the file exists - an appropriate message will be displayed.

We also use the magic function __destruct, which removes the file that the user has requested.

In our case, we simulate this removal with the echo function - to see what is really going on in this example.

So this is a simple functionality to remove files from the server - for example, user photos in a given directory.

Not long ago, one could assume that the code used here is secure.

Is this code secure?

After all, we are defending ourselves against the path traversal attack and removing files from only one directory.

But security industry is a dynamic market - where everything is possible.

Last year, a new attack on applications created in PHP was presented at the largest Security Conference - Blackhat in the USA.

Phar files are used to carry it out. What are these files?

PHAR file

This format is similar to Java jar files.

With this format, we can package all our multi-file applications into one - a portable file that is a kind of archive.

Why is this so important from a security point of view?

Some file-reading functions support so-called wrappers1 - in addition to the standard parameters.

PHP wrappers

It is thanks to them that these functions can support additional formats.

For example, the http:// or ftp:// protocols are such wrappers.

Phar is also one of them.

What's next? Researchers have found that if we use a function that supports wrappers - like file_exists - and as a parameter we pass the phar wrapper - this function will check if the file exists - but will also open its content.

What do I mean by "open"?

Metadata

Phar archive - contains the file content, but it also stores metadata about the entire package.

And as we can read in the documentation2 - it is stored in a serialized form.

In PHP, this means that you use the serialize function to write and then unserialize function to read it.

The file_exists function invokes unserialize on the metadata of the package that we pass as a parameter.

So this is a classic object injection attack - when data from the attacker is passed to the unserialize function.

It's enough to create a sample phar file - and make it contain the object that we want to pass to the application we are attacking.

PHAR Injection

Let's see our example again.

Our goal is to delete the file outside the files directory.

So we create a phar package.

Inside, there is an object of applicationclass.

There we set the name parameter to appropriate value.

Create PHAR archive

Now just send the file to the server and then call the file_exists function using the phar wrapper.

As you can see - files outside the files directory have been removed. This is because the content of the metadata was read by the file_exists function.

Our protection against hackers didn't work - the user parameter did not contain a double dot.

Exploit in practice

What is the moral?

In the past, it was enough to check if we don't have the unserialize function in the source code of our application.

Now, you should additionally check that the parameter passed by the user does not contain the phar keyword.

Icon made by Freepik, Smashicons, Maxim Basinski Premium from www.flaticon.com