xiaocms文件上传GETSHELL
信息安全 代码审计    2017-01-05 11:42:10    132    0    0

漏洞描述

xiaocms后台文章发布存在缩略图上传. 该处并没有对文件类型进行校验. 导致可以上传任意文件, 直接getshell.

漏洞分析

通过xiaocms后台的文件上传URL可以得知URL是c=uploadfile&a=uploadify_upload&type=gif,jpg,jpeg,png

根据core/xiaocms.php中的parse_request()可以知道c参数是控制器,a参数是方法名, 可以定位到admin/contronller/uploadfile.php

而后根据a参数找到uploadify_upload方法定义的位置:

/** 
* uploadify_upload 
*/ 
public function uploadify_uploadAction() { 
     $type = $this->get('type'); 
     $size = (int)$this->get('size'); 
     if ($this->post('submit')) { 
     $data = $this->upload('file', explode(',', $type), $size); 
     if ($data['result']) echo $data['path']; 
     } 
} ​ 


可以看见实际的文件上传动作是由$this->upload完成的, 对$this->upload传入了三个参数, 一个字符串常量'file' , 一个$type参数从URL中获取的, 然后一个文件大小$size, 其中$type是我们可以控制的, 这里没有对$type做任何处理.

我们继续跟入$this->upload看看它的实现:

/** 
* 文件上传 
*/ 
private function upload($fields, $type, $size) { 
    $upload = xiaocms::load_class('upload'); 
    $ext = strtolower(substr(strrchr($_FILES[$fields]['name'], '.'), 1)); 
    if (in_array($ext, array('jpg','jpeg','bmp','png','gif'))) { 
        $dir = 'image'; 
    } else { 
        $dir = 'file'; 
    } 
    $path = $this->dir .$dir . '/' . date('Ym') . '/'; 
    if (!is_dir(XIAOCMS_PATH.$path)) mkdirs(XIAOCMS_PATH.$path); 
    $file = $_FILES[$fields]['name']; 
    $filename = md5(time() . $_FILES[$fields]['name']) . '.' . $ext; 
    $filenpath = $path.$filename; 
    $result = $upload->set_limit_size(1024*1024*$size)->set_limit_type($type)->upload($_FILES[$fields],XIAOCMS_PATH.$filenpath); 
    if (in_array($ext, array('jpg', 'gif', 'png', 'bmp'))) { 
        $this->watermark(XIAOCMS_PATH.$filenpath); 
    } 
    return array('result'=>$result, 'path'=> SITE_PATH . $filenpath, 'file'=>$file , 'ext'=>$dir=='image' ? 1 : $ext); 
}  ​ 


upload方法做了几个事情:

1. load_class 加载upload类

2. 从$_FILES中取出上传的文件名, 并且以.作为分隔符, 取出文件后缀.

3. 判断该上传文件是属于什么类型的. 图片类型,还是文件类型.

4. 然后建立上传目录, 重命名上传文件, 用上传文件名的后缀拼接重命名之后的文件名.

5. 设置上传文件大小, 设置上传文件类型, 然后调用upload方法上传文件, 对upload方法传入文件原始名称,和重命名之后的文件名称(路径)

6. 如果文件类型是图片就加上水印

7. 返回文件路径

我们先去看看upload方法长什么样子, upload方法在core/library/upload.class.php

public function upload($file_upload, $file_name) 
{ 
    if (!is_array($file_upload) || empty($file_name)) return false; 
    $this->parse_init($file_upload); 
    if (!@move_uploaded_file($this->file_name['tmp_name'], $file_name)) return '文件上传失败,请检查服务器目录权限'; 
    return true; 
}​

可以看见upload方法在正式@move_uploaded_file之前, 调用了parse_init()方法, 到现在为止,我们还没看见上传文件限制在哪里, 去看看parse_init:

protected function parse_init($file) 
{ 
    $this->file_name = $file; 
    if ($this->file_name['size'] > $this->limit_size) { 
        echo '您上传的文件:' . $this->file_name['name'] . ' 大小超出上传限制!'; 
        exit(); 
    } 
    if ($this->limit_type) { 
        if (!in_array($this->get_file_ext(), $this->limit_type)) { 
            echo '您上传的:' . $this->file_name['name'] . ' 文件格式不正确!'; 
            exit(); 
        } 
    } 
    return true; 
} ​

在这里我们看见了对上传文件的限制了. 在第24行到第28行. 可以看见它是根据$this->limit_type来进行判断的.
如果$this->get_file_ext的后缀不在this->limit_type中, 就返回格式不正确.直接exit()掉, 就无法进入下一步的@move_uploaded_file
那么我们如果可以控制$this->limit-type, 就可以上传任意文件.我们跟踪$this->limit-type,看看它在哪里定义,是否可控:

public function set_limit_type($type) 
{ 
    if (!$type || !is_array($type)) return false; 
    $this->limit_type = $type; 
    return $this; 
}​


$this->limit-type 在set_limit_type方法中定义, set_limit_size方法要求参数是$type. 通过联系上下文, 我们可以知道$type是直接从URL中获取的. 因此,$this->limit-type 我们是可控的. 可以上传任意文件.

漏洞利用

1. 登陆后台. 选择产品信息发布

2. 在缩略图上传处,选择文件上传. 载入1.php

3. 通过burp拦截请求, 在type后面加入,php. 上传成功, 获得返回地址


Pre: flvcd解析广告绕过

Next: No Post

132
Sign in to leave a comment.
No Leanote account? Sign up now.
0 comments
Table of content