ThinkCMF 任意文件包含漏洞分析

本文作者: Z1NG 􏰅􏰆􏰇􏰈􏰉(信安之路 2019 年度优秀作者)

找了个空闲的时间想着动手调试新爆出的 ThinkCMF 漏洞。作为代码审计入门不久的我,惯性思维的就去网上找了些分析文章参考,想要节省一些时间。然鹅。。网上的文章大多都抄来抄去,大致画风如下:

根据 POC 盲猜。。。的确有时是根据 POC 能够定位到漏洞文件和触发函数。可是这我死活想不明白,如何会定位到 Portal 应用中的控制器。。。大概大佬们都是一眼望穿漏洞成因的吧。。。

路由定位

在审计一个开源项目的时候,尤其是框架,通常要先把路由分发调度情况搞清楚,才能更好的跟进程序流程,以及 POC 的构造。就拿这个例子进行练练手,调试这个真的花了很长很长时间,说到底还是自己太菜了。

首先,先看 POC

http://127.0.0.1/tpCMF/?a=display&templateFile=README.md

看了 POC,由于对 ThinkCMF 整体的架构不熟悉,死活不知道断点下在哪合适。根据手册,发现了 Portal 的由来。

原来是存在 Portal 这样一个举例应用,但这并不能说明 POC 就一定访问的是 Portal 应用呀?(好像有点钻牛角尖)

为了定位到漏洞点,我将断点下到了入口文件,进行漫长的调试,寻找路由分发部分的代码。在许久之后总算找到路由分发的代码了,于是继续跟进代码调试。目的是找寻为什么是访问 Portal 这个应用,以及参数 a 是什么作用。

跟进代码之后,很快就能发现字符 'a' 被赋值给一个变量 $varAction。

继续往下跟进,在 240 行处,调用了 getAction 这个静态方法,显然是为了获取一些值。

可以看出,action 的值就是用参数 a 传入的!也就是说通过 a 传入的是要被执行的方法。

代码继续跟,看看为什么是 Portal 应用。在此处是传入的是 'DEFAULT_MODULE' 大概意思就是获取默认模块。

可以在 config 变量中看到,这个值是 Poral

可以分析出,默认是访问 Portal 应用,由于使用的是 MVC 架构,自然而然的可以想到是访问 Portal 里 Index 控制器。如下图所示

接着程序会使用反射机制,动态执行 display 方法。在 152 行处,会获得方法的一系列参数,如下图所示。

至此,程序流程从开始到漏洞点的路由分析已经结束,搞明白了参数 a 的作用和为什么是访问 Portal 应用。接下来就是漏洞点的分析了。

漏洞分析

经过漫长的调试,总算是明白了为什么是 Portal 应用,为什么是 a 参数。接下来,就要看看为什么会产生漏洞

将断点下在 IndexController

继续调试,跟进代码会来到 HomebaseController 的 display 方法。

此处可以不断跟进,看左下角的调用栈。。还是蛮深的!在 Template 类中的 fetch 方法是为了获取目标文件里的内容。跟进 LoadTemplate。

在此处,会生成一个缓存文件,目标文件内容会使用 Storage::put 写入到缓存文件里。

接着用 load 的函数将缓存文件进行包含。一路分析过来,可以发现传入的文件名并没有经过检查,因此可以包含任意文件。

效果如下:

最后

漏洞本身并不复杂,在路由这块花了很多时间调试。写的很潦草,虽然只是简简单单的几张图几句话,但都是一遍一遍调试下来的,真正调试的时间远比写出这边水文花的时间长,代码审计就是自己动手调试一遍才有意思。调试框架的代码真的让人晕到不行,尤其不熟悉的框架。同时,也通过这个例子,让自己体会到了审计之前分析路由的重要性。以上都是个人的一些不成熟的屁话,看看就好。

解决了审计小白的困惑:heart_eyes: