WellCMS 2.0 Beta3 后台任意文件上传

2020-03-02 约 553 字 预计阅读 3 分钟

声明:本文 【WellCMS 2.0 Beta3 后台任意文件上传】 由作者 2200 于 2020-03-02 08:53:11 首发 先知社区 曾经 浏览数 376 次

感谢 2200 的辛苦付出!

一、概述

WellCMS是一款开源、倾向移动端的轻量级CMS,高负载CMS,亿万级CMS,是大数据量、高并发访问网站最佳选择的轻CMS。登陆该CMS后台,某图片上传处,由于上传文件类型可控,可修改上传文件类型获取webshell。

二、复现

这个漏洞来自一次偶然的测试,一次幸运的测试,那就直接写出我的测试过程。

第一步,登陆该CMS后台:

第二步,进入“后台管理“,定位利用点,点击下图红框中图片进行上传:

上传并抓取数据包:

第三步,修改post包中“filetype”参数类型为“php”;经分析 “data”参数为base64加密,这里我们将测试数据“<?php phpinfo();?>”经过base64加密等构造,形成“data”参数的数据:data%3Aimage%2Fjpeg%3Bbase64%2CPD9waHAgcGhwaW5mbygpOz8%2B,最后数据包放行,返回成功上传为php文件的路径:

最后,尝试访问,成功:

三、大致分析

根据漏洞定位代码文件:route/attach.php,代码如下:

if ($action == 'create') {
    // hook attach_create_start.php
    user_login_check();
    // hook attach_create_check_after.php
    $backstage = param(2, 0);
    $width = param('width', 0);
    $height = param('height', 0);
    $is_image = param('is_image', 0); // 图片
    $name = param('name');
    $data = param_base64('data');
    $mode = param('mode', 0); // 上传类型 1主图
    $filetype = param('filetype'); // 压缩图片后缀jpeg jpg png等
    $convert = param('convert', 0); // 图片转换压缩 = 1
    $n = param('n', 0); // 对应主图赋值
    $type = param('type', 0); // type = 0则按照SESSION数组附件数量统计,type = 1则按照传入的n数值
    // hook attach_create_before.php
    // 允许的文件后缀名
    //$types = include _include(APP_PATH.'conf/attach.conf.php');
    //$allowtypes = $types['all'];
    empty($group['allowattach']) AND $gid != 1 AND message(2, '您无权上传');
    // hook attach_create_center.php
    empty($data) AND message(1, lang('data_is_empty'));
    //$data = base64_decode_file_data($data);
    $size = strlen($data);
    $size > 20480000 AND message(1, lang('filesize_too_large', array('maxsize' => '20M', 'size' => $size)));
    // hook attach_create_file_ext_start.php
    // 获取文件后缀名 111.php.shtmll
    $ext = file_ext($name, 7);
    $filetypes = include APP_PATH . 'conf/attach.conf.php';
    // hook attach_create_file_ext_before.php
    //主图必须为图片
    if ($is_image == 1 && $mode == 1 && !in_array($ext, $filetypes['image'])) message(1, lang('well_up_picture_error'));

    // hook attach_create_file_ext_center.php

    // 如果文件后缀不在规定范围内 改变后缀名
    //!in_array($ext, $filetypes['all']) AND $ext = '_' . $ext;
    if (!in_array($ext, $filetypes['all'])) {
        $ext = '_' . $ext;
    } else {
        // CMS上传图片
        $t == 1 AND $convert == 1 AND $is_image == 1 AND $ext = $filetype;
    }
    // hook attach_create_file_ext_after.php
    $tmpanme = $uid . '_' . xn_rand(15) . '.' . $ext;
    // hook attach_create_tmpanme_after.php
    $tmpfile = $conf['upload_path'] . 'tmp/' . $tmpanme;
    // hook attach_create_tmpfile_after.php
    $tmpurl = $conf['upload_url'] . 'tmp/' . $tmpanme;
    // hook attach_create_tmpurl_after.php
    $filetype = attach_type($name, $filetypes);
    // hook attach_create_save_before.php
    file_put_contents($tmpfile, $data) OR message(1, lang('write_to_file_failed'));
    // hook attach_create_save_after.php
    // 保存到 session,发帖成功以后,关联到帖子。
    // save attach information to session, associate to post after create thread.
    // 抛弃之前的 $_SESSION 数据,重新启动 session,降低 session 并发写入的问题
    // Discard the previous $_SESSION data, restart the session, reduce the problem of concurrent session write
    sess_restart();
    empty($t) AND empty($_SESSION['tmp_files']) AND $_SESSION['tmp_files'] = array();
    $t == 1 AND empty($_SESSION['tmp_website_files']) AND $_SESSION['tmp_website_files'] = array();

    // hook attach_create_after.php
    // type = 0则按照SESSION数组附件数量统计,type = 1则按照传入的n数值
    empty($type) AND $n = ($t == 1) ? count($_SESSION['tmp_website_files']) : count($_SESSION['tmp_files']);
    $filesize = filesize($tmpfile);
    $attach = array(
        'backstage' => $backstage, // 0前台 1后台
        'url' => $backstage ? '../' . $tmpurl : '' . $tmpurl,
        'path' => $tmpfile,
        'orgfilename' => $name,
        'filetype' => $filetype,
        'filesize' => $filesize,
        'width' => $width,
        'height' => $height,
        'isimage' => $is_image,
        'downloads' => 0,
        'aid' => '_' . $n
    );
    // hook attach_create_array_after.php
    if ($mode == 1) {
        // hook attach_create_thumbnail_beofre.php
        $_SESSION['tmp_thumbnail'] = $attach;
        // hook attach_create_thumbnail_after.php
    } else {
        // hook attach_create_website_files_beofre.php
        // 0 BBS 1 CMS
        $t == 1 ? $_SESSION['tmp_website_files'][$n] = $attach : $_SESSION['tmp_files'][$n] = $attach;
        // hook attach_create_website_files_after.php
    }
    // hook attach_create_session_after.php
    unset($attach['path']);
    // hook attach_create_end.php
    message(0, $attach);
}

大致流程:
1、 首先,接受相关参数,将filetype自行设置成“php”:

$data = param_base64('data');
$filetype = param('filetype'); /

2、 进行逻辑判断:

if (!in_array($ext, $filetypes['all'])) {
        $ext = '_' . $ext;
    } else {
        // CMS上传图片
        $t == 1 AND $convert == 1 AND $is_image == 1 AND $ext = $filetype;
    }

3、 最后成功写入:

$tmpanme = $uid . '_' . xn_rand(15) . '.' . $ext;
    // hook attach_create_tmpanme_after.php
    $tmpfile = $conf['upload_path'] . 'tmp/' . $tmpanme;
    // hook attach_create_tmpfile_after.php
    $tmpurl = $conf['upload_url'] . 'tmp/' . $tmpanme;
    // hook attach_create_tmpurl_after.php
    $filetype = attach_type($name, $filetypes);
    // hook attach_create_save_before.php
    file_put_contents($tmpfile, $data) OR message(1, lang('write_to_file_failed'));

关键词:[‘安全技术’, ‘漏洞分析’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now