Proof of concept for CVE-2025-21535
Contents:
Recently a professor in my college released a challenge,
Create a poc for CVE-2025-21535 and win 5 grands
The offer sounds too good so naturally I am going to give it a try. What I am going to show here is execution of a command in a server that an unauthenticated user shoudn’t have been able to. Read along to find out.
# What is the CVE about
In oracle’s WebLogic servers
version 12.2.1.4.0 and 14.1.1.0.0 lies a RCE (Remote Code Execution) vulnerability. This can be exploited by a specially crafted message sent via their proprietary T3/IIOP protocol
to their admin servers.
Two major things to unpack here
- What are WebLogic servers?
- What is the T3/IIOP protocol?
WebLogic
servers are simple servers that enable an admin to monitor a bunch of client machines. When setting it up, it asks for all the different clients the organisation has, whether to put them in a cluster or not and more. For our purposes, it is simply a server that enables special protocols like T3 to talk to it.
The thing here being that WebLogic servers are usually made to host JAVA applications
and hence most of the code written will be JAVA and I have absolutely no idea about JAVA (say hello to AI).
The T3
protocol was something developed under BEA Systems (which was later acquired by Oracle) to establish communications with a server.
Lets understand T3 communications in details
# Client Initialization
The client (e.g., our Java application) initializes a connection to the WebLogic server using a T3 URL
# Connection Establishment
The client uses socket communication to connect to the WebLogic server over the specified port. T3 uses:
- TCP/IP for reliable data transmission.
- Custom binary encoding (tag-length-value format) for efficient data transfer.
During this phase:
The client sends a handshake to establish compatibility and version negotiation. The server responds, confirming the connection.
# Session Creation
Once the connection is established, the server creates a persistent session for the client. This session is used to track stateful interactions between the client and the server.
# Request-Response Exchange
The client sends requests to the server, such as:
- JNDI lookups: Retrieving resources like DataSources, JMS connections, EJBs, etc
- RMI invocations: Invoking remote methods on server-side objects.
- Deployment commands: Deploying or managing applications.
The server processes the request and sends a response back to the client. The communication uses a tag-length-value format to efficiently encode data:
- Tag: Identifies the type of data or command.
- Length: Specifies the size of the data.
- Value: Contains the actual data or payload.
What about the IIOP
protocol? I didn’t really care for this one cause I figured T3 is probably the more important one. (I might be severely wrong so keeping this path open…)
# Setup procedure
- Installing pre-reqs
The first step
is establishing a vulnerable oracle WebLogic server to test our attacks out. The prerequesites for doing this can be installed using this
Use this link: oracle java archive to download JAVA version 8, linux x64 tarred and gunzipped (unless if you’re using windows, in which case good luck).
I have uses 202
cause that was the version I got, make sure you use your own.
Check the java version, if it runs and shows the correct one, then you’re good to go. Set it as default,
Use bashrc
if you use bash and not zsh
.
- Install WebLogic 12.2.1.4.0
The second step is installing the WebLogic server. For this
- Install an oracle account
- Download the version 12.2.1.4.0 generic version
- Unzip the file and install using JAVA
So, once you unzip you will see a .jar
file. This is the installer for the server, and we will run this using
This will run a GUI, and it makes it much easier to setup. The few important things to keep in mind are:
- Template: simple webserver
- Advance feature: All of them
- Don’t enable SSL (not really needed)
- No need for managed servers or clusters. Do not add
server templates
too. (this is different from the initial template we discussed) Unix machine
: yes, add a unix machine. Not enabling GID or UID, listen address is localhost and node manager is 5556.- Assigning the server to the node manager UNIX machine. Not setting up virtual targets.
After all this, you will be given a URL. That’s where your server will go. However, we’ll use localhost
itself.
- Running the server
Run the following commands to run the server locally.
I have used the name vuln_domain, yours may be different, so ensure you use the correct name. After running the server, head to
http://127.0.0.1:7001/console
This will deploy your application.
Note that T3 protocol is enabled by default
# Testing the server
The idea is to use T3 protocol to communicate with the WebLogic server and see if that works. Running the below code, it ensures that T3 is properly setup and it runs
;
;
;
;
Save the above as WebLogicT3Client.java
. Then run the below command to create the necessary class
.
This should result in the creation of WebLogicT3Client.class
. Then we execute the code using
Also, change purge
to whatever your username is. (Mine is purge cause purge means cool)
# The exploit
Alright now that the server is up and running, we need to find the exploit. According to the official documentation for the CVE in nvd.nist, we find that the weakness enumeration
is CWE-306
.
CWE-306
: The product does not perform any authentication for functionality that requires a provable user identity or consumes a significant amount of resources.
or it might mean this as well.
Exposing critical functionality essentially provides an attacker with the privilege level of that functionality. The consequences will depend on the associated functionality, but they can range from reading or modifying sensitive data, accessing administrative or other privileged functionality, or possibly even executing arbitrary code.
But what does this means for us? It can be either of the two things
- Some functionality that only the admin should be doing, could be performed by an unauthenticated user as well
- Something related to JAVA serialisation vulnerability
I don’t want to look at JAVA serialisation objects yet without first checking the first option extensively. We know there are 3 major things that can be done by an admin in the WebLogic servers,
- JNDI lookups
- RMI invocations
- Deployment commands
So, I am gonna first test if I can retrieve or query these using non-admin privileges. If I can, well, thats bad.
Trying to access a random resource with and without credentials
Checking for RMI
;
;
;
;
;
;
;
Apparently this can help in figuring out if RMI is running on your server. Turns out we can run this without admin credentials as well. This is how my security page looked like when I ran this without admin credentials
Yeah, got the same values irrespective of credentials.
Name: mejbmejb_jarMejb_EO, Class: weblogic.rmi.cluster.ClusterableRemoteObject
Name: jmx, Class: weblogic.jndi.internal.ServerNamingNode
Name: javax, Class: weblogic.jndi.internal.ServerNamingNode
Name: weblogic, Class: weblogic.jndi.internal.ServerNamingNode
Name: __WL_GlobalJavaApp, Class: weblogic.jndi.internal.ServerNamingNode
Name: ejb, Class: weblogic.jndi.internal.ServerNamingNode
Name: java:global, Class: weblogic.jndi.internal.ServerNamingNode
Name: eis, Class: weblogic.jndi.internal.ServerNamingNode
Name: _WL_internal_JaWproFX2ApBWuB5SHvOrubDEm75UA2k8avPUe04e2Gsr6oyE6hh5WDY6n7sT2SP, Class: weblogic.jndi.internal.ServerNamingNode
These is the JNDI tree (the Java Naming and Directory Interface tree) that lists the different resources or nodes in the server that can be access via RMI, that is, invoke some methods on the server-side. This is pretty cool honestly.
If we analyse each entry in this tree to get a better feel for things
mejbmejb_jarMejb_EO
: This is an EJB (Enterprise Java Bean). It is a server-side software element that summarizes business logic of an application. Thus, its presence means that if we invoke this node using RMI we can access the business side logic.jmx
: This stands for Java Management Extensions, that is used to manage and monitor applications, system objects, hardware peripheral devices and service-oriented networks. All the examples listed come under the umbrella ofmbeans
.javax
: Javax is a prefix used in Java to denote a set of standard extension packages that provide additional functionality for Java applications. It stands for Java Extension and is commonly used for application programming interfaces (APIs) related to enterprise, messaging, and other areas (straight from lenovo’s official page).
The javax
and jmx
node is the most low-level/system-level node there is. From what I understand, if this node is compromised, then a lot of things can happen.
weblogic
: This is the top-level JNDI node for WebLogic-specific resources. This acts as a container for internal WebLogic services and objects.
This may expose a lot of information as well.
The next few aren’t that important probably, except perhaps eis
eis
: An Enterprise Information System is any kind of information system which improves the functions of enterprise business processes by integration. This means typically offering high quality of service, dealing with large volumes of data and capable of supporting some large and possibly complex organization or enterprise. An EIS must be able to be used by all parts and all levels of an enterprise. (directly from wikipedia)
Basically, it might be holding access to a database
…
# Interacting with the nodes
FIRSTLY FIGURE WHY THESE RMI SERVICES ARE RUNNING IF I NEVER SET THEM UP?
- Perform a lookup
For example,
Object resource ;
- Explore sub-nodes
nodes like jmx, javax, weblogic, ejb, and others act as containers. We can explore their contents programmatically by listing their sub-nodes:
NamingEnumeration subNodes ;
while
I will try this tomorrow. I am looking for more information weblogic
, jmx
, javax
and eis
. These seem interesting as hell!
Its like 2am, I have classes from 8, gotta sleep. Goodnight.
# Morning 9 am
I noticed that restrictive JMX policies
are enabled under the advanced security tab.
This means restrictive policies will be used for JMX authorisation. I am not sure what these “restrictive policies” look like, so I can’t comment on what this means for us. But since this was enabled by default I will not toggle this (to replicate that dumb system admin who doesn’t change default configurations)
Let’s perform lookups for each node.
;
;
;
;
;
;
;
Alright, few things came up. This was the result,
Connected to WebLogic. Performing lookups…
### Listing entries under: javax
Failed to list JNDI names under javax: User <anonymous> does not have permission on javax to perform list operation.
### Listing entries under: jmx
Name: runtime, Class: weblogic.jndi.internal.NonListableRef
-> Failed to lookup runtime: jmx/runtime cannot be looked up using a remote JNDI context. Use JSR160 interface to use JMX remotely or use a local JNDI context to look up the local MBeanServer.
Name: domainRuntime, Class: weblogic.jndi.internal.NonListableRef
-> Failed to lookup domainRuntime: jmx/domainRuntime cannot be looked up using a remote JNDI context. Use JSR160 interface to use JMX remotely or use a local JNDI context to look up the local MBeanServer.
Name: edit, Class: weblogic.jndi.internal.NonListableRef
-> Failed to lookup edit: jmx/edit cannot be looked up using a remote JNDI context. Use JSR160 interface to use JMX remotely or use a local JNDI context to look up the local MBeanServer.
### Listing entries under: weblogic
Failed to list JNDI names under weblogic: User <anonymous> does not have permission on weblogic to perform list operation.
### Listing entries under: eis
Name: jms, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (eis.jms)
Apparently only eis
lookup was successful as an anonymous user. If I do this with proper credentials, this is what I get,
Connected to WebLogic. Performing lookups...
### Listing entries under: javax
Name: jms, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (javax.jms)
Name: transaction, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (javax.transaction)
### Listing entries under: jmx
Name: runtime, Class: weblogic.jndi.internal.NonListableRef
-> Failed to lookup runtime: jmx/runtime cannot be looked up using a remote JNDI context. Use JSR160 interface to use JMX remotely or use a local JNDI context to look up the local MBeanServer.
Name: domainRuntime, Class: weblogic.jndi.internal.NonListableRef
-> Failed to lookup domainRuntime: jmx/domainRuntime cannot be looked up using a remote JNDI context. Use JSR160 interface to use JMX remotely or use a local JNDI context to look up the local MBeanServer.
Name: edit, Class: weblogic.jndi.internal.NonListableRef
-> Failed to lookup edit: jmx/edit cannot be looked up using a remote JNDI context. Use JSR160 interface to use JMX remotely or use a local JNDI context to look up the local MBeanServer.
### Listing entries under: weblogic
Name: cluster, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.cluster)
Name: fileSystem, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.fileSystem)
Name: partitionId, Class: java.lang.String
-> Lookup successful: 0
Name: rmi, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.rmi)
Name: messaging, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.messaging)
Name: jms, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.jms)
Name: partitionName, Class: java.lang.String
-> Lookup successful: DOMAIN
Name: common, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.common)
Name: jmx, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.jmx)
Name: management, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.management)
Name: logging, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.logging)
Name: MessageInterception, Class: weblogic.messaging.interception.internal.InterceptionServiceImpl
-> Failed to lookup MessageInterception: weblogic.messaging.interception.internal.InterceptionServiceImpl
Name: transaction, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (weblogic.transaction)
### Listing entries under: eis
Name: jms, Class: weblogic.jndi.internal.ServerNamingNode
-> Lookup successful: WLContext (eis.jms)
I realised I completely missed this object mejbmejb_jarMejb_EO
. This EJB is likely a RMI accessible MBean server node. So, it might help us get remote access to WebLogic MBeans for JMX monitioring and management.
Notice that when we tries to lookup under JMX, we got this error
Failed to lookup runtime: jmx/runtime cannot be looked up using a remote JNDI context. Use JSR160 interface to use JMX remotely or use a local JNDI context to look up the local MBeanServer.
This happened regardless of admin access (as the error statement properly mentions, its not a privilege issue). So, let’s try to hook up mejbmejb_jarMejb_EO
and see if we get access to the local MBeans server.
okay this won’t work cause I probably don’t have an MBeans
server running. Got an error. I will continue working on EIS cause that might be more useful… (if this doesn’t work I shall try jmx
properly).
Alight I ran an EIS check to figure out what all methods exist so that I can look it up. It is all being done without admin creds (the resuts are symmetric either way)
;
;
;
;
;
;
;
;
What I found is, that EIS is linked NOT to a JMS object like QueueConnectionFactory
, but rather it is a JNDI naming subtext (a node in our tree). What we should then do is retreive the names and objects inside of eis.jms
.
I looked inside eis.jms to find a subdirectory named internal
. Looking inside that I found this
Found: WLSConnectionFactoryJNDINoTX of type javax.naming.Reference
Found: WLSConnectionFactoryJNDIXA of type javax.naming.Reference
There are naming references, that is not actual JMS objects but sort of like a pointer to it. We now need to get the actual JMS objects. Alright, I tried to access a JMS connection factory using code but got this error (irrespective of credentials)
Connected to WebLogic. Performing lookups...
Found: WLSConnectionFactoryJNDINoTX of type javax.naming.Reference
Found: WLSConnectionFactoryJNDIXA of type javax.naming.Reference
javax.naming.NamingException: [Connector:199318]It is not supported to access connector resource outside server vuln_domain/VulnerableAdmin which defines the resource, current server is remote client.
at weblogic.connector.deploy.JNDIHandler.getObjectInstance(JNDIHandler.java:644)
at javax.naming.spi.NamingManager.getObjectInstance(NamingManager.java:321)
at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:451)
at weblogic.jndi.internal.WLContextImpl.lookup(WLContextImpl.java:435)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at testingEIS.main(testingEIS.java:34)
I think the issue is simply that I have no JMS resources even running!
I will look into the different defined actions a little more. Then finally look into JAVA object serialisation and deserialisation errors.
# Deploying a rouge RMI object
InitialContext ctx ;
ctx.;