yii反序列化漏洞复现及利用

本文详细介绍了Yii2框架在2.0.38之前版本存在的反序列化漏洞,该漏洞允许攻击者通过构造恶意请求执行任意命令。文章通过环境复现、漏洞分析和PoC展示,揭示了漏洞的触发点和利用链,涉及yiidbBatchQueryResult、FakerGenerator等类的方法。同时,提供了多个不同版本的exploit示例,包括ctfshow平台上的实战应用。

yii反序列化漏洞

Yii框架

Yii 是一个适用于开发 Web2.0 应用程序的高性能PHP 框架。

Yii 是一个通用的 Web 编程框架,即可以用于开发各种用 PHP 构建的 Web 应用。 因为基于组件的框架结构和设计精巧的缓存支持,它特别适合开发大型应用, 如门户网站、社区、内容管理系统(CMS)、 电子商务项目和 RESTful Web 服务等。

Yii 当前有两个主要版本:1.1 和 2.0。 1.1 版是上代的老版本,现在处于维护状态。 2.0 版是一个完全重写的版本,采用了最新的技术和协议,包括依赖包管理器 Composer、PHP 代码规范 PSR、命名空间、Traits(特质)等等。 2.0 版代表新一代框架,是未来几年中我们的主要开发版本。

Yii 2.0 还使用了 PHP 的最新特性, 例如命名空间Trait(特质)

漏洞描述

Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在调用unserialize 时,攻击者可通过构造特定的恶意请求执行任意命令。CVE编号是CVE-2020-15148。

2.0.38已修复,官方给yii\db\BatchQueryResult类加了一个__wakeup()函数,__wakeup方法在类被反序列化时会自动被调用,而这里这么写,目的就是在当BatchQueryResult类被反序列化时就直接报错,避免反序列化的发生,也就避免了漏洞。

环境复现

本地使用phpstudy进行环境搭建

一定要选到YII安装目录的web目录,端口号重置下。配置好以后 就可以访问了

修改config\web.php中的cookieValidationKey为任意值,作为yii\web\Request::cookieValidationKey的加密值,不设置会报错

由于是反序列化利用链,我们需要一个入口点,在controllers目录下创建一个Controller:

action为:http://url/index.php?r=test/test

controllers/TestController.php

<?php

namespace app\controllers;

use yii\web\Controller;

class TestController extends Controller{
   
   
    public function actionTest($data){
   
   
        return unserialize(base64_decode($data));
    }
}

漏洞分析

漏洞的出发点是在\yii\vendor\yiisoft\yii2\db\BatchQueryResult.php文件中

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

    /**
     * Resets the batch query.
     * This method will clean up the existing batch query so that a new batch query can be performed.
     */
    public function reset()
    {
   
   
        if ($this->_dataReader !== null) {
   
   
            $this->_dataReader->close();
        }
        $this->_dataReader = null;
        $this->_batch = null;
        $this->_value = null;
        $this->_key = null;
    }

正常来说跟进close()方法,但没有找到利用点。但是这里_dataReader是可控的,可以通过触发__call方法来进行利用。

__call(),在对象中调用一个不可访问方法时调用

当一个对象调用不可访问的close方法或者类中没有close方法,即可触发__call。全局搜索一下__call方法,在\vendor\fzaninotto\faker\src\Faker\Generator.php存在合适的方法

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

继续跟进format方法

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

call_user_func_array:调用回调函数,并把一个数组参数作为回调函数的参数

使用方法:

call_user_func_array(callable $callback, array $param_arr): mixed 
callback
    被调用的回调函数。
param_arr
    要被传入回调函数的数组,这个数组得是索引数组。

示例:

<?php
namespace Foobar;
class Foo {
   
   
    static public function test($name) {
   
   
        print "Hello {
     
     $name}!\n";
    }
}
// As of PHP 5.3.0
call_user_func_array(__NAMESPACE__ .'\Foo::test', array('Hannes'));
// As of PHP 5.3.0
call_user_func_array(array(__NAMESPACE__ .'\Foo', 'test'), array('Philip'));
?>

跟进getFormatter

public function getFormatter($formatter)
    {
   
   
        if (isset($this->formatters[$formatter])) {
   
   
            return $this->formatters[$formatter];
        }
        foreach ($this->providers as $provider) {
   
   
            if (method_exists($provider, $formatter)) {
   
   
                $this->formatters[$formatter] = array($provider, $formatter);

                return $this->formatters[$formatter];
            }
        }
        throw new \InvalidArgumentException(sprintf('Unknown formatter "%s"', $formatter));
    }

因为$this->formatters是可控的,因此getFormatter方法的返回值也是我们可控的,因此call_user_func_array($this->getFormatter($formatter), $arguments);中,第一个参数可控,第二个参数为空。

这一步就需要一个执行类,这时需要类中的方法需要满足两个条件

  1. 方法所需的参数只能是其自己类中存在的(即参数:$this->args
  2. 方法需要有命令执行功能
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Snakin_ya

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值