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目录,意味着攻击者可以通过互联网访问。
一、漏洞复盘
首先看一下漏洞存在的位置。
点击“文件上传”,上传一个名为ma2.php,这是一个一句话木马。
可以查看文件的内容,可见这个文件的位置为/public/ma2.php
可推断,上传的一句话木马的URL为 http://[HOST]/wolfcms/public/ma2.php,利用一句话菜刀去连接
成功拿下网站。
二、漏洞分析
存在问题的文件位于/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));
}
三、防御方法
文件上传类漏洞的防御方法有很多,大方向上有三点:
1、将文件上传的目录设置成不可执行。
2、判断文件类型
3、使用随机数改写文件名和文件路径
2017年7月30日
wolf的新版本0.8.3.1中对上述漏洞做了修补,但是仍可被绕过,具体情况如下:
点击Upload file,此次漏洞利用的客户机需要是ubuntu,将webshell命名为“ma2.php.”
可以看到上传的文件名已经被web服务器(windows)将其最后的“.“去掉,成为了一个合法的php文件
可以看到该webshell的代码
利用一句话木马客户端,连接这个木马,可浏览目标服务器的目录。
看看代码,这一版是如何修补了上一版的文件上传漏洞。
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文件可以正常执行。