内容简介:Apache XML-RPC是一个java的XML-RPC库。XML-RPC是在XML的帮助下通过HTTP进行远程过程调用的协议。 Apache XML-RPC可以在客户端用于进XML-RPC调用,也可以在服务器端用XML-RPC公开一些函数。现在ws-xmlrpc库不被Apache支持。 最新版本是2013年发布的3.1.3版本。但是,许多应用程序仍然使用ws-xmlrpc库新建Maven工程,引入如下依赖主方法
一、xmlrpc简介
Apache XML-RPC是一个 java 的XML-RPC库。XML-RPC是在XML的帮助下通过HTTP进行远程过程调用的协议。 Apache XML-RPC可以在客户端用于进XML-RPC调用,也可以在服务器端用XML-RPC公开一些函数。现在ws-xmlrpc库不被Apache支持。 最新版本是2013年发布的3.1.3版本。但是,许多应用程序仍然使用ws-xmlrpc库
二、漏洞重现
新建Maven工程,引入如下依赖
<dependencies> <dependency> <groupId>org.apache.xmlrpc</groupId> <artifactId>xmlrpc-common</artifactId> <version>3.1.3</version> </dependency> <dependency> <groupId>org.apache.xmlrpc</groupId> <artifactId>xmlrpc-server</artifactId> <version>3.1.3</version> </dependency> <dependency> <groupId>commons-collections</groupId> <artifactId>commons-collections</artifactId> <version>3.2.1</version> </dependency> </dependencies>
主方法 App.java
public class App { private static final int port = 8888; public static void main(String[] args) throws Exception { WebServer webServer = new WebServer(port); XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer(); PropertyHandlerMapping phm = new PropertyHandlerMapping(); phm.addHandler("User", User.class); xmlRpcServer.setHandlerMapping(phm); XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig(); serverConfig.setEnabledForExtensions(true); webServer.start(); } }
接收传入对象 User.java
public class User { public String welcome(String name) { return "welcome " + name; } }
运行 App.java
后即在 8888
端口建立 HTTP
服务。即可使用Burpsuite进行发包测试 参考 官网帮助文档 ,可以发现xmlrpc支持 java.io.Serializable
序列化后的base64编码的数据,但是需要引用命名空间 http://ws.apache.org/xmlrpc/namespaces/extensions
。所以使用 ysoserial
的 CommonsCollections5
生成payload。 因为本机测试环境为jdk1.8,用其它payload会爆错 。 然后使用certutil -encode 将生成的文件进行base64编码。
漏洞分析
当客户端发送请求时, org.apache.xmlrpc.server.XmlRpcStreamServer.getRequest(XmlRpcStreamRequestConfig, InputStream)
方法会接收到该请求,该方法会将请求内容封闭到XMLReader对象中。
protected XmlRpcRequest getRequest(final XmlRpcStreamRequestConfig pConfig, InputStream pStream) throws XmlRpcException { final XmlRpcRequestParser parser = new XmlRpcRequestParser(pConfig, getTypeFactory()); final XMLReader xr = SAXParsers.newXMLReader(); xr.setContentHandler(parser); try { xr.parse(new InputSource(pStream)); } catch (SAXException e) { Exception ex = e.getException(); if (ex != null && ex instanceof XmlRpcException) { throw (XmlRpcException) ex; } throw new XmlRpcException("Failed to parse XML-RPC request: " + e.getMessage(), e); } catch (IOException e) { throw new XmlRpcException("Failed to read XML-RPC request: " + e.getMessage(), e); } final List params = parser.getParams(); return new XmlRpcRequest(){ public XmlRpcRequestConfig getConfig() { return pConfig; } public String getMethodName() { return parser.getMethodName(); } public int getParameterCount() { return params == null ? 0 : params.size(); } public Object getParameter(int pIndex) { return params.get(pIndex); } }; }
然后程序会走到 org.apache.xmlrpc.parser.XmlRpcRequestParser.endElement(String, String, String)
方法来获取各个元素的值
public void endElement(String pURI, String pLocalName, String pQName) throws SAXException { switch(--level) { case 0: break; case 1: if (inMethodName) { if ("".equals(pURI) && "methodName".equals(pLocalName)) { if (methodName == null) { methodName = ""; } } else { throw new SAXParseException("Expected /methodName, got " + new QName(pURI, pLocalName), getDocumentLocator()); } inMethodName = false; } else if (!"".equals(pURI) || !"params".equals(pLocalName)) { throw new SAXParseException("Expected /params, got " + new QName(pURI, pLocalName), getDocumentLocator()); } break; case 2: if (!"".equals(pURI) || !"param".equals(pLocalName)) { throw new SAXParseException("Expected /param, got " + new QName(pURI, pLocalName), getDocumentLocator()); } break; case 3: if (!"".equals(pURI) || !"value".equals(pLocalName)) { throw new SAXParseException("Expected /value, got " + new QName(pURI, pLocalName), getDocumentLocator()); } endValueTag(); break; default: super.endElement(pURI, pLocalName, pQName); break; } }
当获取到最后的元素时,会执行 org.apache.xmlrpc.parser.RecursiveTypeParserImpl.endValueTag()
方法
protected void endValueTag() throws SAXException { if (inValueTag) { if (typeParser == null) { addResult(text.toString()); text.setLength(0); } else { typeParser.endDocument(); try { addResult(typeParser.getResult()); } catch (XmlRpcException e) { throw new SAXException(e); } typeParser = null; } } else { throw new SAXParseException("Invalid state: Not inside value tag.", getDocumentLocator()); } }
即会执行typeParser.getResult(),并且此时的typeParser为SerializableParser,
public class SerializableParser extends ByteArrayParser { public Object getResult() throws XmlRpcException { try { byte[] res = (byte[]) super.getResult(); ByteArrayInputStream bais = new ByteArrayInputStream(res); ObjectInputStream ois = new ObjectInputStream(bais); return ois.readObject(); } catch (IOException e) { throw new XmlRpcException("Failed to read result object: " + e.getMessage(), e); } catch (ClassNotFoundException e) { throw new XmlRpcException("Failed to load class for result object: " + e.getMessage(), e); } } }
从而造成了反序列化命令执行漏洞。
以上所述就是小编给大家介绍的《CVE-2016-5003 xmlrpc反序列化漏洞》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
JavaScript DOM编程艺术 (第2版)
[英] Jeremy Keith、[加] Jeffrey Sambells / 杨涛、王建桥、杨晓云 等 / 人民邮电出版社 / 2011-4 / 49.00元
JavaScript是Web开发中最重要的一门语言,它强大而优美。无论是桌面开发,还是移动应用。JavaScript都是必须掌握的技术。W3C的DOM标准是开发Web应用的基石。已经得到所有现代浏览器的支持,这使得跨平台Web开发成了一件轻松惬意的事。 本书是超级畅销书的升级版,由倡导Web标准的领军人物执笔,揭示了前端开发的真谛,是学习JavaScript和DOM开发的必读之作。 本......一起来看看 《JavaScript DOM编程艺术 (第2版)》 这本书的介绍吧!