某CMS 20180827版本 前台getshell

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

内容简介: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 的二次检查。

最后

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


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

查看所有标签

猜你喜欢:

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

Practical JavaScript, DOM Scripting and Ajax Projects

Practical JavaScript, DOM Scripting and Ajax Projects

Frank Zammetti / Apress / April 16, 2007 / $44.99

http://www.amazon.com/exec/obidos/tg/detail/-/1590598164/ Book Description Practical JavaScript, DOM, and Ajax Projects is ideal for web developers already experienced in JavaScript who want to ......一起来看看 《Practical JavaScript, DOM Scripting and Ajax Projects》 这本书的介绍吧!

JSON 在线解析
JSON 在线解析

在线 JSON 格式化工具

URL 编码/解码
URL 编码/解码

URL 编码/解码

Markdown 在线编辑器
Markdown 在线编辑器

Markdown 在线编辑器