孚盟云CRM AjaxBusinessPrice.ashx SQL注入漏洞


漏洞简介

上海孚盟软件有限公司是一家专业的外贸SaaS服务和行业解决方案提供商。其旗下产品孚盟云AjaxBusinessPrice.ashx接口存在SQL注入漏洞,未经身份验证的远程攻击者除了可以利用SQL注入漏洞获取数据库中的信息(例如,管理员后台密码、站点的用户个人信息)之外,甚至在高权限的情况可向服务器中写入木马,进一步获取服务器系统权限。

影响版本

fofa语法

app="孚盟软件-孚盟云"

漏洞分析

直接看 AjaxBusinessPrice.ashx 对应的dll文件 FumaCRM_BS.NewWeb.dll 里有关 AjaxBusinessPrice 方法的实现如下

public void ProcessRequest(HttpContext context)
{
  context.Response.ContentType = "text/plain";
  string str = context.Request["action"];
  if (!string.IsNullOrEmpty(UserCookie.GetCookieValue("empId")))
  {
    this.userId = UserCookie.GetCookieValue("empId");
    this.userId = FumaCRM_BS.Utility.Encrypt.Encrypt.DesDecrypt(this.userId);
  }
  else
  {
    Helper.WriteLog("empID:空", "ajaxbusiness");
    context.Response.Write("-1");
  }
  string s = str;
  // ISSUE: reference to a compiler-generated method
  switch (\u003CPrivateImplementationDetails\u003E.ComputeStringHash(s))
  {
    case 315799074:
      if (!string.op_Equality(s, "insertBusiPrice"))
        break;
      this.insertBusiPrice(context);
      break;
    case 323632542:
      if (!string.op_Equality(s, "ImportBusinessPriceFiles"))
        break;
      this.ImportBusinessPriceFiles(context);
      break;

首先判断Cookie里的empId是否为空,如果为空直接响应“-1”,因此跟进GetCookieValue方法看下Cookie取值如何取的

public static string GetCookieValue(string key)
{
  if (HttpContext.Current == null)
    return "";
  HttpCookie cookie = HttpContext.Current.Request.Cookies[nameof (UserCookie)];
  try
  {
    string cookieValue = "";
    if (cookie != null && JsonConvert.DeserializeObject(cookie.Value, typeof (Hashtable)) is Hashtable hashtable && hashtable.ContainsKey((object) key))
      cookieValue = hashtable[(object) key].ToString();
    return cookieValue;
  }
  catch (Exception ex)
  {
    UserCookie.WriteLog("cookie err:" + ex.Message, "ddSaas");
    return "";
  }
}

OJBK,看到 JsonConvert类的使用,非常明了,请求里的Cookie就是一串json,类似{"UserId":"12345","UserName":"张三","Role":"Admin"} 这种格式,cookie的键名就是UserCookie

根据代码逻辑,我们的请求cookie只需要存在UserCookie={"empId":"xxxx"} 这种格式就可满足条件了。

再看看FumaCRM_BS.Utility.Encrypt.Encrypt.DesDecrypt(this.userId)相关解密实现

朴实无华的DES解密,key(密钥)在代码里硬编码为 fumasoft

且一般c#的DES加密模式为ECB,填充模式PKCS7,我们也可以据此伪造要给合法的empId,比如 1 经过 des ECB PKCS7 加密后为 e0a40f1c63e6b84f。

根据参数action的值进入不同的处理逻辑,当action=ImportBusinessPriceFiles时,看ImportBusinessPriceFiles方法的实现

public void ImportBusinessPriceFiles(HttpContext context)
{
  try
  {
    Helper.WriteLog("ImportBusinessPriceFiles: start", "products");
    string str1 = context.Request["templateId"] == null ? "18" : context.Request["templateId"].ToString();
    int num = context.Request["Fid"] == null ? 927 : Convert.ToInt32(context.Request["Fid"].ToString());
    int int32 = context.Request["type"] == null ? 0 : Convert.ToInt32(context.Request["type"].ToString());
    Helper.WriteLog("ImportBusinessPriceFiles: templateId:" + str1, "products");
    Helper.WriteLog("ImportBusinessPriceFiles: Fid:" + (object) num, "products");
    Helper.WriteLog("ImportBusinessPriceFiles: type:" + (object) int32, "products");
    DataTable table = MySqlHelper.ExecuteDataSet(new EncryptData().DecryptString(MySqlHelper.DBConnectionString), (CommandType) 1, $"select * from Tempelate where TempelateId = '{str1}' ").Tables[0];

templateId 参数未经过任何过滤或校验就被直接拼接进SQL语句中进行执行,从而造成SQL注入漏洞,这里需要注意数据库相关操作为MySQL数据库,而非sql server !

当action=checkBusinessPrice时

跟进getEmpAllMouldByEmpId方法

public string getEmpAllMouldByEmpId(string empId)
{
  if (string.IsNullOrEmpty(empId) && !string.IsNullOrEmpty(UserCookie.GetCookieValue(nameof (empId))))
  {
    empId = UserCookie.GetCookieValue(nameof (empId));
    empId = FumaCRM_BS.Utility.Encrypt.Encrypt.DesDecrypt(empId);
  }
  string empAllMouldByEmpId = "";
  if (!string.IsNullOrEmpty(empId))
  {
    StringBuilder stringBuilder = new StringBuilder();
    DataTable table = this.dbHelper.Query($" select MouldID from syLicMouldDtl where MouldKey  in (select MouldKey from syLicMouldEmp where EmpID = '{empId}')").Tables[0];

OK,参数empId被直接拼接进SQL语句执行,同样造成SQL注入漏洞,还是这么朴实无华!

以及ImportBusinessPriceToDingPan

GetContactEmailByFid

GetContacts

GetContactEmail

getCustReturnValue

getBusinessPriceHtml

moreLoad

GetBmailByFid

GetCqnoByFid

saveBusinessPriceForPdf

sendBusinessPriceMessage

createShoppingCart

漏洞复现

漏洞利用需要注意,此处是MySQL数据库相关操作,并非mssql !

POST /m/Dingding/Ajax/AjaxBusinessPrice.ashx HTTP/1.1
Host: fumacrm.mrxn.net
Cookie: UserCookie={"empId":"1"}
Content-Type: application/x-www-form-urlencoded

action=ImportBusinessPriceFiles&templateId='SQLI_POC&Fid=1&type=1

成功延时 4 秒

以及 action=checkBusinessPrice 时

通过报错注入,成功在响应里回显数据库版本信息

此类的其余诸多的sql注入方法就不一一复现了


手机扫码阅读

金和OA HolidayEdit.aspx SQL注入漏洞

金和OA AttendWorkAttendance.aspx SQL注入漏洞

评 论