
Apache Spark 4.2.0 - 높음 - 원격 - 권한 잔여 - proxy-user defaultExtraClassPath
abraxaslabs.tech · github.com/abraxas · @abraxas_null · [email protected] · spark-proxyuser-classpath
분석 문서: https://abraxaslabs.tech/research/spark-proxyuser-classpath
분류: 권한 잔여 (CVE-2023-22946 / SPARK-41958의 잔여) 도달 범위: 원격
Apache Spark 4.2.0 (32f72996) - Apache Software Foundation
CVE-2023-22946 / SPARK-41958은 여전히 spark.submit.proxyUser.allowCustomClasspathInClusterMode의 기본값을 false로 두고, --proxy-user 클러스터 제출 시 여전히 childClasspath.clear()를 실행한다. 그것이 공개된 YARN --jars 경로다. 이후 Spark 4.0은 spark.driver.defaultExtraClassPath를 추가했다. 런처는 클러스터 모드를 포함하여 항상 해당 키를 spark-submit JVM -cp 앞에 붙인다. SPARK-41958은 그것을 결코 보지 못한다.
Livy 스타일 테넌트는 여전히 게이트웨이 spark-submit JVM 내부에서 스테이징된 jar를 로드할 수 있다. Hadoop UserGroupInformation.doAs는 그 Unix UID를 바꾸지 않는다.
| ID | 아직 CVE 없음 |
| 분류 | 권한 잔여 (CVE-2023-22946 / SPARK-41958의 잔여) |
| 도달 범위 | 원격 (게이트웨이를 통한 Livy 스타일 --proxy-user 작업 제출) |
| CWE | CWE-269, CWE-427 |
| CVSS | 높음: 8.8 CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H |
| 제품 | Apache Spark |
| 영향 받음 | Apache Spark 4.2.0 (32f7299601108917fb01920a54e084595b7b3bf8) |
| 인증 | --conf와 스테이징된 --jars를 spark-submit --proxy-user ... --deploy-mode cluster로 전달하는 Livy / Kyuubi / Oozie 스타일 게이트웨이의 인증된 테넌트 |
| 라이선스 | GNU Affero GPL v3.0 |
| 랩 | 127.0.0.1:18950 전용. 증거 파일. 인용된 런처 / 제출 경로의 가젯. |
슈퍼유저 UID로 spark-submit --proxy-user <tenant> --deploy-mode cluster를 실행하는 멀티 테넌트 Spark 게이트웨이(Livy, Kyuubi, Oozie 등)에서 테넌트 계정을 보유한다. 게이트웨이 JVM이 열 수 있는 jar를 스테이징한다. --conf spark.driver.defaultExtraClassPath=<staged jar>를 보낸다. SPARK-41958 게이트는 false로 유지될 수 있다. 구성된 spark-submit -cp는 여전히 해당 jar로 시작한다. 그 안의 클래스는 게이트웨이 Unix UID로 로드된다.
--conf spark.submit.proxyUser.allowCustomClasspathInClusterMode=true는 두 번째 경로다. .internal()은 문서 전용이고, --conf는 여전히 해당 키를 기록하며, YARN 클러스터는 그런 다음 childClasspath에 --jars를 유지한다. 공개된 CVE-2023-22946은 clear()가 이미 처리하는 YARN 기본 --jars 경로로 남아 있다. 이 잔여는 게이트되지 않은 defaultExtraClassPath다.
정상 제출 후의 Hadoop 가장은 YARN AM / k8s 드라이버에 대해 여전히 프록시 사용자다. 이 잔여는 게이트웨이 JVM에만 해당한다.
| 방법 | 싱크 | 정찰 | 무결성 | 가용성 | 출처 |
|---|---|---|---|---|---|
Livy 스타일 제출 --proxy-user + yarn/k8s/standalone 클러스터 + --conf spark.driver.defaultExtraClassPath=<staged local jar>, SPARK-41958 플래그는 false로 유지 | SparkSubmitCommandBuilder.buildSparkSubmitCommand SparkSubmitCommandBuilder.java:317-327 -cp 첫 번째 항목 | 게이트웨이 UID가 읽을 수 있는 파일 목록/읽기 (keytab 디렉터리, spark-defaults, 로컬 스테이징). 이후 RPC의 Hadoop 아이덴티티는 여전히 프록시 사용자. | spark-submit JVM 내부에서 테넌트 클래스 로드. Unix UID는 게이트웨이(Hadoop 프록시 슈퍼유저)로 유지. 실험실: defaultExtraClassPath-on-cp=yes childClasspath-cleared=yes lab.WitnessMain이 SPARK-PROXYUSER-CLASSPATH-WITNESS를 기록함. 공개 CVE 클래스에서 추론: 해당 UID로서의 Hadoop Configuration 리소스 오버레이 / FileSystem 구현 조회. | 오버레이가 예외를 던지면 제출 JVM 크래시. 클래스는 아님. | 구성된 -cp로서의 실험실 입증 로드 + witness 기록. Hadoop 오버레이는 추론됨. Livy/Kyuubi --conf 패스스루는 추론됨 (해당 트리는 이 핀과 다름). |
동일 제출에 --conf spark.submit.proxyUser.allowCustomClasspathInClusterMode=true와 --jars / 기본 리소스 사용 | SparkSubmit.prepareSubmitEnvironment SparkSubmit.scala:333-336,738-743,917-924 이후 runMain :980-987 | 시스템 로더가 아닌 자식 URLClassLoader에서 walk A와 동일한 정찰. | addJarToClasspath가 실행되도록 --jars를 childClasspath에 유지. 실험실: conf-flag-keeps-jars=yes. | 동일. | 실험실 입증 childClasspath 유지. 플래그가 false로 유지될 때 clear()가 커버하는 공개 YARN --jars 경로의 재파일링은 아님. |
실험실 입증 vs 추론: 구성된 -cp는 클러스터 모드에서 defaultExtraClassPath를 포함함; childClasspath.clear()는 기본 플래그에서 여전히 실행됨; spark.driver.extraClassPath는 클러스터에서 생략됨; 플래그가 false인 --jars는 지워짐; 해당 -cp의 witness 클래스가 오라클을 기록함. Hadoop config-class 실행은 공개 CVE-2023-22946 메커니즘이며, 여기서 재실행되지 않음. Livy/Kyuubi의 --conf 포워딩은 해당 프로젝트들이 문서화한 아키텍처임.
| 방법 | 싱크 | 폐쇄 유지 |
|---|---|---|
클러스터 모드의 --driver-class-path / spark.driver.extraClassPath | SparkSubmitCommandBuilder.java:318-319 | spark-submit -cp에 추가되지 않음. 실험실: extraClassPath-omitted=yes. YARN/K8s가 프록시 사용자로 시작하는 클러스터 드라이버로 전달됨. |
기본 클러스터 + --proxy-user + --jars (플래그를 뒤집지 않고 defaultExtraClassPath 없이) | SparkSubmit.scala:917-918 childClasspath.clear() | YARN/standalone/k8s 클러스터 자식 클래스패스가 비워짐. 실험실: 대조 walk에서 childClasspath-cleared=yes. 공개 CVE-2023-22946은 이 경로로 유지됨. |
게이트웨이의 --proxy-user 클라이언트 모드 드라이버 | docs/security.md Proxy User 섹션 | 문서화됨: 클라이언트 모드 드라이버 JVM은 슈퍼유저. 벤더는 CVE가 아니라고 함. Livy/Kyuubi는 클러스터 모드를 강제하도록 지시받음. |
K8s 클러스터 모드 드라이버 컨테이너 (spark.kubernetes.submitInDriver=true)가 클래스패스에 . 추가 | SparkSubmit.scala:420-431 SPARK-43540 | 드라이버 파드 내부의 두 번째 spark-submit이며, Livy 호스트가 아님. 파드 UID는 컨테이너 사용자. |
클러스터 모드의 spark.driver.extraJavaOptions | SparkSubmitCommandBuilder.java:341-357 | spark-submit JVM에 적용되지 않음. SPARK_SUBMIT_OPTS는 게이트웨이 환경이며, 테넌트 --conf가 아님. |
| 제출된 앱의 YARN AM / k8s 드라이버 | 깨끗한 제출 후 Hadoop 임퍼소네이션 | 클러스터 실행에 대해서는 여전히 프록시 사용자. 이 잔여물은 게이트웨이 JVM에만 해당. |
| 미인증 작업 제출 / Connect SQL / ML 모델 로드 | SECURITY.md FAQ / docs/ml-security.md | 설계상. 이 잔여물이 아님. |
Spark 4.2.0(32f7299601108917fb01920a54e084595b7b3bf8)을 고정하고 SparkSubmit.submit / prepareSubmitEnvironment / runMain, SPARK-41958 플래그, 그리고 런처의 -cp 빌더를 살펴보았다. 공개된 Medium 글은 여전히 --jars 경로에 대해 유효하다: 기본 allowCustomClasspathInClusterMode는 false이며(package.scala:2849-2854), 클러스터 + 프록시 사용자 조합에서는 여전히 childClasspath를 비운다. --conf는 여전히 해당 내부 키를 기록한다(SparkSubmitArguments.scala:474-476). 별개로, Spark 4.0.0의 spark.driver.defaultExtraClassPath는 클러스터 모드를 포함하여 항상 spark-submit의 -cp에 포함된다:
boolean isClientMode = isClientMode(config);
String extraClassPath = isClientMode ? config.get(SparkLauncher.DRIVER_EXTRA_CLASSPATH) : null;
String defaultExtraClassPath = config.get(SparkLauncher.DRIVER_DEFAULT_EXTRA_CLASS_PATH);
if (extraClassPath == null || extraClassPath.trim().isEmpty()) {
extraClassPath = defaultExtraClassPath;
} else {
extraClassPath += File.pathSeparator + defaultExtraClassPath;
}
List<String> cmd = buildJavaCommand(extraClassPath);
4.0.0 키는 .internal()입니다(package.scala:80-85). --conf는 여전히 이를 기록합니다(SparkSubmitCommandBuilder.java:572-576). SPARK-41958은 이 경로를 결코 제한하지 않았습니다. jar는 SparkSubmit이 시작되기 전에 시스템 클래스로더에 올라가 있기 때문입니다.
이미 기록된 잘못된 접근들: 공개 CVE-2023-22946을 다시 제출하는 것(clear()가 커버하는 YARN --jars 순회); 클라이언트 모드 드라이버를 슈퍼유저로 취급하는 것을 CVE로 보는 것(security.md에 따르면 그렇지 않음); Ivy spark.jars.ivySettings(다른 가젯); SPARK_DIST_CLASSPATH / SPARK_SUBMIT_OPTS(게이트웨이 환경 변수이지 테넌트의 --conf가 아님); clear() 이후의 로그 라인(이미 비어 있는 버퍼를 기록함). 극적인 요소: 리버스 셸. 오라클은 구성된 -cp가 lab.WitnessMain을 로드할 때 기록되는 증인 문자열입니다.