ThinkPHP3.x/5.x框架缺陷可导致任意文件包含
2019-07-01 16:34:54 Author: mp.weixin.qq.com(查看原文) 阅读量:74 收藏

0x01 介绍

ThinkPHP是一个快速、兼容而且简单的轻量级国产PHP开发框架,诞生于2006年初,原名FCS,2007年元旦正式更名为ThinkPHP,遵循Apache2开源协议发布,从Struts结构移植过来并做了改进和完善,同时也借鉴了国外很多优秀的框架和模式,使用面向对象的开发结构和MVC模式,融合了Struts的思想和TagLib(标签库)、RoR的ORM映射和ActiveRecord模式。

0x02 漏洞说明

ThinkPHP在加载模版解析变量时存在变量覆盖的问题,导致可以覆盖模板文件的路径,从而实现任意文件加载。此漏洞与CodeIgniter框架内核设计缺陷可导致任意代码执行类似。漏洞存在于5.x以及3.x版本中,本文仅以5.x为例进行说明。

0x03 漏洞分析

先看这样一段代码:

这是官方文档中的一段示例代码,其中使用assign方法进行模板变量赋值,并调用fetch方法输出模板内容。

跟进\think\Controller:assign,代码如下:

可以看到将数据存入了成员变量data中,当传入数组时使用array_merge与data进行合并。

再看\think\Controller:fetch方法

调用了\think\View:fetch,代码如下

其中默认视图引擎为Think,在fetch方法调用了\think\view\driver\Think:fetch进行模板渲染

在最后调用了\think\Template:fetch来渲染模板

其中最关键的部分是$this->storage->read($cacheFile, $this->data); 此处读取编译好的模板并进行显示。Storage默认为File,代码在\think\template\driver\File:read

解析变量时使用EXTR_OVERWRITE,导致有可能覆盖掉cacheFile,从而实现任意文件包含。回顾前面的流程可以知道vars中的值由三部分组成:视图静态变量、\think\Controller:assign赋值的数据、\think\Controller:fetch或display赋值的数据。由于在assign或fetch/display中可以传入数组,且后续操作未对数组的键名进行改变,从而可以传递[‘cachFile’=>’filetoinclude’]类似形式的数据来进行变量覆盖。

0x04 漏洞测试

漏洞原理: fetch渲染模块里中存在EXTR_OVERWRITE ,可能变量覆盖。
触发条件:assign($arr)中数组键名可控,或assign($key, $value)中$key可控。

poc:            cacheFile=../README.md

使用composer安装thinkphp5最新源码,修改Index控制器内容,并创建相应的视图模板app/index/view/index/index.html内容随意。

在POST数据中提交cacheFile=../README.md,成功包含项目目录下的README.md文件。

当服务器开启allow_url_include时,可直接包含php://input执行任意代码。注意:php://input获取的是原始POST数据,不要对提交的代码进行urlencode,否则无法执行代码。

0x05 案例

由于官方框架未对此问题进行处理,且在文档中也并未提醒开发者传入模板的数据需要过滤。部分开发者使用assign方法不当,导致了漏洞的发生。此处以thinkcmf为例。

该项目在后台设置中多次出现了此问题,以其中一处进行说明。代码在\app\admin\controller\SettingController

在upload中使用cmf_get_upload_setting读取上传配置进行显示,在uploadPost中获取POST数据通过cmf_set_option进行保存。

先看cmf_set_option的代码

从数据库中读取原有配置并json_decode,与现配置进行合并再json_encode后写回数据库。并在写入数据库后删除了相应的缓存。再看cmf_get_upload_setting

其中通过cmf_get_option读取数据库中的配置,不存在时则使用默认配置。再看cmf_get_option如何获取配置

首先会从缓存中读取,如果缓存中不存在则从数据库中读取,然后再写入缓存。回顾uploadPost的设置流程,可以传入自定义键名的数组,从而在upload中传入模板的数据其键名可控,从而可以实现变量覆盖。

登录后台,点击设置=》上传设置。点击保存,抓包后修改

再次点击上传设置,成功加载README.md

0x06 番外

作为开发者不应该盲目信任框架,对于不太了解的功能谨慎使用。而作为攻击者,传统的web后门极易被查杀,可以考虑利用应用程序的特性来制作后门。这样能够极大的增加后门被查杀的难度。


文章来源: https://mp.weixin.qq.com/s/IuKjTS0Q0VVzuoeSwqZ5Gw
如有侵权请联系:admin#unsafe.sh