漏洞描述
- BigTree-CMS
- BigTree是一个基于PHP和MySQL的可扩展的开放源码CMS。它是由Fastspot的专业设计师、战略家和开发人员创建的,可以帮助您创建和维护更好的网站
- 漏洞概况
- site/index.php/admin/trees/add/ in BigTree 4.2.22 and earlier allows remote attackers to upload and execute arbitrary PHP code because the BigTreeStorage class in core/inc/bigtree/apis/storage.php does not prevent uploads of .htaccess files.
环境搭建
- BigTree-CMS 4.2.22
- php7.2 + ubuntu18.04 + mysql 5.7 + apache2
这里需要特别注意一下的是,搭建环境的时候我们先建立一个Example Site,不然的话我们是找不到漏洞的入口的

漏洞利用
漏洞的入口url在http://your-ip/bigtree/site/index.php/admin/trees/add

点击Browse按钮,这个本来是用来上传照片用的

先上传一个文件,注意文件名要避开$DisabledExtensionRegEx 正则表达式,这里上传一个名为haozhe.的文件
1 | // haozhe. |

然后再上传.htaccess文件
1 | // .htaccess |

上传的文件会保存再web项目目录的site/files/resources文件夹下

漏洞分析
我们先看之前上传文件的时候的抓到的数据包

我们发现POST的请求路径是bigtree/site/index.php/admin/ajax/file-browser/upload,所以可以猜测漏洞的触发点在admin/ajax/file-browser/upload文件中。
可以看到在第17行,实例化了一个BigTreeStorage类。接着检查POST请求中是否存在$_POST["replace"]参数,如果不存在则置$replacing = false,表示并不是要替换一个已经存在的文件。

然后在第45行,如果$error的值不为0,就可以进入第59行的if ($replacing || !$admin->matchResourceMD5($temp_name, $_POST["folder"]))判断语句,

虽然replacing = false,但是!$admin->matchResourceMD5($temp_name, $_POST["folder"])的返回值是true,所以可以继续执行

因为$replacing = false,所以接下来调用$storage的$store()方法。

我们跟进这个方法,这个方法在core/inc/bigtree/apis/storage.php文件中。

在这里我们可以看到造成漏洞的关键点,在core/inc/bigtree/apis/storage.php中的store()方法中,也就是第217行中,调用preg_match()方法检查$file_name是不是和正则表达式匹配,如果匹配的话就调用unlink()函数来删除这个文件,并且返回false。如果在这里没有拦住恶意文件,那么接下来就可以说是畅通无阻了。
因为我们上传的是.htaccess文件,这个正则表达式匹配不到,所以不会进入这个if语句执行unlink(),我们继续跟下去

然后在第238行,因为$this->Cloud是false,这是在一开始就定义好的,所以进入else逻辑继续执行。

在第275行调用BigTree的moveFile方法,继续跟进moveFile(),这个方法在文件core/inc/bigtree/utils.php中。

moveFile()方法继续调用了copyFile()方法,所以继续跟进,在这个函数里,我们可以看到终于看到了编写OpenRASP插件支持的copy()函数。

最后梳理一下,整个调用过程就如下图所示:

官方修复

OpenRASP插件
我发现虽然在OpenRASP官方手册的注册类型页面中没有copy类型的,但是实际上是可以注册为copy的,所以我之前算是一直错误理解了……
官方手册中支持的Hook函数列表中有copy函数

之前我一直在注册类型页面寻找能不能找到一种类型,它里面的支持函数有copy,最后我直接尝试了注册类型为copy,打印params信息,结果竟然真的有返回。

它返回了三个信息:source、dest和stack,而且我们其实可以看到stack中就是上面分析的函数调用链。
对于这个补丁的插件,我们只要把它的正则表达式拿回来就可以了。
核心代码:

完整代码:
1 | const plugin_version = 'CVE-2018-10574' |
编写完插件后,要重新启动apache服务器
1 | $ sudo service apache2 restart |
上传.htaccess文件,拦截成功。

之前的漏洞
CVE-2017-7695
其实在BigTree-CMS 版本中,在这个补丁点就出现过漏洞

对于这个正则表达式
1 | var $DisabledExtensionRegEx = '/\\.(exe|com|bat|php|rb|py|cgi|pl|sh|asp|aspx)$/i'; |
我们只要在上传的文件名后面加上一个空格就可以轻松绕过了

官方给出的修复方案

CVE-2017-9364
在后来的BigTree-CMS 4.2.18 版本中,又出现了后缀名过滤不严的问题。

所以我们可以直接上传一个以.pht为后缀或者是.phtml为后缀的文件

访问http://your-ip/bigtree/site/files/resources/test.phtml

官方给出的修复就是在$DisabledExtensionRegEx中加入phtml和pht

漏洞的总结
- 这个点前后共有3个CVE,主要是因为对上传的文件名过滤不严,我们知道在用php编写上传功能时,需要注意:
- 过滤常见的文件名,比如:php、phtml、pht、asp、aspx等等
- 禁止用户上传
.htaccess文件 - 匹配用户上传文件名后缀的正则表达式末尾不应该加上
$