首页 » 安全观察 » 正文

【安全研究】OpenSNS部分漏洞梳理与探究

声明!

本文仅供学习和研究,由于传播、利用此文所提供的信息而造成的任何直接或者间接的后果及损失,均由使用者本人负责,海青实验室及文章作者不承担任何责任。

安全狗海青实验室拥有此文章的修改和解释权,如欲转载或传播,必须保证此文的完整性,包括版权声明在内的全部内容,未经海青实验室同意,不得任意修改或者增减此文章内容,不得以任何方式将其用于商业目的。

我们已将漏洞相关情况汇报了CNVD,目前若干漏洞已被收录

同时,我们也已将相关情况通知了厂商,目前漏洞已修复,厂商向我们发来了感谢信

通常来说,ThinkPHP框架在底层实现上已经具备了一定程度的防御能力,只要严格按照ThinkPHP的开发规范,可以大大减小漏洞产生的可能性,但在实际开发过程中,研发人员往往贪图便利,不严格遵循规范,导致产生了很多漏洞。

近期,海青实验室对OpenSNS进行了一次简单的代码审计,这是一款基于ThinkPHP框架开发的综合性社交软件,其中不少漏洞正是开发过程中不严格遵循相关规范的结果,因此我们梳理成文,供读者参考,如有错误,也请各位指正。

如下图代码,当获取到变量$pid的值之后,便直接以拼接的方式构造了查询语句的where条件。

在开发手册中,ThinkPHP定义好了Where条件的构造方法,也推荐使用数组的方式进行构造。严格的按照开发手册进行开发,在框架底层不存在问题的前提下,自然而然可以避免SQL注入的产生。

如下代码,仍然以简单粗暴的方式构造Where条件。

而这个变量$id值是如何来的呢?如果在一般程序之中,可能需要回溯,看看是谁调用了sortField函数,并且传入的$id值是否有经过处理。而在ThinkPHP框架之中,定义在控制器里的函数方法,它们的参数列表是可控的,直接传参即可!ThinkPHP路由分发中参数绑定的操作如下图:

上图110行处的会得到一个$vars数组,里面存放的是传入的参数值,这里的参数值会来到bindParams函数之中进行参数绑定。循环遍历$params的数组,而这个数组的来源于$reflect->getParameters()也就是操作的参数列表,这样即便传参的顺序是乱的也没关系,因为会按照参数列表的顺序,匹配vars数组里的值,最后返回一个args数组进行最后反射执行的参数。

http://127.0.0.1/tp51/public/index.php/Index/index/hello?zhhhy=111

如上,想要利用该漏洞,只需构造如下访问即可

http://127.0.0.1/opensns/index.php?s=/admin/user/sortField&id=-1%20or%20if(1,sleep(1),0))%20%23

如下,很明显$aTheme是可控的,并且没有过滤跳转符。在84行处就拼接路径构造压缩包。

审计时,经常会遇到一些没见过的函数和类库,可以简单查阅一些相关材料,比如此处的PclZip压缩文件类,之前并没遇见过,因此百度之。查阅到文档

根据说明,第一个参数是需要被打包的文件路径,而后面的参数只是为了目录结构,并不影响打包哪个文件。因此,此处显然可以打包整站的文件

http://127.0.0.1/opensns/?s=admin/theme/packageDownload&theme=../../opensns

效果如下:触发下载

可以看到整个网站的源码都被下载了下来。

关于文件解压引发的getshell这个问题,海青实验室之前的一篇文章就已经介绍了两个由于文件解压的例子。根据审计的思路,可以搜索到解压功能的代码,如下:

参照PclZip压缩文件类的说明文档,可以得知206行进行解压操作,并且将文件夹解压到指定的$ExpressionPkg目录下,在解压完成后,会删除该压缩包。并没有对加压出来的文件进行检查,因此压缩包里可以包含PHP文件。在ThinkPHP框架之中,控制器里的方法如果是Public,那么即可通过路由的方式直接访问。但此处不行,因为是Private,显然是该类的内部方法,需要寻找是谁调用了它。

如上代码,只要$flag=1时就会将上传的文件进行保存,上传成功后,则进一步的进行解压。那么利用就简单了,如下所示

来到如下页面进行文件上传。

http://127.0.0.1/opensns/index.php?s=/admin/Expression/add.html

准备一个具有恶意代码的压缩包

将文件上传。此时,由于上传文件的MIME类型不正确而会失败,不太理解为什么这边会失败,抓包发现Content-Type的字段确实和代码中定义允许的类型不一样。

通过Burpsuite抓包修改Content-Type为application/zip 即可成功。

当成功上传后,就可以访问

http://127.0.0.1/opensns/uploads/Expression/exp.php

这个问题,海青实验室之前的一篇文章就已经介绍了两个由于文件解压的例子。在OpenSNS这套开源系统中,仍然存在此类问题,由此可见,该问题在一些WEB应用之中还是蛮常见的。

这个漏洞的最终成因和前段时间爆出来的ThinkCMF任意文件包含的成因是相同的,只不过触发点不一样。

OpenSNS在使用assign传递参数以便渲染模板的时候,第一个参数给了一个变量,而这个变量是可控的。而后可以发现当传入的是keyword[_filename]=1.txt时,经过assign解析会得到_filename=1.txt的结果,这个值会存在$vars数组。而后进入display函数之中,一路跟进到load函数下,78行处会将$vars数组的值注册为变量,以至于将原有的$_filename变量进行覆盖,从而导致可以包含任意文件。执行效果如下:

由于这个洞并不是我挖掘到的,所以不做更多的细节分析。更多细节请看http://llfam.cn/2019/10/19/%E4%BB%8Ebytectf%E5%86%8D%E8%B0%88tp/。

从上述的几个漏洞来看,审计基于TP框架开发的WEB应用其实核心部分就是在Controller控制器之中的代码。首先是要理解TP框架路由分发调度的机制,这样在定位漏洞和复现漏洞的时候会更加得心应手。既然基于框架开发,如果没有严格按照框架的开发手册进行开发工作,可能就会因为一些疏忽导致漏洞的产生。例如,使用不正确的方式构造Where语句导致的SQL注入。再看文件相关的操作,个人认为路径穿越在文件相关漏洞的产生之中有着至关重要的作用,如果不能穿越路,径仅限于当前文件夹,,那么就无法将危害扩大。对文件后缀检测依然是防止恶意代码和文件注入的有效手段,同时也需要提防解压功能这种夹带Webshell的情况。

发表评论