漏洞描述
- 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
文件 - 匹配用户上传文件名后缀的正则表达式末尾不应该加上
$