前言

前些日子,骑士cms 官方公布了一个系统紧急风险漏洞升级通知:骑士cms 6.0.48存在一处任意文件包含漏洞,利用该漏洞对payload文件进行包含,即可造成远程代码执行漏洞。这篇文章将从漏洞公告分析开始,叙述一下笔者分析漏洞与构造payload时遇到的有趣的事情。

漏洞情报

官方发布的系统紧急风险漏洞升级通知如下:

http://www.74cms.com/news/show-2497.html

从官方公布的信息来看,官方修复了两个地方:

1、/Application/Common/Controller/BaseController.class.php

2、/ThinkPHP/Library/Think/View.class.php

从BaseController.class.php这处补丁来看:

笔者猜测漏洞多半出在了渲染简历模板的assign_resume_tpl方法中。从补丁修复上来看,增添了如下代码

$tpl_file = $view->parseTemplate($tpl);

if(!is_file($tpl_file)){

return false;

}

可以发现程序通过$view->parseTemplate对$tpl参数进行处理,并对处理结果$tpl_file进行is_file判断

我们先跟入$view->parseTemplate看看

从上图143行的结果来看,parseTemplate中也是先通过is_file判断,然后将符合的结果返回。

如果此处传入的$tpl变量是文件,那么这个文件可以顺利的通过parseTemplate与assign_resume_tpl方法中的is_file判断。回想一下,这是一个文件包含漏洞,成功利用的先前条件是恶意的文件得存在,然后被包含。这个漏洞多半是通过assign_resume_tpl方法的$tpl参数传入一个真实存在的待包含的恶意文件,而补丁先通过parseTemplate方法内的is_file判断了一次这个恶意文件是否存在,接着又在assign_resume_tpl方法通过is_file方法判断一次,成功的利用一定会使is_file为true。那assign_resume_tpl方法中增加的代码是否有作用?又有着什么作用?

这个问题笔者将在文章最后介绍。

接下来从第二处View.class.php这处补丁来看:

补丁将fetch 方法中

if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile);

代码注释替换为

if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_'));

在thinkphp中,E()函数是用来抛出异常处理的。可见这处的修改应该是不想让$templateFile变量值写到日志log文件中。

单从这点来看,命令执行所需的payload百分百是可以通过$templateFile变量写到log文件里的,然后配合任意文件包含漏洞将这个log文件包含并执行。

漏洞分析

通过对漏洞情报的分析,我们差不多知道了这个漏洞的来龙去脉:

  1. 通过控制fetch 方法中$templateFile变量,将payload写入log文件

  2. 通过assign_resume_tpl方法包含这个存在payload的log文件

首先我们抛开怎么把payload写入log文件,先来看看文件包含漏洞怎么回事。

经过上文的猜测,我们可以通过assign_resume_tpl方法包含任意文件。首先我们要看看怎么通过请求调用assign_resume_tpl方法

如何访问assign_resume_tpl方法

assign_resume_tpl方法位于common模块base控制器下。通过对Thinkphp路由的了解,assign_resume_tpl方法多半是用如下url进行调用

http://127.0.0.1//74cms/index.php?m=common&c=base&a=assign_resume_tpl

但是实际上,程序抛出了个错误

这是为什么呢?经过动态调试发现一个有意思的事情:common模块是并不能被直接调用的。原因如下:

\ThinkPHP\Library\Think\Dispatcher.class.php中存在如下代码

从上图代码可见,因为我们common模块位于MODULE_DENY_LIST中,因此不能直接通过m=common来调用common模块。

既然不能直接调用,看看有没有其他的办法调用common模块base控制器下的assign_resume_tpl方法

经过研究发现,几乎所有其他的控制器,最终都继承自common模块的BaseController控制器

我们拿Home模块的AbcController控制器举例,见下图:

AbcController 继承FrontendController

而FrontendController由继承了BaseController

因此可以通过get请求

点击收藏 | 1 关注 | 1
登录 后跟帖