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