- 类别:javanative 别名:— 优先级:—
- 作者:—
- 依赖:
com.alibaba:druid:1.2.16
把内层「JDBC URL」子链的产物包装进一个 com.alibaba.druid.pool.DruidDataSource 连接池对象。当上游的 getter 触发型 gadget(Fastjson / Jackson / Rome 等)在反序列化时调用该对象的 getConnection()(对应属性名 connection)时,Druid 连接池会用预置的 url 真正建立 JDBC 连接,从而把控制权交给内层的恶意 JDBC URL(H2 RCE、MySQL 任意文件读取、Derby 命令执行等)。
本 gadget 本身不是字节码 sink,也不是反序列化入口,而是「getter 段」与「JDBC URL 段」之间的桥接/适配环:对上通过 getConnection getter 被触发,对下消费一段 JDBC URL 利用链。
- 入口
tags:DataSourceChains—— 声明自己属于「DataSource 触发」这一类,供上游 getter 型 gadget(nextTags含DataSourceChains者,如 Fastjson、Jackson、Rome 系列、DWrap)衔接。Getter—— 表明本环的触发方式是「被调用 getter」,即靠getConnection()这个 getter 被反射/JSON 反序列化调用来启动。NotForJavaSerializable—— 关键约束:DruidDataSource无法安全地走 Java 原生序列化(其内部字段包含不可序列化状态),因此本环只适用于「对象被现场 new 出来再调用 getter」的场景(Fastjson/Jackson 等 JSON 反序列化、或经DWrap动态代理包裹),不能直接嵌入纯 JavareadObject链。对比同目录的 DruidDataSource(用DruidXADataSource)未标此 tag。END—— 在「getter 段」视角下,本环是该段的收口:getter 被触发后即进入 Druid 内部逻辑,无需再往外包一层 getter 载体。注意END与nextTags并存并不矛盾——END指它是 getter 触发链的终点,nextTags指它仍要向内接一段 JDBC URL 子链。
- 衔接
nextTags:JdbcUrlChains—— 之后(内层)接一个「只需一个 JDBC URL 字符串」的利用链(如 H2JavaJdbc1、MysqlJdbc、PostgreSqlJdbc、SqliteJdbc等)。JdbcUrlWithSQLChains—— 之后接一个「除 URL 外还要附带初始化 SQL 列表」的利用链(如 DerbyCommandJdbc、Hsqldb*Jdbc系列);这些 SQL 由 Druid 的connectionInitSqls在建连后自动执行。
excludes:无。
本类直接 implements Gadget,无基类。核心是两段:getObject(构造 Druid 连接池对象)与 invoke(取内层 JDBC URL、写入 context、并调用 getObject)。
private final String getterMethodName = "getConnection";
private final String getterPropertyName = "connection";
public Object getObject(String jdbcUrl, List<String> sqlList) throws Exception {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setLogWriter(null);
dataSource.setStatLogger(null);
dataSource.setUrl(jdbcUrl); // ① 恶意 JDBC URL
dataSource.setInitialSize(1); // ② 初始连接数 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;
}逐段说明:
- ①
setUrl(jdbcUrl):把内层子链产出的恶意 JDBC URL 塞进连接池。真正的利用发生在建连时——Druid 会按 URL 前缀选择/加载 JDBC 驱动并连接,H2/Derby/MySQL 等驱动各自的「URL 特性」即是漏洞面(H2 的INIT=RUNSCRIPT、MySQL 的allowLoadLocalInfile读文件、Derby 的create=true加载类等)。 - ②
setInitialSize(1)+setLogWriter(null)/setStatLogger(null):只需最小化配置让连接池能被初始化并触发一次建连;关闭日志/统计避免噪声与额外依赖。 - ③ 反射置空
transactionHistogram/statLogger/initedLatch:这些是 Druid 内部的监控直方图、统计日志器与初始化闭锁字段。它们默认引用了在攻击者环境中不存在或会抛异常的对象;置空后可让对象在受害端顺利完成getConnection内部的初始化流程(init())而不因这些辅助字段报错。这也是本环被标NotForJavaSerializable的根因——对象状态是手工「削」出来的,不具备可序列化完整性。 - ④
connectionInitSqls = sqlList:Druid 支持「连接初始化 SQL」,在每次物理建连后立即执行列表中的 SQL。这正是JdbcUrlWithSQLChains(Derby/Hsqldb 命令执行类)依赖的机制:URL 负责挂载/加载,SQL 负责触发存储过程或 RCE。
@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); // 告知上游:目标类型是 DataSource
context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, "getConnection"); // 告知上游:要触发的方法
context.put(ContextTag.GETTER_PARAM_NAME_KEY, "connection"); // 告知上游:getter 属性名
String jdbcUrl = "";
List<String> sqlList = new ArrayList<String>();
if (jdbcObj instanceof String) { // 情形 A:内层直接给 URL 字符串
jdbcUrl = (String)jdbcObj;
} else if (jdbcObj instanceof Map) { // 情形 B:内层给 URL + SQL 列表
Map jdbcMap = (Map)jdbcObj;
jdbcUrl = (String)jdbcMap.get(ContextTag.JDBC_URL);
sqlList = (List)jdbcMap.get(ContextTag.JDBC_URL_SQL_LIST);
}
return this.getObject(jdbcUrl, sqlList);
}invoke 体现了链「由内向外」构建的原则:
chain.doCreate(context)先让内层(JDBC URL 段)产出结果。约定两种形态:单纯String(对应JdbcUrlChains),或携带JDBC_URL与JDBC_URL_SQL_LIST两键的Map(对应JdbcUrlWithSQLChains)。- 三个
context.put是与上游 getter 型 gadget 的「握手」:把「要触发的父类型 =DataSource、方法 =getConnection、属性名 =connection」写入共享GadgetContext。上游 getter 载体(如 Fastjson/Jackson 的属性求值、或 CommonsBeanutils 家族通过GETTER_PARAM_NAME_KEY读取属性名)据此在反序列化时精确地调用getConnection(),而不是盲目遍历所有 getter。 - 最后调用
getObject返回构造好的DruidDataSource实例,交给上游继续外包。
触发时序(反序列化端,自外向内执行):上游 getter gadget 触发 DruidDataSource.getConnection() → Druid init() 用 url 建立物理连接 → 加载对应 JDBC 驱动、解析 URL 恶意特性 →(若有)执行 connectionInitSqls → 完成 RCE / 文件读取 / 类加载。
本类无 @Param。可配内容全部来自内层 JDBC URL 子链:jdbcUrl 与 sqlList 由 JdbcUrlChains / JdbcUrlWithSQLChains 段的 gadget 提供,本环仅做转发与包装。
- 依赖
com.alibaba:druid:1.2.16(源码基于该版反编译)。原理依赖的是 Druid 通用的「连接池初始化即建连」与connectionInitSqls行为,跨小版本大体通用;反射置空的内部字段名(transactionHistogram/statLogger/initedLatch/connectionInitSqls)与具体版本的私有字段实现绑定,换版本需核对字段是否存在。 - 只走 getter 触发链:
NotForJavaSerializable决定它不能进纯 Java 原生序列化链,典型入口是 Fastjson/Jackson 这类「对 JSON 反序列化目标对象逐属性调用 getter」的场景;也可经 DWrap 用 SpringJdkDynamicAopProxy包裹以规避 Jackson 直接调用 DataSource 的不稳定问题。 - 实际杀伤来自内层 URL/SQL:本环不产出字节码,最终效果取决于所选 JDBC 方言 gadget——H2(内存库
RUNSCRIPT/别名函数 RCE)、Derby(connectionInitSqls触发命令/类加载)、MySQL(恶意服务端读文件/反序列化)、Postgres/Sqlite 等。 - 与 DruidDataSource 的区别:后者用
com.alibaba.druid.pool.xa.DruidXADataSource(XA 数据源),逻辑与字段置空完全一致,但未标NotForJavaSerializable;两者可视为同一利用的「普通池 / XA 池」双变体,按目标环境可加载哪个类择一。
usedInChains 为空——自由构件,未被 default-chains.yaml 中的 51 条预设链直接固定引用。但它是「Druid Jdbc」类利用的核心桥接环,可按 tag/nextTag 自由拼装,典型形态:
[<getter 载体: Fastjson/Jackson/...>, DruidDataSource2, <JDBC URL 段: H2JavaJdbc1 / MysqlJdbc / DerbyCommandJdbc / ...>]
(参考同族的 H2JavaExecJdbc1 曾出现在名为「Druid Jdbc」的示例链中。)
- 上游(
tags含DataSourceChains,能触发本环 getter):Fastjson、Fastjson2、Jackson、JacksonToString、FastjsonToString1、Rome1~4、RomeEqualsBean/ToStringBean 系列;以及包裹层 DWrap(DataSourceWrapperChain→DataSourceChains)。 - 下游(
nextTags=JdbcUrlChains/JdbcUrlWithSQLChains):H2JavaJdbc1、MysqlJdbc、DerbyCommandJdbc、PostgreSqlJdbc、SqliteJdbc、Hsqldb*Jdbc、Db2Jdbc、ModeShapeJdbc等(均在gadgets/common/)。 - 同族变体:DruidDataSource(DruidXADataSource 版)。
- 检测特征:
- 反序列化流量/内存中出现
com.alibaba.druid.pool.DruidDataSource(或...xa.DruidXADataSource)实例,且其url指向可疑方言(jdbc:h2:mem、jdbc:derby:、jdbc:mysql://带allowLoadLocalInfile/autoDeserialize、jdbc:postgresql://...socketFactory等)。 - Fastjson/Jackson 报文中出现
dataSource/connection相关属性并伴随 JDBC URL 字符串。 - 运行期出现「反序列化线程发起对外 JDBC 连接」的异常调用栈(
DruidDataSource.getConnection→init)。
- 反序列化流量/内存中出现
- 加固建议:
- 禁用/收敛 Fastjson
autoType、Jackson 默认多态类型(enableDefaultTyping),对DataSource/DruidDataSource等类型加入反序列化黑名单。 - JDBC 驱动侧禁危险 URL 参数:MySQL 关闭
allowLoadLocalInfile、autoDeserialize;避免在服务端引入 H2/Derby 等可被 URL 直接触发代码执行的驱动。 - 对连接池建连做出网/目的地白名单,阻断反序列化上下文中意外发起的 JDBC 连接。
- 升级并最小化依赖,移除生产环境不需要的
com.alibaba:druid与嵌入式数据库驱动。
- 禁用/收敛 Fastjson