Object serialization in Java language
To understand everything concerning this type of vulnerabilities, and for those who have little programming experience, first, you need to know is: what is object serialization.
Object serialization is nothing more than the conversion of an object into a format (p.e. a byte stream) which then can be stored or transmitted [1], likewise, there must be an inverse process to convert this data back to an object or retrieve the object, this process is called deserialization.
Who know Java programming know we can do this through the following code:
FileOutputStream file = new FileOutputStream(filename);
ObjectOutputStream serializer = new ObjectOutputStream(file);
serializer.writeObject(myObject);
serializer.close();
file.close();
What the previous code does is to serialize a Java object and then save it in a file using the “writeObject” method, this will generate a binary file that contains the binary representation of the object (as a binary stream), the only requirement is that the object must implement the Serializable interface.
To deserialize the object of the previous example, we can do it through the following code:
FileInputStream file = new FileInputStream(filename);
ObjectInputStream unserializer = new ObjectInputStream(file);
myRecoveredObject = (myObject) unserializer.readObject();
Object serialization in Java language has two important behaviors, that we must consider when programming, as well as to understand its operation and application:
- Only the data and structure of the objects are serialized, not code.
- If the class contains code, it must at least reside at the deserialization point.
I’m not going to give a detailed explanation of how it works internally, because it’s not necessary, however, if you want more information about this Java language feature, there is a lot of resources on the Internet that can help you [2].
Exploiting Java object serialization vulnerabilities
At first glance there seems to be no problem or danger with object serialization as this feature only converts the data and the structure of the objects (not code), however, there is a problem with it, this is found in the JRE libraries, as well as in third-party libraries (packages), the problem is because some events, which are specific to internal objects of JRE, make use of a language instrumentation feature called «Reflection». This feature allows the dynamic execution of Java code, which can be very insecure because if in some way we include or trick those classes that contain the events, we could get arbitrary code execution on the side where the deserialization takes place.
This type of vulnerabilities is not new, but recently and thanks to the works (articles, conferences, and others) of @frohoff and @gebl that created several «Gadgets» or snippets of code that achieve the arbitrary command execution on the system, have allowed to popularize and force the affected companies to take serious measures on the subject.
The AnnotationInvocationHandler class is necessary to automatically execute the payload, since the method that performs its deserialization (readObject), invokes the entrySet method of the proxy object in which a chain of classes (Transformer) is configured performing the dynamic execution of the payload.
These Gadgets can be created using some classes in third-party libraries (eg common-collections) and it’s even possible to use the own libraries of the JRE, currently, there are tools that allow us generating different payloads (ysoserial [3]).
The following is the Java code used to create the previous Gadget:
final String[] execArgs = new String[] { command };
final Transformer transformerChain = new ChainedTransformer(
new Transformer[]{ new ConstantTransformer(1) });
final 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),
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);
return handler;
In this way, after sending the serialized Gadget to the deserialization endpoint and once the call to readObject is performed on the byte stream, it will automatically execute our payload that commonly contains a call to Runtime.getRuntime().exec() method, which will execute the command that we specify.
Countermeasures implemented
Given the emergence of a high number of vulnerabilities of this type, after a long time (about 20 years) Oracle decided to implement some countermeasures in its JDK (Java SE 8 CPU Update 121) in order to mitigate this problem, then they introduce a new security feature: serialization filters [4], Black List y White List, with the purpose of preventing developers from making use of some classes considered unsafe. This measures certainly does not end with this kind of attacks, although it can be reduced with the use of good practices by programmers. However, in my opinion, the most effective solution can be better oriented in avoiding that the developers perform dynamic execution of methods using «Reflection«, this should not be a functionality enabled by default, of course, a change like this is quite strong and can affect some libraries already developed, which would have to be updated or re-implemented.
The case of Oracle WebLogic Server
As almost everyone already knows, Weblogic is a container of Java applications, unfortunately Weblogic uses for its control a proprietary protocol called T3, in this protocol a handshake is initially performed, and then a request is made where a list of serialized Java objects are attached, these objects allow executing the administrative functions provided by the service. The severity lies in the fact that, without having to authenticate, it is possible to send malicious serialized objects and achieve remote code execution.
Currently, there are five important vulnerabilities that use object serialization and affect multiple versions of WebLogic, they are the following:
- CVE-2015-4852
- CVE-2016-0638
- CVE-2016-3510
- CVE-2017-3248
- CVE-2018-2628
Metasploit modules
As a small contribution to the security community, I’ve developed three Metasploit modules that take advantage of some of these vulnerabilities, other vulnerabilities already are included in the Metasploit framework.
- CVE-2015-4852: Through object serialization, it achieves RCE – weblogic_serialize_rawobject [5].
- CVE-2016-3510: Through a MarshalledObject object it achieves RCE – weblogic_serialize_marshaledobject [6].
- CVE-2017-3248: Through serialization of an UnicastRef object it creates an inverse connection using JRMP from the server in which the payload is sent achieving RCE – weblogic_serialize_unicastref [7].
Currently these modules have not been added to the Metasploit main repository because the release cycle has not been completed, however, you can try them out and use by manually adding them to the framework. In the references section, you can take a look at the pull requests, discussions, files and code.
References
[1] https://en.wikipedia.org/wiki/Serialization
[2] https://docs.oracle.com/javase/7/docs/platform/serialization/spec/serialTOC.html
[3] https://github.com/frohoff/ysoserial
[4] https://www.oracle.com/technetwork/java/javase/8u121-relnotes-3315208.html
[5] https://github.com/rapid7/metasploit-framework/pull/11131
[6] https://github.com/rapid7/metasploit-framework/pull/11134
[7] https://github.com/rapid7/metasploit-framework/pull/11136