16

ThinkCMF 任意文件包含/代码执行漏洞

 3 years ago
source link: https://www.smi1e.top/thinkcmf-%e4%bb%bb%e6%84%8f%e6%96%87%e4%bb%b6%e5%8c%85%e5%90%ab-%e4%bb%a3%e7%a0%81%e6%89%a7%e8%a1%8c%e6%bc%8f%e6%b4%9e/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

ByteCTF的opensns 到前段时间斗象科技发的ThinkCMF 框架上的任意内容包含漏洞 再到Li4n0师傅发的TinkcmfX 前台任意代码执行分析 都是由于thinkphp模版设计缺陷再加上开发者不恰到的使用导致的。因此在这里拿ThinkCMF做为例子简单分析学习一下。

影响版本:
ThinkCMF X1.6.0
ThinkCMF X2.1.0
ThinkCMF X2.2.0
ThinkCMF X2.2.1
ThinkCMF X2.2.2

任意文件包含

http://127.0.0.1/?a=display&templateFile=README.md 

image.png

ThinkPHP框架约定可以通过 a 参数来指定对应的 action ,配置文件中的默认模块为 Portal 控制器为 Index 

image.png
因此可知调用的控制器为 Portal/Controller/IndexController.class.php 
image.png
由于没有名为 display 的 action ,因此会调用其父类 HomebaseController 的 display 方法
image.png

然后会调用 $this->parseTemplate 处理 $template 参数,当其是一个存在当文件时,直接返回,然后调用父类的 display 方法,也就是 ThinkPHP3 的 display 方法,接着会调用View类的display方法

image.png
最终 View 类的 fetch 方法。
image.png

可以明显的看到if条件中有危险操作,不过我们进不去,ThinkPHP3 中TMPL_ENGINE_TYPE 默认为 Think 。

image.png
不过else条件中有一个钩子操作 
image.png
ThinkCMFX/simplewind/Core/Library/Behavior/ParseTemplateBehavior.class.php
image.png
跟进ThinkPHP内置模板引擎类 Template 的 fetch 方法
image.png
$this->loadTemplate 方法读取了 $templateFile 文件内容后,将其编译为tpl缓存文件,返回缓存文件名
image.png
最后调用load方法将其include出来。
image.png

而在ByteCTF opensns 那道题中

<?php
public function search()
{
    $keywords=I('post.keywords','','text');

    $modules = D('Common/Module')->getAll();
    foreach ($modules as $m) {
        if ($m['is_setup'] == 1 && $m['entry'] != '') {
            if (file_exists(APP_PATH . $m['name'] . '/Widget/SearchWidget.class.php')) {
                $mod[] = $m['name'];
            }
        }
    }
    $show_search = get_kanban_config('SEARCH', 'enable', $mod, 'Home');

    $this->assign($keywords);
    $this->assign('showBlocks', $show_search);
    $this->display();
}

assign 方法的 $keywords 参数可控

image.png
通过传入数组 keywords[_filename]=/flag 令 $this->tVar[_filename]=/flag 
display()渲染时
$params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix); 

然后继续跟进ThinkPHP内置模板引擎类 Templatefetch 方法

image.png
上面的$this->tVar数组也就是 this->tVar 传入了 Storage::load 
image.png

接着变量覆盖掉了 $_filename ,从而include了出来。

image.png

http://127.0.0.1/index.php?a=display&templateFile=README.md&content=%3C?php%20phpinfo();die();

image.png

还是跟上面一样跟入 fetch 方法,

image.png
继续跟进 $this->loadTemplate 
image.png
跟进编译模板文件内容的 $this->compiler 方法
image.png
可以看到直接进行了拼接,虽然过滤了 ?><?php ,在没有定义 THINK_PATH 的情况下退出程序,但是文件包含是通过 index.php 进行访问的,不会进入该if条件,从而可以执行代码,或者也可以 <?=phpinfo();exit();?> 绕过过滤。
image.png

由于漏洞的关键点在thinkphp View 类的 fetch 方法,我们也可以直接调用 fetch 操作
http://127.0.0.1/?a=fetch&content=%3C?=phpinfo();exit(); 
同样的也可以
http://127.0.0.1/?a=fetch&templateFile=README.md 只不过无回显

image.png

原因其实就是 HomebaseController 类中的 fetch、display 方法是public的,可以被用户任意调用

image.png
而thinkphp中为 protected 
image.png

在thinkphp5.1中对此进行了修复
bytectf opensns那个题是由于用户可控assign的参数或者说是display的参数,在正常环境下基本不可能出现。

Referer

TinkcmfX 前台任意代码执行分析
ThinkCMF 框架上的任意内容包含漏洞
ByteCTF opensns


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK