这个漏洞,我劝你耗子尾汁

  • A+
所属分类:安全文章

这是 酒仙桥六号部队 的第 127 篇文章。

全文共计3620个字,预计阅读时长11分钟


前言

最近在某论坛上看到一篇分析74cms存在模板解析漏洞的文章,74cms使用了tp3的框架,然后自己对tp框架的模板解析渲染也不是很熟,就想着学习一下这个漏洞,顺便熟悉一下tp3的模板解析。说干就干,先挑一个软一点的74cms捏一下,cms版本:v6.0.20。


漏洞分析

对一个已知漏洞进行分析比较喜欢采用溯源的方式进行,首先已知漏洞点的位置:/Application/Common/Controller/BaseController.class.php,触发方法:assign_resume_tpl。

这个漏洞,我劝你耗子尾汁

在第175行调用了fetch方法,而在tp3框架内,所有的控制器都是继承自父类:/ThinkPHP/Library/Think/Controller.class.php,所以我们直接跟进到父类当中,来查看这个fetch方法到底发生了什么。这里要注意一下,传递的变量$tpl是要被解析的模板路径。

来到父类当中,可以看到这个fetch方法是来自于构造方法中实例化的view对象。

这个漏洞,我劝你耗子尾汁

这个漏洞,我劝你耗子尾汁

view视图类的位置在:/ThinkPHP/Library/Think/View.class.php。所以还是继续跟进到视图类当中,这里还是要注意参数的传递,在第84行中可以看到,调用fetch函数时传递三个参数,参数$templateFile是之前传递的被解析模板的路径,$content和$prefix两个参数都为空。接着来看视图类当中的fetch函数,先上代码。

这个漏洞,我劝你耗子尾汁

首先判断$content参数是否为空,根据上面的传参,$content变量为空,然后调用parseTemplate函数,传递$templateFile,跟进一下这个函数。

这个漏洞,我劝你耗子尾汁

可以看到使用is_file函数判断传递的模板是否是个文件,如果是的话直接返回,这里不管是图片文件,TXT文件等等,is_file函数都返回true,所以此处直接就返回到调用点了。接下来再看第117行,此处有一个判断,通过C方法获取模板引擎类型,看是否是使用原生的PHP模板,这个配置文件位于:/ThinkPHP/Conf/convention.php,tp3的默认配置是“Think”。

这个漏洞,我劝你耗子尾汁

所以经过判断之后会直接进入到视图解析标签模块,也就是第125,126行。其中125行是将参数组合成一个数组,其中$this-tVar是存储模板中的变量,$temlateFile存储的还是被解析模板的路径,$content和$prefix依旧为空。配置debug之后,可以清楚的看到参数的传递情况。

这个漏洞,我劝你耗子尾汁

之后进入这个HOOK::listen方法,方法位置:/ThinlPHP/Library/Think/Hook.class.php。

这个漏洞,我劝你耗子尾汁

这个HOOK类是一个行为扩展,在TP3中称之为钩子,当我们传递了一个“view_parse“参数之后,实际就是触发了一个”view_parse“事件,此时TP3会进入到Hook::listen方法,查找$tags变量中有没有绑定”view_parse”的方法,然后遍历$tags的属性,执行Hook::exec方法。这里我们通过debug看一下整个Hook::listen的执行过程以及中间参数的变化。

这个漏洞,我劝你耗子尾汁

在上面的参数传递过程中可以看到view_parse事件绑定了ParseTemplateBehavior的行为方法。在执行Hook::exec方法时,$name传递绑定的行为方法,$params传递的是一个引用。之后就进入到exec方法之中。

这个漏洞,我劝你耗子尾汁

在exec方法之中规定所有行为扩展的入口是run方法,根据上一步的参数传递,在118行中实例化ParseTemplateBehavior行为对象,然后调用该对象的run方法,并将引用的$param参数传递进去。该类的路径:/ThinkPHP/Library/Behavior/ParseTemplateBehavior.class.php。

因为所有行为扩展的入口都是run方法,所有我们直接看run方法就可以了。

这个漏洞,我劝你耗子尾汁

在上面的分析中我们知道模板引擎是“Think“,所以程序会进入到25至29行,又因为新解析一个模板是没有缓存对象的,所以此处直接进入第31行,这里传递的参数需要注意,在第22行中,$data[‘content’]为空,所以此时$content变量的值是$_data[‘file’],即解析模板的路径。然后进入模板编译与加载的fetch方法。该方法路径:/ThinkPHP/Library/Think/Template.class.php。

接下来看到Template类,首先看到fetch函数。

这个漏洞,我劝你耗子尾汁

此处$templateFile变量还是待解析模板的路径,然后在第76行调用loadTemplate方法,再继续跟进该函数。在loadTemplate方法中主要关注以下几个地方:在第92行读取模板文件的内容,赋值给变量$tmpContent。

这个漏洞,我劝你耗子尾汁

在第113行通过compiler方法对模板内容进行编译,最后第114行将编译后的结果进行存储,并且返回编译后模版文件的路径。

这个漏洞,我劝你耗子尾汁

此处还要继续跟进compiler方法,查看模板的编译过程。

这个漏洞,我劝你耗子尾汁

在编译过程中第130行会将没有经过任何过滤的模板内容拼接进入模板代码当中,然后将模板内容直接返回。此处通过debug可以直观的看到返回值得内容。

这个漏洞,我劝你耗子尾汁

返回结果之后再回到上面的loadTemplate方法,第114行将结果进行存储,生成模板文件,然后将文件的路径返回给fetch方法。

这个漏洞,我劝你耗子尾汁

在fetch方法获取到路径之后,第77行调用load方法加载模板,漏洞产生的原因就在此处。Load方法的路径:/ThinkPHP/Library/Think/Storage/Driver/File.class.php

这个漏洞,我劝你耗子尾汁

第80行代码是为了调试自己加的,在进入load方法之后首先判断变量是否为空,然后对变量进行extract的解析,此处其实会出现另外一个问题,变量覆盖,如果刚好能够覆盖$_filename变量,那么又是一个漏洞。不过此处没有这么复杂,不需要进行变量覆盖,因为恶意代码以及被写入缓存的模板文件中,而第81行直接通过include对模板文件进行包含,这就造成了漏洞。接着看一下缓存的模板里面的内容:

这个漏洞,我劝你耗子尾汁

然后此处第一行会校验我们是否是从入口访问到的模板,避免我们直接访问模板,这里没有什么影响。只要include能成功执行到第二行,我们的恶意代码就会执行,创建一个sites.txt文件,内容为Runoob。

到上面这一步这个漏洞的利用过程已经分析完毕了,可以使用一张流程图来看一下整个过程。

这个漏洞,我劝你耗子尾汁


原生框架测试

通过上面的梳理,我们可以看到其实整个漏洞触发的过程都是在TP3框架内部进行的,是因为在进行模板解析之前没有控制传入的模板路径,解析过程中没有过滤模板内的文件内容,解析完成之后直接通过include方式将模板文件进行了包含。那么如果我们跳出74cms,直接看TP3框架,理论上也是会存在这个漏洞的。所以接下来下载原生的TP3框架,自己写一个触发漏洞的方法。将Home模块的Index控制器修改,代码如下:

这个漏洞,我劝你耗子尾汁

触发控制器的请求:index.php?m=home&c=index&a=index&variable=1&tpl=./1.txt,其中1.txt是要被解析的带有恶意代码的模板文件,内容如下:

这个漏洞,我劝你耗子尾汁

如果代码被执行就会在根目录下写入一个sites.txt文件,内容是Runoob。之后在前台触发以下漏洞,看是否会生成该文件。执行后的情况:

这个漏洞,我劝你耗子尾汁

成功生成sites.txt文件。

这个漏洞,我劝你耗子尾汁

查看一下缓存的模板文件的内容。

这个漏洞,我劝你耗子尾汁

可以看到在使用了原生的TP3模板之后,也是能成功触发漏洞的。而且经过调试,整个漏洞触发的过程与之前分析的一致,也就不在赘述了。那么我们也可以得到结论,这个漏洞其实是TP3框架本身的问题,不是特定发生在某些cms上的,如果有程序使用了TP3的框架,而且使用了基本控制器中的fetch方法,且模板的路径可以由用户定义就有可能触发这个漏洞,这样的话漏洞的影响范围就变得更加广泛了。


小小的总结

在这一次审计的过程当中,熟悉了TP3框架对模板的解析过程,受益匪浅。这个漏洞产生的根本原因还是过滤不严格造成了任意文件包含漏洞,属于框架本身的漏洞。在调试过程中还走进了一个误区,最开始使用phpinfo()作为恶意模板的内容,但是多次尝试都没有看到有结果输入,这不是因为phpinfo没有执行,而是因为模板定义存在问题,所以不会产生回显,其实phpinfo本身在被包含时就已经执行了,所以之后将payload换成了写入一个新的文件,这样即使不能回显也可以看到恶意代码是否执行。还有一点困难就是调试过程中函数的跳转,参数的传递次数过多,如果不仔细调试容易跟丢执行流程。不管如何,这一次的调试还是有着巨大的收获。


这个漏洞,我劝你耗子尾汁

这个漏洞,我劝你耗子尾汁

本文始发于微信公众号(酒仙桥六号部队):这个漏洞,我劝你耗子尾汁

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: