Sploitus

Exploit for CVE-2020-2551 CVE-2018-2628 CVE-2020-2551

githubexploit · 2020-05-24

Exploit Code

README197 lines
## https://sploitus.com/exploit?id=349CEDEB-9B5B-5769-87D3-D96017DB2BCD
# WebLogic-CVE-2020-2551-To-Internet  
### CVE-2020-2551: POC for use on the Internet  

* Test the POC (can be used for external testing)  
    `python CVE-2020-2551.py [HOST] [IP]`  

* Try modifying the code base to perform remote class loading (failed)  
    `python CVE-2020-TEST.py [HOST] [IP]`  

# A brief discussion on WebLogic CVE-2020-2551 vulnerability & external POC construction  
(Originally published on Safety Guest, [original link](https://www.anquanke.com/post/id/206494))  

### 0x00 Basic concepts  
To understand this vulnerability, some prior knowledge is required, such as CORBA and RMI.  

A simple overview:  
CORBA is a set of technical standards developed by OMG, used for distributed applications. It uses IDL for cross-language support, and communication between clients and servers occurs via the IIOP protocol.  

RMI is another distributed application technology. In JAVA, it can be simplified using JNDI. Communication between clients and servers occurs via the JRMP protocol. However, in WebLogic, RMI uses the T3 protocol. There have been several vulnerabilities related to this before ([link](https://blog.knownsec.com/2018/04/weblogic-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6BC%8F%E6B4%9Ecve-2018-2628%E6BCAB%E8B0%88/)).  

[RMI-IIOP](https://docs.oracle.com/javase/8/docs/technotes/guides/rmi-iiop/tutorial.html#7738) combines the advantages of RMI and CORBA, allowing RMI applications to be deployed via the IIOP protocol.  

The official documentation ([link](https://docs.oracle.com/javase/8/docs/technotes/guides/rmi-iiop/rmi_iiop_pg.html)) also mentions:  
RMI server objects can use the IIOP protocol to communicate with CORBA client objects written in any language.  

### 0x01 RMI-IIOP  
For now, let’s focus on how to create an RMI-IIOP instance.  

Client code can refer to the [“RMI, JNDI, LDAP, JRMP, JMX, JMS in Java” (Part 1)](https://paper.seebug.org/1091/#weblogic-rmi) project’s [test projects](https://github.com/longofo/rmi-jndi-ldap-jrmp-jmx-jms/tree/master/rmi-iiop). You can compile HelloClient and HelloServer yourself, or use the compiled versions from the test projects.  

Start the name server in the command line (built-in in Java):  
```
start orbd -ORBInitialPort 1050
```  

Start HelloServer on the server side and configure remote debugging. For instructions on how to use IDEA for remote debugging, refer to the methods mentioned at the beginning of [this article](https://www.anquanke.com/post/id/201762).  

```
java -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005 HelloServer
```  

Of course, you can also view the results without remote debugging. Just start the program directly:  
```
java HelloServer
```  

Start the client on the command line:  
```
Java HelloClient
```  

At this point, a calculator will appear. If the remote debugging is successful, you can see the following call stack:  
![](https://p1.ssl.qhimg.com/t01229669c9075dbb0a.png)  

The command executed in EvilMessage.readObejct():  
![](https://p4.ssl.qhimg.com/t01bf4871fd59f1812f.png)  

By the way: Information about [installing](https://badcode.cc/2018/05/20/WebLogic-%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95%E7%8E%AF%E5%A2%83%E690%AD%E5BBBA/) and [debugging](https://badcode.cc/2018/05/20/WebLogic-%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95%E7%8E%AF%E5%A2%83%E690%AD%E5BBBA/) in WebLogic…  

So, what about RMI-IIOP in WebLogic? The article [“About RMI-IIOP in Java”](https://paper.seebug.org/1105/) mentions how to utilize RMI-IIOP in WebLogic. Based on that, some research was conducted. [Using WebLogic’s RMI over IIOP](https://www.oreilly.com/library/view/weblogic-the-definitive/059600432X/ch04s04.html) discusses several ways to use RMI-IIOP clients in WebLogic, including:  
1. Independent RMI clients (used with jndi, without using anything from WebLogic)  
2. WebLogic clients  
3. J2EE clients  
4. CORBA/IDL clients

The difference between the first two methods seems to be only in the JNDI_FACTORY setting.

![](https://p4.ssl.qhimg.com/t01bbb532965ba915b4.png)

When studying the exploitation of WebLogic T3 deserialization, I deployed a Helloserver application on WebLogic. There was a sayhello() method that could be used. I tried setting both JNDI_FACTORY calls and successfully called the sayHello() method using the second JNDI_FACTORY.

![](https://p5.ssl.qhimg.com/t01d32c56e876358e09.png)
So, I modified the WebLogic T3 protocol [POC](https://github.com/longofo/rmi-jndi-ldap-jrmp-jmx-jms/blob/master/weblogic-rmi-client/src/main/java/com/longofo/weblogicrmi/Payload1.java). In fact, I just changed RMI to IIOP. It was found that the jtaTransactionManager’s execution chain worked successfully, and a jrmp request was sent to the local jrmplist.

![](https://p3.ssl.qhimg.com/t018f007a1ba77e682f.png)
Let’s look at the traffic. When the remove() method is called, a remove__java_lang_Object request is sent. There is malicious data in the traffic, but the aced magic header was not found.

![](https://p5.ssl.qhimg.com/t01b67a89d59b6b6637.png)
It is speculated that after special parsing on the server side, the data is deserialized. Looking at the call stack, it can be seen that the latter part of the execution chain is very similar to the earlier native RMI-IIOP execution chain. The earlier one was triggered by CDRInputStream.read_value(), while here it is triggered by WebLogic’s IIOPInputStream.read_value(). (The point of read_value was also mentioned in [the 2019 issue](https://i.blackhat.com/eu-19/Wednesday/eu-19-An-Far-Sides-Of-Java-Remote-Protocols.pdf)).

![](https://p5.ssl.qhimg.com/t0112ed8892670dee64.png)
Here, the request will first be processed by clusterableServerRef.invoke(). Depending on the invoker, this invoker.invoke() will be called. Then, Mejb_dj5nps_HomeImpl_WLSkel.invoke() is called because it is “remove”. Therefore, the case 6 branch is entered to call IIOPInputStream.readObject(). In the read_value() method, the IIOPInputStream data is parsed, and deserialization is triggered. This is the POC that utilizes the remove() method.

### 0x02 CVE-2020-2551
Master Lucifaer’s analysis [article](https://lucifaer.com/2020/02/25/WebLogic WLS core component RCE analysis (CVE-2020-2551)?from=timeline&isappinstalled=0#2-2-Weblogic parsing process) mentions exploiting it using the bind() method. This is also a mainstream way of exploitation on the Internet. Let’s look at the call stack.

![](https://p4.ssl.qhimg.com/t010c0953eedd2ce880.png)
Just like before, the request will first be processed by clusterableServerRef.invoke(). Depending on the invoker, this invoker.invoke() will be called. Here, CobraServerRef.invoke() is called. Then, in _NamingContextAnyImplBase._invoke(), since va1 is “bind_any”, the case 0 branch is entered, and IIOPInputStream.read_any() method is called. Later, IIOPInputStream.read_value() will still be called to trigger deserialization. Previously, it was said that the aced magic header was not seen in the traffic because IIOPInputStream has a set of parsing methods. The IIOPInputStream’s hex-value format is as follows, which includes the class name and field information:

![](https://p3.ssl.qhimg.com/t01aff53927b8153309.png)
Ultimately, the readObejct() method of the malicious class will be called.

![](https://p3.ssl.qhimg.com/t014ca19d4d751f0f0b.png)
After looking at the patch, it was found that it is at the same location as the [patch](https://www.tenable.com/security/research/tra-2016-09) for the 2015 T3 deserialization exploitation.

![](https://p3.ssl.qhimg.com/t0181a34517cc5af375.png)
In the testing of [WebLogic CVE-2020-2551 vulnerability analysis](https://paper.seebug.org/1138/), it was found that the class location filtered by CVE-2020-2551 is also in the weblogic.iiop.Utils class.

![](https://p5.ssl.qhimg.com/t013774e3aeaf2d19a0.png)
However, during local testing, when WebLogic 10.3.6 was patched with the 2015 patch, the isBlacklisted() function was not triggered. (But in MsgAbbrevInputStream and InboundMsgAbbrev, isBlacklisted() is called for blacklist verification. It’s strange.)

![](https://p1.ssl.qhimg.com/t0159484ecbe95bae799.png)

The patch for CVE-2020-2551 adds a filtered verifyclassermitted() method in weblogic.iiop.Utils.LoadClass().

![](https://p5.ssl.qhimg.com/t014b82504356994d71.png)

The blocklist filters out malicious classes, including the parent class of JtaTransactionManager, com.bea.core.repackaged.springframework.transaction.support.AbstractPlatformTransactionManager. This class is built into WebLogic and is very dangerous. During the review of the patch, I had an idea: since the verification in line 606 occurs after LoadClass(), wouldn’t it be possible to bypass the defense by executing malicious static code blocks during class loading? This will be discussed later.

### 0x03 Simulating IIOP Protocol for POC

The POC written in JAVA has network issues when tested locally on WebLogic services. It doesn’t work when tested in Docker containers or on external machines. For more information, refer to the analysis article: [How to Solve WebLogic CVE-2020-2551 POC Network Issues](https://xz.aliyun.com/t/7498) and [Discussion on WebLogic-CVE-2020-2551](https://paper.seebug.org/1149/).

Next, let’s debug the POC. You can refer to the previous “remove” example or the [Y4er](https://github.com/Y4er/CVE-2020-2551) project. Two solutions mentioned in the previous articles are:
* Modifying the weblogic.jar package and re-packaging it.
* Simulating the IIOP protocol.

I tried both approaches. After re-packaging WebLogic, I encountered the error java.lang.NoSuchMethodError: weblogic.security.subject.SubjectManager.installCESubjectManager, but no solution was found.

![](https://p0.ssl.qhimg.com/t01842f4e0d86f44b55.png)

So, I tried simulating the IIOP protocol. First, I set breakpoints in the POC for debugging.

![](https://p5.ssl.qhimg.com/t01d9503f5d84a55e54.png)

It was found that when calling EndPointImpl.sendReceive(), two packets were sent and received during the new InitialContext(env) operation.

![](https://p4.ssl.qhimg.com/t018879ca6b321f39fb.png)

The LocateReply contains IOR information. It’s important to understand what IOR is (http://www.pvv.ntnu.no/~ljosa/doc/encycmuclopedia/devenv/corba-index.html). Its function is to provide the host and port required for IIOP communication when RMI-IIOP clients interact with server objects using the IIOP protocol. The Object_key in the red box is used to distinguish between different server objects.

![](https://p3.ssl.qhimg.com/t01fa94e9770504478f.png)

When simulating the IIOP protocol, it’s crucial to pay attention to the Object_key. The host and IP actually don’t matter. When testing initially, I simply replayed all the packets again. When sending resolve_any, the location forward was returned.

![](https://p5.ssl.qhimg.com/t01cf7a0af53d9d4116.png)

The [official documentation](https://docs.oracle.com/cd/E13211_01/wle/wle42/corba/giop.pdf) states that location forward indicates that the Object_key changes. The Object_key returned by different requests may differ (here, the Object_key refers to the key address in the data packet). As mentioned before, this Object_key is used to distinguish which object to communicate with using the IIOP protocol. This value needs to be dynamically obtained from the LocateReply.

![](https://p4.ssl.qhimg.com/t01f4568e843c72df80.png)

Finally, instead of simulating the remove method, I simulated the IIOP request sent by the bind() method. Since there are fewer requests, let’s look at the normal data packets used locally.

![](https://p2.ssl.qhimg.com/t01b26261d0b5e8a492.png)

Send LocateRequest, receive data, and use regular expressions to extract the key address from the LocateReply.

![](https://p2.ssl.qhimg.com/t01058ed9f3c252983f.png)

Manually set the address of the malicious jrmp server (rmi://...), send bind_any packets every 1 second. Since the jrmp requests in this exploitation chain don’t use DGCClient, they aren’t affected by [JEP290](https://mogwailabs.de/blog/2019/03/attacking-java-rmi-services-after-jep-290/). Exploitation is possible through jrmplisten.

![](https://p5.ssl.qhimg.com/t014fef0f53246e55cf.png)

POC was successfully tested in a Docker environment. The SSRF environment [vulhub](https://github.com/vulhub/vulhub/tree/master/weblogic/ssrf) can be used. Set the IP to the host machine; Docker successfully retrieves the JRMp request from the host machine. The specific code is available on [GitHub](https://github.com/Dido1960/Weblogic-CVE-2020-2551-To-Internet/blob/master/CVE-2020-2551.py).

![![](https://p4.ssl.qhimg.com/t012799157906eb1652.png)]

### 0x04 Verification of Hypotheses

As mentioned earlier, there’s an idea of using the code base to load remote code and bypass detections. Students who have studied [JNDI attacks](https://www.veracode.com/blog/research/exploiting-jndi-injections-java) should know that the code base can be used to specify the location of remote classes. If the code base is controllable and the program allows remote class loading, then malicious classes can be loaded to execute malicious code in static code blocks. From the code, it can be seen that the second parameter of weblogic.iiop.Utils.lodaClass() represents the code base. This parameter is read in the IIOPInputStream.read_value() method, which is the var8 parameter. Line 1659 calls readIndirectingRepositoryId(var8), and ultimately, weblogic.iiop.Utils.lodaClass() will be called. To execute lines 1644 and 1659, the value of var4 must be 3.

![![](https://p5.ssl.qhimg.com/t01160d6c37735efe9f.png)]

The call stack from readIndirectingRepositoryId to getClassFromId will eventually execute line 304: loadclass().

![https://p5.ssl.qhimg.com/t019cd344213124a196.png]

Let’s look at the bind_any packet. It is actually composed of GIOP Header and GIOP Request. GIOP Request includes key address (the same as in LocateteReply), ServiceContextList, and stub_data. The value of var4 is\x7f\xff\xff\x02 in stub_data. Therefore, (va4r & 1) = 0, va4 & 6) = 2, so the code base isn’t set for line 1644.

![https://p5.ssl.qhimg.com/t014ab4c0dba18c4fe0.png]

We can modify the first box to\x00\x00\x00\x03 and add information about the length and value of the code base in the second box. The specific code is available on [GitHub](https://github.com/Dido1960/Weblogic-CVE-2020-2551-To-Internet/blob/master/CVE-2020-TEST.py). It can be seen that an alignment operation is also performed. This is a potential issue because before reading the next class information, it checks whether the position of the next byte is a multiple of 4. If not, some bytes will be ignored. For example, if the position of the next byte is 1, then 3 bytes will be ignored, and reading starts directly from the 4th byte. This position is relative to the entire bind_any packet. If the byte is not a multiple of 4, a zero is added.

![https://p2.ssl.qhimg.com/t017effa14933cb15f1.png]

There’s another issue. Looking at the call stack from readIndirectingRepositoryId to getClassFromId, the findClassInfo() function is involved. Here, if a class has already been loaded, the class ID information will be saved. When findClassInfo() is called, the class information is returned directly, and the weblogic.iiop.Utils.getClassFromID() function isn’t executed.

![https://p2.ssl.qhimg.com/t011d7d0b9164fd3d9d.png]

So, during testing, the class name needs to be changed each time.

![https://p4.ssl.qhimg.com/t0163c76b9f9d201aeb.png]

In any case, finally, it was successful to simulate the IIOP protocol by modifying the code base value and executing the weblogic.iiop.Utils.getClassFromID() function. Unfortunately, when trying to obtain RMIURLClassFinder, NULL was returned. The RMIEnvironment.getEnvironment().isNetworkClassLoadingEnabled() function returned false.

![https://p5.ssl.qhimg.com/t0164e10b369c405a5b.png]

The reason is that the _NetworkClassLoadingEnable parameter in ServerMBeanImpl has a value of False.

![https://p0.ssl.qhimg.com/t016ddf4a9c673e8717.png]

We want to see in which weblogic configuration file this parameter is set, but it wasn’t found. ### Summary

Actually, during the process of learning this vulnerability, it was discovered that a lot of prior knowledge is required, such as Java deserialization, RMI, JNDI, etc. For related learning, you can refer to this [article column](https://www.anquanke.com/subject/id/206001). Although the attempt to exploit by modifying the code base failed, still, a lot of knowledge was gained.

[source-iocs-preserved url=https://badcode.cc/2018/05/20/WebLogic-%E5%8A%A8%E6%80%81%E8%B0%83%E8%AF%95%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA/,https://blog.knownsec.com/2018/04/weblogic-%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9Ecve-2018-2628%E6%BC%AB%E8%B0%88/,https://p1.ssl.qhimg.com/t0159484bec95bae799.png method=iiop.Utils.LoadClass(),iiop.Utils.getClassFromID(),iiop.Utils.getClassFromId(),iiop.Utils.lodaClass()]