某CMS 20180827版本 前台getshell

栏目: 编程工具 · 发布时间: 5年前

内容简介:2018年9月21日,Destoon官方发布安全更新,修复了由用户“索马里的海贼”反馈的一个漏洞。根据更新消息可知漏洞发生在头像上传处。Destoon中处理头像上传的是 module/member/avatar.inc.php 文件。在会员中心处上传头像时抓包,部分内容如下:

前言

2018年9月21日,Destoon官方发布安全更新,修复了由用户“索马里的海贼”反馈的一个漏洞。

某CMS 20180827版本 前台getshell

漏洞分析

根据更新消息可知漏洞发生在头像上传处。Destoon中处理头像上传的是 module/member/avatar.inc.php 文件。在会员中心处上传头像时抓包,部分内容如下:

某CMS 20180827版本 前台getshell

对应着avatar.inc.php代码如下:

<?php 
defined('IN_DESTOON') or exit('Access Denied');
login();
require DT_ROOT.'/module/'.$module.'/common.inc.php';
require DT_ROOT.'/include/post.func.php';
$avatar = useravatar($_userid, 'large', 0, 2);
switch($action) {
    case 'upload':
        if(!$_FILES['file']['size']) {
            if($DT_PC) dheader('?action=html&reload='.$DT_TIME);
            exit('{"error":1,"message":"Error FILE"}');
        }
        require DT_ROOT.'/include/upload.class.php';

        $ext = file_ext($_FILES['file']['name']);
        $name = 'avatar'.$_userid.'.'.$ext;
        $file = DT_ROOT.'/file/temp/'.$name;

        if(is_file($file)) file_del($file);
        $upload = new upload($_FILES, 'file/temp/', $name, 'jpg|jpeg|gif|png');

        $upload->adduserid = false;

        if($upload->save()) {
            ...
        } else {
            ...
        }
    break;

这里通过 $_FILES['file'] 依次获取了上传文件扩展名 $ext 、保存临时文件名 $name 、保存临时文件完整路径 $file 变量。之后通过 new upload(); 创立一个upload对象,等到 $upload->save() 时再将文件真正写入。

upload 对象构造函数如下,include/upload.class.php:25:

<?php
class upload {
    function __construct($_file, $savepath, $savename = '', $fileformat = '') {
        global $DT, $_userid;
        foreach($_file as $file) {
            $this->file = $file['tmp_name'];
            $this->file_name = $file['name'];
            $this->file_size = $file['size'];
            $this->file_type = $file['type'];
            $this->file_error = $file['error'];

        }
        $this->userid = $_userid;
        $this->ext = file_ext($this->file_name);
        $this->fileformat = $fileformat ? $fileformat : $DT['uploadtype'];
        $this->maxsize = $DT['uploadsize'] ? $DT['uploadsize']*1024 : 2048*1024;
        $this->savepath = $savepath;
        $this->savename = $savename;
    }
}

这里通过 foreach($_file as $file) 来遍历初始化各项参数。而 savepathsavename 则是通过 __construct($_file, $savepath, $savename = '', $fileformat = '') 直接传入参数指定。

因此考虑上传了两个文件,第一个文件名是 1.php ,第二个文件是 1.jpg ,只要构造合理的表单上传(参考: https://www.cnblogs.com/DeanChopper/p/4673577.html),则在avatar.inc.php中

$ext = file_ext($_FILES['file']['name']); // `$ext`即为`php` 
$name = 'avatar'.$_userid.'.'.$ext; // $name 为 'avatar'.$_userid.'.'php'
$file = DT_ROOT.'/file/temp/'.$name; // $file 即为 xx/xx/xx/xx.php

而在 upload 类中,由于多个文件上传, $this->file$this->file_name$this->file_type 将foreach在第二次循环中被置为jpg文件。测试如下:

某CMS 20180827版本 前台getshell

回到 avatar.inc.php ,当进行文件保存时调用 $upload->save() ,include/upload.class.php:50:

<?php
class upload {
    function save() {
        include load('include.lang');
        if($this->file_error) return $this->_('Error(21)'.$L['upload_failed'].' ('.$L['upload_error_'.$this->file_error].')');

        if($this->maxsize > 0 && $this->file_size > $this->maxsize) return $this->_('Error(22)'.$L['upload_size_limit'].' ('.intval($this->maxsize/1024).'Kb)');

        if(!$this->is_allow()) return $this->_('Error(23)'.$L['upload_not_allow']);

        $this->set_savepath($this->savepath);
        $this->set_savename($this->savename);

        if(!is_writable(DT_ROOT.'/'.$this->savepath)) return $this->_('Error(24)'.$L['upload_unwritable']);
        if(!is_uploaded_file($this->file)) return $this->_('Error(25)'.$L['upload_failed']);
        if(!move_uploaded_file($this->file, DT_ROOT.'/'.$this->saveto)) return $this->_('Error(26)'.$L['upload_failed']);

        $this->image = $this->is_image();
        if(DT_CHMOD) @chmod(DT_ROOT.'/'.$this->saveto, DT_CHMOD);
        return true;
    }
}

先经过几个基本参数的检查,然后调用 $this->is_allow() 来进行安全检查 include/upload.class.php:72:

<?php
    function is_allow() {
        if(!$this->fileformat) return false;
        if(!preg_match("/^(".$this->fileformat.")$/i", $this->ext)) return false;
        if(preg_match("/^(php|phtml|php3|php4|jsp|exe|dll|cer|shtml|shtm|asp|asa|aspx|asax|ashx|cgi|fcgi|pl)$/i", $this->ext)) return false;
        return true;
    }

可以看到这里仅仅对 $this->ext 进行了检查,如前此时 $this->extjpg ,检查通过。

接着会进行真正的保存。通过 $this->set_savepath($this->savepath); $this->set_savename($this->savename); 设置了 $this->saveto ,然后通过 move_uploaded_file($this->file, DT_ROOT.'/'.$this->saveto)file 保存到 $this->saveto ,注意此时的 savepathsavenamesaveto 均以 php 为后缀,而 $this->file 实际指的是第二个jpg文件。

漏洞利用

综上,上传两个文件,其中第一个文件以php为结尾如 1.php ,用于设置后缀名为 php ;第二个文件为 1.jpg ,jpg用于绕过检测,其内容为php一句话木马(图片马)。

某CMS 20180827版本 前台getshell

然后访问 http://127.0.0.1/file/temp/avatar1.php 即可。其中 1 是自己的 _userid

不过实际利用上会有一定的限制。

第一点是destoon使用了伪静态规则,限制了file目录下php文件的执行。

某CMS 20180827版本 前台getshell

第二点是avatar.inc.php中在 $upload->save() 后,会再次对文件进行检查,然后重命名为 xx.jpg

省略...
$img = array();
$img[1] = $dir.'.jpg';
$img[2] = $dir.'x48.jpg';
$img[3] = $dir.'x20.jpg';
$md5 = md5($_username);
$dir = DT_ROOT.'/file/avatar/'.substr($md5, 0, 2).'/'.substr($md5, 2, 2).'/_'.$_username;
$img[4] = $dir.'.jpg';
$img[5] = $dir.'x48.jpg';
$img[6] = $dir.'x20.jpg';
file_copy($file, $img[1]);
file_copy($file, $img[4]);
省略...

因此要利用成功就需要条件竞争了。

补丁分析

某CMS 20180827版本 前台getshell

在upload的一开始,就进行一次后缀名的检查。其中is_image如下:

function is_image($file) {
    return preg_match("/^(jpg|jpeg|gif|png|bmp)$/i", file_ext($file));
}

某CMS 20180827版本 前台getshell

__construct() 的foreach中使用了break,获取了第一个文件后就跳出循环。

is_allow() 中增加对 $this->savename 的二次检查。

最后

嘛,祝各位大师傅中秋快乐!


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Head First JavaScript程序设计

Head First JavaScript程序设计

[美]Eric T. Freeman、[美] Elisabeth Robson / 袁国忠 / 人民邮电出版社 / 2017-9 / 129.00 元

本书语言和版式活泼,内容讲解深入浅出,是难得的JavaScript入门书。本书内容涵盖JavaScript的基本知识以及对象、函数和浏览器文档对象模型等高阶主题。书中配备了大量有趣的实例、图示和练习,让读者轻轻松松掌握JavaScript。一起来看看 《Head First JavaScript程序设计》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

JS 压缩/解压工具
JS 压缩/解压工具

在线压缩/解压 JS 代码

图片转BASE64编码
图片转BASE64编码

在线图片转Base64编码工具