热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

thinkcmfx漏洞太大_ThinkCMFX任意文件包含漏洞(学习)

前言:最近爆出来的漏洞,ThinkCmfX版本应该是通杀的,基于3.XThinkphp开发的我们就拿这个payload来进行分析http:

前言:最近爆出来的漏洞,ThinkCmfX版本应该是通杀的,基于3.X Thinkphp开发的

我们就拿这个payload来进行分析

http://127.0.0.1/index.php?a=fetch&content=

我们要知道tp框架的特性,可以通过这种形式的路由方式进行访问相应的功能点,例如通过g\m\a参数指定分组\控制器\方法

我们可以跟进父类的fetch的方法中查看

发现还调用了父类的fetch方法return parent::fetch($templateFile,$content,$prefix);,那我们可以继续来到AppframeController,但是发现里面没有fetch那么就肯定是继承来自Controller的控制器了,继续跟进

发现调用了view类的fetch方法继续更,这里的view类是Controller构造函数中$this->view = Think::instance('Think\View');

view类中的fetch方法如下:

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; //这里进行模板文件的输出

}

可以看注释,我们的content肯定是有内容的,那么进行的就是第二个if判断,经过调式走的是第二个判断

来到这里Hook::listen('view_parse',$params); //这个是关键,第一个参数传的是view_parse,我们先看下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;

}

我们全局搜索,view_parse或者echo $name输出调试发现调用的类为ParseTemplateBehavior

'view_parse' => array(

'Behavior\ParseTemplateBehavior', // 模板解析 支持PHP、内置模板引擎和第三方模板引擎

),

在exe函数中 如果类名存在的话会进行实例化 并且调用run方法

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);

}

我们再看下ParseTemplateBehavior的类中的run方法

// 行为扩展的执行入口必须是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);

}

}

}

当payload为上面的时候走的是else语句中的,我们可以去看下Think\Template的类

public function fetch($templateFile,$templateVar,$prefix='') {

$this->tVar = $templateVar; // tvar = $_data['var']

$templateCacheFile = $this->loadTemplate($templateFile,$prefix);

//echo $templateCacheFile;

Storage::load($templateCacheFile,$this->tVar,null,'tpl');

}

它的fetch方法如下

public function fetch($templateFile,$templateVar,$prefix='') {

$this->tVar = $templateVar; // tvar = $_data['var']

$templateCacheFile = $this->loadTemplate($templateFile,$prefix); //$templateFile为$_content

//echo $templateCacheFile;

Storage::load($templateCacheFile,$this->tVar,null,'tpl');

}

其中loadTemplate方法如下传入的参数为$templateFile,其实也就是$_content

public function loadTemplate ($templateFile,$prefix='') {

if(is_file($templateFile)) {

$this->templateFile = $templateFile;

// 读取模板文件内容

$tmplContent = file_get_contents($templateFile);

}else{

$tmplContent = $templateFile;

}

// 根据模版文件名定位缓存文件

$tmplCacheFile = $this->config['cache_path'].$prefix.md5($templateFile).$this->config['cache_suffix'];

// 判断是否启用布局

if(C('LAYOUT_ON')) {

if(false !== strpos($tmplContent,'{__NOLAYOUT__}')) { // 可以单独定义不使用布局

$tmplContent = str_replace('{__NOLAYOUT__}','',$tmplContent);

}else{ // 替换布局的主体内容

$layoutFile = THEME_PATH.C('LAYOUT_NAME').$this->config['template_suffix'];

// 检查布局文件

if(!is_file($layoutFile)) {

E(L('_TEMPLATE_NOT_EXIST_').':'.$layoutFile);

}

$tmplContent = str_replace($this->config['layout_item'],$tmplContent,file_get_contents($layoutFile));

}

}

// 编译模板内容

$tmplContent = $this->compiler($tmplContent);

Storage::put($tmplCacheFile,trim($tmplContent),'tpl');

return $tmplCacheFile;

}

倒数第二句调用了put方法,Storage::put($tmplCacheFile,trim($tmplContent),'tpl');,其中put和load方法同存的有File.class.php类文件,走到File.class.php类文件

