On April 17, Oracle released the quarterly Critical Patch Update (CPU) advisory. Among the 254 new security fixes, the CPU also contained a fix for the critical WebLogic server vulnerability CVE-2018-2628. This is a Java deserialization vulnerability in the core components of the WebLogic server and, more specifically, it affects the T3 proprietary protocol.
According to the advisory, the CVE-2018-2628 is a high-risk vulnerability that scores 9.8 in the CVSS v3 system. This score is typical for RCE vulnerabilities that allow attackers to fully compromise a system by remotely executing code without authentication. The vulnerability was reported by Liao Xinxi of NSFOCUS Security Team as well as a researcher by the name loopx9.
On April 18, multiple users on GitHub released proof of concept (POC) exploit code against this flaw. Soon after, reports indicated increased scanning activity for vulnerable, unpatched servers.
According to Oracle, the following WebLogic server releases are affected:
- 10.3.6.0
- 12.1.3.0
- 12.2.1.2
- 12.2.1.3
In order to apply Oracle’s CPU, WebLogic customers must download the corresponding PSU updates from Oracle’s support site and install the patch using Smart Update or OPatch. The following PSUs correspond to Oracle’s April 2018 CPU:
- PSU 10.3.6.0.180417
- PSU 12.1.3.0.180417
- PSU 12.2.1.2.180417
- PSU 12.2.1.3.180417
For more information please consult Doc ID 1470197.1 from the Oracle support site.
This is not the first time that WebLogic was found to be vulnerable to a deserialization vulnerability. In November 2015, Oracle fixed CVE-2015-4852, another Java deserialization flaw in WebLogic. In October 2017, Oracle fixed CVE-2017-10271, a XML deserialization vulnerability which attackers have been exploiting to download cryptocurrency miners in victim systems.
Despite the fact that the April CPU contained a fix for the newly discovered CVE-2018-2628, researchers found ways around this patch. The protection bypass was inevitable because Oracle patched WebLogic by implementing a blacklist.
Using a blacklist approach has certain benefits such as easy configuration and is less likely to cause functional issues. However, blacklisting is a terrible security strategy. A blacklist is bound to be incomplete (see CWE-184) and requires constant maintenance. When adopting a blacklist approach for protection, developers are playing the Whac-a-Mole game and are committing to maintain the blacklist for every known exploit in order to be effective at scale.
Technical Analysis
Let’s see how Oracle’s blacklist works for CVE-2015-4852 and CVE-2018-2628.
The following packages are blacklisted and are not allowed to be deserialized:
- org.apache.commons.collections.functors
- com.sun.org.apache.xalan.internal.xsltc.trax
- javassist
Initially, as a protection to CVE-2015-4852, only the following classes were blacklisted:
- org.codehaus.groovy.runtime.ConvertedClosure
- org.codehaus.groovy.runtime.ConversionHandler
- org.codehaus.groovy.runtime.MethodClosure
In subsequent releases, this blacklist was extended to disallow these classes as well:
- org.springframework.transaction.support.AbstractPlatformTransactionManager
- sun.rmi.server.UnicastRef
Note that these are the packages and classes that are blacklisted by default. WebLogic administrators have the option to extend these lists.
These packages and classes were blacklisted because they are used as gadgets by known gadget chains (exploits). Blacklisting these gadgets allows Oracle to protect WebLogic against known POC exploits but this action does not remediate the issue, but does avoid re-architecting the whole component.
Sophisticated attackers can bypass the blacklist by creating gadget chains with different sets of gadgets. One technique exploit authors have in their arsenal is the use of dynamic proxies.
Specifically for CVE-2018-2628, Oracle added one more protection based on a blacklist approach. This time, a specific blacklist was added at the deserialization of InboundMsgAbbrev instances that terminates the process if the instance implements the java.rmi.registry.Registry interface.
In other words, this protection disallows the use of exploits (gadget chains) that use dynamic proxies that implement the Registry interface in place of a legitimate InboundMsgAbbrev instance.
The use of the dynamic proxy can be seen in the following stack trace that shows the RCE attack in action:
java.lang.Runtime.exec()
sun.reflect.NativeMethodAccessorImpl.invoke()
sun.reflect.DelegatingMethodAccessorImpl.invoke()
java.lang.reflect.Method.invoke()
org.apache.commons.collections.functors.InvokerTransformer.transform()
org.apache.commons.collections.functors.ChainedTransformer.transform()
org.apache.commons.collections.map.LazyMap.get()
sun.reflect.annotation.AnnotationInvocationHandler.invoke()
$Proxy56.entrySet()
sun.reflect.annotation.AnnotationInvocationHandler.readObject()
sun.reflect.NativeMethodAccessorImpl.invoke()
sun.reflect.DelegatingMethodAccessorImpl.invoke()
java.lang.reflect.Method.invoke()
java.io.ObjectStreamClass.invokeReadObject()
java.io.ObjectInputStream.readSerialData()
java.io.ObjectInputStream.readOrdinaryObject()
java.io.ObjectInputStream.defaultReadFields()
java.io.ObjectInputStream.readSerialData()
java.io.ObjectInputStream.readOrdinaryObject()
java.io.ObjectInputStream.readObject()
sun.rmi.transport.StreamRemoteCall.executeCall()
sun.rmi.server.UnicastRef.invoke()
sun.rmi.transport.DGCImpl_Stub.dirty()
sun.rmi.transport.DGCClient$EndpointEntry.makeDirtyCall()
sun.rmi.transport.DGCClient$EndpointEntry.access$1600()
sun.rmi.transport.DGCClient$EndpointEntry$RenewCleanThread.run()
java.lang.Thread.run()
java.lang.Thread.begin()
java.lang.Thread.invokeRun()
java.lang.Thread$ThreadHandler.invokeRun()
The above stack trace was captured in a POC attack that uses the JRMPClient and CommonsCollections1 ysoserial payloads on a Java 6u21 and WebLogic 10.3.6 system.
In a vulnerable system, WebLogic administrators can identify possible Java deserialization attacks if similar exceptions are seen in their WebLogic logs:
- java.lang.ClassCastException: $Proxy56 cannot be cast to weblogic.rjvm.ClassTableEntr
- java.io.InvalidObjectException: Unauthorized proxy deserialization
The problem with blacklisting java.rmi.registry.Registry interface from the deserialization of the InboundMsgAbbrev instance is that attackers can simply replace the blacklisted interface with another interface. Deserialization gadget chains are like words in a Scrabble game. If a particular word cannot be used, another word can potentially be used to achieve the same goal.
On April 29, several security researchers, such as @pyn3rd, claimed that they have successfully bypassed WebLogic’s Registry interface blacklisting by using different gadgets.
Remediation
As of now, Oracle has not released another patch update for this CVE. Despite the fact that researchers claim to have bypassed Oracle’s April CPU fix for CVE-2018-2628, users should by no means be discouraged from installing the April CPU.
One way to harden the system against gadget chains is to use the latest JDK. The publicly available RCE POC exploits depend on older versions of the JDK. Upgrading the JDK is not a complete remediation of the issue but it is highly advisable to do since it deactivates the known POC exploits. Based on experiments, the minimum JDK versions that should be used are the ones that were released as part of the October 2015 CPU; namely: 6u111, 7u91, and 8u65. Note that it is recommended to install the JDK of the latest April 2018 CPU.
Another reason to upgrade the latest JDK is because it will allow you to use the JEP-290 Serialization Filtering mechanism. Using the process-wide global filter administrators can define their own whitelists for deserialization. WebLogic also has its own system properties that allow users to specify their own filters. Consult the Oracle documentation on how to set up the weblogic.oif.serialFilter property.
Security administrators could even consider blocking or filtering incoming connections to WebLogic’s admin port, which by default is 7001.
The use of a Web Application Firewall could also be helpful but beware of the false positives since most of these solutions use pattern and signature matching. These heuristic approaches are never fully accurate and, in effect, they simply offer another way of performing filtering (blacklisting and/or whitelisting). This type of filtering is even less accurate compared to the JEP-290 Serialization Filtering mechanism of the JRE.
Waratek’s approach offers accurate protection which does not depend on filtering known bad classes (blacklisting) or known legitimate classes (whitelisting). Using a proprietary technology based on JRE virtualization, the JRE is dynamically compartmentalized and unnecessary privileges during deserialization are de-escalated. This way Waratek achieves protection regardless of what the gadget chain is, what the vulnerable component is, and what the entry point is. This solution protects against known and zero-day exploits and works like a light-switch as it requires no profiling of the application, no source code changes and no system restart. Additionally, Waratek Patch users have the option to use a virtual patch that hardens the JRE, guards code execution, and protects against any exploit that performs process forking.
Author:
Apostolos Giannakidis
Security Architect
Apostolos drives the research and the design of the security features of Waratek’s Runtime Protection. Before starting his journey in Waratek in 2014, Apostolos worked in Oracle for 2 years focusing on Destructive Testing on the whole technology stack of Oracle and on Security Testing of the Solaris operating system. Apostolos has more than 10 years of experience in the software industry and holds an MSc in Computer Science from the University of Birmingham.