In addition to Weibo, there is also WeChat
Please pay attention
WeChat public account
Shulou
2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >
Share
Shulou(Shulou.com)06/01 Report--
This article is about how to achieve Apache Ofbiz deserialization vulnerability CVE-2020-9496 analysis, the editor feels very practical, so share with you to learn, I hope you can get something after reading this article, say no more, follow the editor to have a look.
Brief introduction of 0x01 vulnerability
On September 29th, 2020, 360CERT analyzed the deserialization vulnerability of the Apache ofbiz component. The vulnerability number is CVE-2020-9496, vulnerability level: high risk, vulnerability score: 8.0.
There is a deserialization vulnerability in Apache ofbiz, which allows attackers to construct specific xmlrpc http requests by accessing unauthorized interfaces, which can affect remote code execution.
0x02 risk rating
360CERT's assessment of the vulnerability is as follows
Evaluation method, threat level, high risk impact surface, general 360CERT score 8.0, 0x03 influence version
-Apache Ofbiz:
< 17.12.04 0x04 漏洞详情XML-RPC XML-RPC是一种远程过程调用(RPC)协议,它使用XML对其调用进行编码,并使用HTTP作为传输机制。它是一种规范和一组实现,允许软件运行在不同的操作系统上,运行在不同的环境中,通过Internet进行过程调用。在XML-RPC中,客户端通过向实现XML-RPC并接收HTTP响应的服务器发送HTTP请求来执行RPC。 Demo 客户端 package org.apache.xmlrpc.demo.client; import java.net.URL; import org.apache.xmlrpc.client.XmlRpcClient; import org.apache.xmlrpc.client.XmlRpcClientConfigImpl; import org.apache.xmlrpc.client.XmlRpcSunHttpTransportFactory; public class Client { public static void main(String[] args) throws Exception { // 创建客户端实例 XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); config.setServerURL(new URL("http://127.0.0.1:8081/xmlrpc")); XmlRpcClient client = new XmlRpcClient(); client.setConfig(config); // 设置传输工厂类 client.setTransportFactory(new XmlRpcSunHttpTransportFactory(client)); // 创建远程方法的参数数组,通过指定远程方法名称进行调用 Object[] params = new Object[]{new Integer(33), new Integer(9)}; Integer result = (Integer) client.execute("Calculator.add", params); System.out.println(result); } } 或者客户端使用动态代理的方式,通过ClientFactory,需要客户端和服务端都要有Adder的接口,具体实现类在服务端。 但要使用XML-RPC的动态代理功能,相应的服务器端的处理器类名称必须是Client端接口类的全名(含包名,该名称一般应该与Server端接口类全名一致),否则将会导致调用失败。 public class Client_Proxy { public static void main(String[] args) throws MalformedURLException { XmlRpcClientConfigImpl config = new XmlRpcClientConfigImpl(); config.setServerURL(new URL("http://127.0.0.1:8081/xmlrpc")); XmlRpcClient client = new XmlRpcClient(); client.setConfig(config); ClientFactory factory = new ClientFactory(client); Adder adder = (Adder) factory.newInstance(Adder.class); int sum = adder.add(2, 4); System.out.println(sum); } } Adder接口 package org.apache.xmlrpc.demo.proxy; public interface Adder { public int add(int pNum1, int pNum2); } 服务端 package org.apache.xmlrpc.demo.webserver; import org.apache.xmlrpc.server.PropertyHandlerMapping; import org.apache.xmlrpc.server.XmlRpcServer; import org.apache.xmlrpc.server.XmlRpcServerConfigImpl; import org.apache.xmlrpc.webserver.WebServer; public class Server { private static final int port = 8081; public static void main(String[] args) throws Exception { WebServer webServer = new WebServer(port); XmlRpcServer xmlRpcServer = webServer.getXmlRpcServer(); PropertyHandlerMapping phm = new PropertyHandlerMapping(); /* Load handler definitions from a property file. * The property file might look like: * Calculator=org.apache.xmlrpc.demo.Calculator * org.apache.xmlrpc.demo.proxy.Adder=org.apache.xmlrpc.demo.proxy.AdderImpl */ phm.load(Thread.currentThread().getContextClassLoader(), "MyHandlers.properties"); /* You may also provide the handler classes directly, * like this: * phm.addHandler("Calculator", * org.apache.xmlrpc.demo.Calculator.class); * phm.addHandler(org.apache.xmlrpc.demo.proxy.Adder.class.getName(), * org.apache.xmlrpc.demo.proxy.AdderImpl.class); */ phm.addHandler("Calculator", org.apache.xmlrpc.demo.Calculator.class); xmlRpcServer.setHandlerMapping(phm); XmlRpcServerConfigImpl serverConfig = (XmlRpcServerConfigImpl) xmlRpcServer.getConfig(); serverConfig.setEnabledForExtensions(true); serverConfig.setContentLengthOptional(false); webServer.start(); } } 服务端调用类 package org.apache.xmlrpc.demo; public class Calculator { public int add(int i1, int i2) { return i1 + i2; } public int subtract(int i1, int i2) { return i1 - i2; } } 在服务端还需要创建一个MyHandlers.properties。 启动服务端之后,运行客户端。Grab traffic. Dynamic agents and ordinary traffic are the same.
The client sends an POST request to / xmlrpc with the following contents:
Calculator.add
thirty-three
nine
Each XML-RPC request begins with a XML element. This element contains a single child element xxx. The element contains child elements, which can contain one or more elements. The param XML element can contain many data types.
The content of the server response is
forty-two
Initialize RequestHandler
Note: the dependent version of `commons- beanutils` of `commons- 17.12.03` is `1.9.3`.
When ControlServlet is loaded for the first time, init is called for initialization, and RequestHandler is initialized through getRequestHandler.
Call the getControllerConfigURL method
This method gets a list of the defined request mappings from the configuration file / WEB-INF/controller.xml, where the controller.xml configuration files of all webapp are traversed.
Among them, the configuration of xmlrpc is defined, and the corresponding auth option is not set. It defaults to false and does not require authentication, which is also a point to be repaired later.
The tag of the configuration file given in the official document:
Then instantiate ViewFactory and EventFactory.
First, take a look at the instantiated ViewFactory, which will traverse the required Viewerhandler and initialize the init based on the fact that the type in the configuration file is the corresponding value in the view attribute. Then deposit it in map.
There are 9 type in the configuration file under webtools.
Then instantiate the EventFactory, again traverse that type is the EventHandler of event, initialize the init, and then store it in map.
Then put all the initialization settings into servletContext.
Process the request
According to the published zdi article, xml is executed in webtools/control/xmlrpc, so go to / webtools/webapp/webtools/WEB-INF/web.xml to see how the relevant routes are handled.
ControlServlet
/ control/*
The resources under the request / control are processed by ControlServlet, which is the core of all request processing. The post request is also processed by the ControlServlet#doGet method:
First, call getRequestHandler, which can be obtained directly because it has been initialized.
The next step is to process something from the request request, and then call the requestHandler.doRequest method to get the appname of the current request based on the request request, in this case webtools, and then get pathinfo, which is xmlrpc.
Then get the corresponding configuration from the config according to pathinfo, and move on. RequestMap.event is the xmlrpc obtained previously according to the configuration.
Type,path,invoke is not null, so follow up on runEvent. Get eventhandler from eventFactory according to type
The call of XmlRpcEventHandler
Then call eventHandler.invoke, where our echo parameter is null, so call the execute method.
Follow the getRequest method.
The first few lines are in preparation for SAX parsing. Set a handler to XmlRpcRequestParser, with the following structure:
The main element parsing occurs in XmlRpcRequestParser.
Then call the parse function to formally enter the process of http xml parsing.
XML parsing
Here, the parsing of xml is mainly based on SAX. The events triggered by SAX parsing are
StartDocument: start reading XML documents
StartElement: read an element, such as
Characters: character read
EndElement: read a closing element, such as
EndDocument: finish reading the XML document.
The whole scan process mainly occurs in XMLDocumentFragmentScannerImpl#dispatch. The previous call stack is as follows:
Use fScannerState to identify which method should be called to parse the tag.
At the beginning of parsing, the state is 6:
Call scanRootElementHook, which is used to scan the root element. Resolver is null, so enter else.
Then in AbstractSAXParser#startElement, ContentHandler.startElement is called, and the content is set when it was initialized, that is, the XmlRpcRequestParser#startElement method.
In the XmlRpcRequestParser#startElement function, parsing methodCall,methodName,params,parma,value tags is supported. If not, leave it to the parent class RecursiveTypeParserImpl for further processing.
It is determined that methodName will set inMethodName to true, and after that, dispatch enters the branch to process content according to state, and then calls XmlRpcRequestParser#characters to set the methodName property.
The next tag is the closing tag call endElement, setting inMethodName to false.
Analysis of tags in value
If the parse is a child tag in value, then the startValueTag method is called.
The inValueTag property is set to true.
Later, for example, when parsing the serializable tag, it will enter the default branch.
RecursiveTypeParserImpl#startElement, at the beginning, typeParser is null.
In the getParser method, a specific corresponding Parser is created from the TypeFactoryImpl based on the tag, and to get the extended Parser in the first judgment, you also need to specify the pURI.
The xml structure in the value in our poc is:
Test
{base64codehere}
So the first instantiation is MapParser, so the typeParser of XmlRpcRequestParser is MapParser.
Or should we call Parser.startDocument first?
Then call its corresponding startElement method.
After judging the struct tag, then parse the next tag member
Repeat the previous process, XmlRpcRequestParser can not parse, let RecursiveTypeParserImpl handle. But at this point, typeParser is no longer null, so MapParser#startElement is called directly for processing.
Second value tag
The other tag in the middle is omitted. Note that there is a value tag before the serializable tag, but it is not handled by XmlRpcRequestParser, because at this time the level is already very large, so you can directly see the processing of value by MapParser.
Call startValueTag and re-set typeParser to null, but here you set the typeParser of MapParser. This step is critical. Only if typeParser is null, can you get the parser again.
Serializable tag
When parsing serializable, the typeParser of XmlRpcRequestParser is still MapParser, but the serializable tag cannot be processed in MapParser, so give it to RecursiveTypeParserImpl at this time. What you get is the typeParser of MapParser. Because it was previously set to null, you re-get Parser, and then resolve to the serializable tag, so getParser returns SerializableParser.
SerializableParser inherits ByteArrayParser and has no startElement method, so the parent class ByteArrayParser is called, OutputStream is set, and the input stream is decoded.
Then process assigning a value to result in Serializable#endElement,setResult.
Then there is processing, in MapParser#endElement.
Follow the endValueTag,typeParser as Serializable.
Call getResult, take out the result and cause deserialization.
Version repair
Fixed: Apache OFBiz unsafe deserialization of XMLRPC arguments
Https://github.com/apache/ofbiz-framework/commit/4bdfb54ffb6e05215dd826ca2902c3e31420287a#diff-b31806fbf9690361ad449e8f263345d8
Configuring xmlrpc directly in controller.xml requires authorized access.
Xmlrpc itself supports deserialization of serialized data, but the problem is that ofbiz does not have permission control over access to the xmlrpc interface, and there are dependencies that can be exploited by deserialization in a lower version.
The above is how to achieve the Apache Ofbiz deserialization vulnerability CVE-2020-9496 analysis, the editor believes that there are some knowledge points that we may see or use in our daily work. I hope you can learn more from this article. For more details, please follow the industry information channel.
Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.
Views: 0
*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.
Continue with the installation of the previous hadoop.First, install zookooper1. Decompress zookoope
"Every 5-10 years, there's a rare product, a really special, very unusual product that's the most un
© 2024 shulou.com SLNews company. All rights reserved.