public function put($filename,$content,$type=''){

$dir = dirname($filename);

if(!is_dir($dir)){

mkdir($dir,0777,true);

}

if(false === file_put_contents($filename,$content)){ //这里的内容可控

E(L('_STORAGE_WRITE_ERROR_').':'.$filename);

}else{

$this->contents[$filename]=$content;

return true;

}

}

if(false === file_put_contents($filename,$content)) //这里的内容可控,然后写入缓存文件,最后调用Storage::load加载cache文件包含文件,最终导致代码执行

public function load($_filename,$vars=null){

if(!is_null($vars)){

extract($vars, EXTR_OVERWRITE);

}

include $_filename; //进行包含文件的操作

}

转自freebuf的流程图如下:



推荐阅读
  • 本文介绍了在mac环境下使用nginx配置nodejs代理服务器的步骤,包括安装nginx、创建目录和文件、配置代理的域名和日志记录等。 ... [详细]
  • 本文整理了315道Python基础题目及答案,帮助读者检验学习成果。文章介绍了学习Python的途径、Python与其他编程语言的对比、解释型和编译型编程语言的简述、Python解释器的种类和特点、位和字节的关系、以及至少5个PEP8规范。对于想要检验自己学习成果的读者,这些题目将是一个不错的选择。请注意,答案在视频中,本文不提供答案。 ... [详细]
  • 后端开发|php教程apache配置文件,thinkphp后端开发-php教程例如你的原路径是http:localhosttestindex.phpindexadd那么现在的地址是 ... [详细]
  • php 获取无限子文件,php快速无限遍历递归文件夹目录、子文件,支持绝对路径和相对路径,支持返回生成数组...
    支持无限极遍历子文件及文件夹,支持绝对路径和相对路径!函数说明:arrayglob(string$pattern[,int$flags]) ... [详细]
  • 实现jqueryfileupload文件上传带进度条效果的方法
    jQueryFileUpload是一个Jquery图片上传组件,支持多文件上传、取消、删除,上传前缩略图预览、列表显示图片大小,支持上传进度条显示;支 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 本文介绍了Perl的测试框架Test::Base,它是一个数据驱动的测试框架,可以自动进行单元测试,省去手工编写测试程序的麻烦。与Test::More完全兼容,使用方法简单。以plural函数为例,展示了Test::Base的使用方法。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • PHP中的单例模式与静态变量的区别及使用方法
    本文介绍了PHP中的单例模式与静态变量的区别及使用方法。在PHP中,静态变量的存活周期仅仅是每次PHP的会话周期,与Java、C++不同。静态变量在PHP中的作用域仅限于当前文件内,在函数或类中可以传递变量。本文还通过示例代码解释了静态变量在函数和类中的使用方法,并说明了静态变量的生命周期与结构体的生命周期相关联。同时,本文还介绍了静态变量在类中的使用方法,并通过示例代码展示了如何在类中使用静态变量。 ... [详细]
  • 动态规划算法的基本步骤及最长递增子序列问题详解
    本文详细介绍了动态规划算法的基本步骤,包括划分阶段、选择状态、决策和状态转移方程,并以最长递增子序列问题为例进行了详细解析。动态规划算法的有效性依赖于问题本身所具有的最优子结构性质和子问题重叠性质。通过将子问题的解保存在一个表中,在以后尽可能多地利用这些子问题的解,从而提高算法的效率。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的步骤和方法
    本文介绍了在CentOS/RHEL 7/6,Fedora 27/26/25上安装JAVA 9的详细步骤和方法。首先需要下载最新的Java SE Development Kit 9发行版,然后按照给出的Shell命令行方式进行安装。详细的步骤和方法请参考正文内容。 ... [详细]
  • ThinkPHP视频教程第二十五集:关联模型
    php教程|php手册thinkphp代码,代码示例,代码参考,php短信,数据库备份代码,令牌验证,去除代码中的空白和注释Thinkphpphp教程-php手册对学习Thinkp ... [详细]
  • php怎么创建项目目录,ThinkPHP 5.1自动生成模块及目录、文件
    试用一下ThinkPHP5.1这最新版的TP框架,创建项目很简单,在web根目录使用composer搞定:composercreate-p ... [详细]
author-avatar
happy柒月卍520
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有