[漏洞分析] Wolf CMS 的漏洞

2016年5月10日

此漏洞的编号为:EDB-ID:36818    OSVDB-ID:120877

软件的官网为:https://www.wolfcms.org/

Wolf CMS是一种内容管理系统,并且免费。其由PHP编码语言写成。

Wolf CMS 0.8.2以及之前版本中存在文件上传漏洞。攻击者可以滥用上传特性来上传恶意的PHP文件到程序中,最终导致任意远程代码执行。
漏洞具体存在于File Manager函数中,这个函数是一个接口,便于管理文件。
在本例中,对于允许上传的文件类型是没有限制的。因此,攻击者可以上传PHP的shell文件,内含恶意代码,来完全控制受害者的服务器。
上传的文件还可以被转移到root目录,意味着攻击者可以通过互联网访问。


一、漏洞复盘

首先看一下漏洞存在的位置。

[漏洞分析] Wolf CMS 的漏洞_第1张图片

点击“文件上传”,上传一个名为ma2.php,这是一个一句话木马。

[漏洞分析] Wolf CMS 的漏洞_第2张图片

可以查看文件的内容,可见这个文件的位置为/public/ma2.php

[漏洞分析] Wolf CMS 的漏洞_第3张图片

可推断,上传的一句话木马的URL为 http://[HOST]/wolfcms/public/ma2.php,利用一句话菜刀去连接

[漏洞分析] Wolf CMS 的漏洞_第4张图片

成功拿下网站。


二、漏洞分析

存在问题的文件位于/wolf/plugins/file_manager/FileManagerController.php中第328至337行

    public function upload() {
        if (!AuthUser::hasPermission('file_manager_upload')) {
            Flash::set('error', __('You do not have sufficient permissions to upload a file.'));
            redirect(get_url('plugin/file_manager/browse/'));
        }
        
        // CSRF checks
        if (isset($_POST['csrf_token'])) {
            $csrf_token = $_POST['csrf_token'];
            if (!SecureToken::validateToken($csrf_token, BASE_URL.'plugin/file_manager/upload')) {
                Flash::set('error', __('Invalid CSRF token found!'));
                redirect(get_url('plugin/file_manager/browse/'));
            }
        }
        else {
            Flash::set('error', __('No CSRF token found!'));
            redirect(get_url('plugin/file_manager/browse/'));
        }
        
        $mask = Plugin::getSetting('umask', 'file_manager');
        umask(octdec($mask));

        $data = $_POST['upload'];
        $path = str_replace('..', '', $data['path']);
        $overwrite = isset($data['overwrite']) ? true : false;

        // Clean filenames
        $filename = preg_replace('/ /', '_', $_FILES['upload_file']['name']);
        $filename = preg_replace('/[^a-z0-9_\-\.]/i', '', $filename);

        if (isset($_FILES)) {
            $file = $this->_upload_file($filename, FILES_DIR . '/' . $path . '/', $_FILES['upload_file']['tmp_name'], $overwrite);

            if ($file === false)
                Flash::set('error', __('File has not been uploaded!'));
        }
        redirect(get_url('plugin/file_manager/browse/' . $path));
    }

从代码中可见,对于上传的文件,代码只做了两件事情,首先,对文件名中的空格换成下划线,并且只保留文件名中的小写字母,数字,下划线,小横线以及点号,剩下的字符一律删除。在本例中上传的一句话木马名为ma2.php,不会受到任何影响,因此成功上传。


三、防御方法

文件上传类漏洞的防御方法有很多,大方向上有三点:

1、将文件上传的目录设置成不可执行。

2、判断文件类型

3、使用随机数改写文件名和文件路径


2017年7月30日

wolf的新版本0.8.3.1中对上述漏洞做了修补,但是仍可被绕过,具体情况如下:

[漏洞分析] Wolf CMS 的漏洞_第5张图片

点击Upload file,此次漏洞利用的客户机需要是ubuntu,将webshell命名为“ma2.php.”

[漏洞分析] Wolf CMS 的漏洞_第6张图片

可以看到上传的文件名已经被web服务器(windows)将其最后的“.“去掉,成为了一个合法的php文件

[漏洞分析] Wolf CMS 的漏洞_第7张图片

可以看到该webshell的代码

[漏洞分析] Wolf CMS 的漏洞_第8张图片

利用一句话木马客户端,连接这个木马,可浏览目标服务器的目录。

[漏洞分析] Wolf CMS 的漏洞_第9张图片

看看代码,这一版是如何修补了上一版的文件上传漏洞。

    public function upload() {
        if (!AuthUser::hasPermission('file_manager_upload')) {
            Flash::set('error', __('You do not have sufficient permissions to upload a file.'));
            redirect(get_url('plugin/file_manager/browse/'));
        }

        // CSRF checks
        if (isset($_POST['csrf_token'])) {
            $csrf_token = $_POST['csrf_token'];
            if (!SecureToken::validateToken($csrf_token, BASE_URL.'plugin/file_manager/upload')) {
                Flash::set('error', __('Invalid CSRF token found!'));
                redirect(get_url('plugin/file_manager/browse/'));
            }
        }
        else {
            Flash::set('error', __('No CSRF token found!'));
            redirect(get_url('plugin/file_manager/browse/'));
        }

        $mask = Plugin::getSetting('umask', 'file_manager');
        umask(octdec($mask));

        $data = $_POST['upload'];
        $path = str_replace('..', '', $data['path']);
        $overwrite = isset($data['overwrite']) ? true : false;

        // Clean filenames
        $filename = preg_replace('/ /', '_', $_FILES['upload_file']['name']);
        $filename = preg_replace('/[^a-z0-9_\-\.]/i', '', $filename);

        $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
        $ext_arr = array('php', 'php3', 'php4', 'inc');
        if (in_array($ext, $ext_arr)) {
            Flash::set('error', __('Not allowed to upload files with extension :ext', $ext));
            redirect(get_url('plugin/file_manager/browse/'));
        }

        if (isset($_FILES)) {
            $file = $this->_upload_file($filename, FILES_DIR . '/' . $path . '/', $_FILES['upload_file']['tmp_name'], $overwrite);

            if ($file === false)
                Flash::set('error', __('File has not been uploaded!'));
        }
        redirect(get_url('plugin/file_manager/browse/' . $path));
    }
首先将后缀名的字母均变成小写,随后定义了一个数组,作为后缀名的黑名单,也就是说,只要用户上传的文件后缀名命中了黑名单中列出来的内容,就会终止上传操作,打印错误信息,并将用户重定向到plugin/file_manager/browse/目录下。

利用黑名单的方法修补文件上传漏洞是不可行的,在这份代码中很好的体现。

如果攻击者利用ubuntu系统,他就可以将文件定义为x.php. 此后缀名没有出现在编码者定义的黑名单中,可以成功上传,上传这个文件到以windows系统为基础的服务器上之后,文件名最后的那个点号会被自动删除,php文件可以正常执行。


你可能感兴趣的:(漏洞分析)