Skip to content

Commit

Permalink
Merge pull request #449 from timoles:exposed_spark_ui_and_api
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 633314073
Change-Id: I267ab231c68f607427ff3611a6c0371eb2c1c545
  • Loading branch information
copybara-github committed May 13, 2024
2 parents 56ede51 + fdc6a09 commit ac368d2
Show file tree
Hide file tree
Showing 13 changed files with 907 additions and 3 deletions.
17 changes: 14 additions & 3 deletions community/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,21 @@ This directory contains plugins contributed by community members.
* [CVE-2021-29441 Nacos < 1.4.1 Authentication Bypass](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/nacos_cve_2021_29441)

#### Remote Code Execution

* [Apache Druid Pre-Auth RCE vulnerability (CVE-2021-25646) Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/apache_druid_preauth_rce_cve_2021_25646)
* [Forgerock AM/OpenAM RCE (CVE-2021-35464) Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/rce/cve202135464)
* [GitLab CE/EE Unauthenticated RCE using ExifTool and disclosure vulnerability (CVE-2021-29441)](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/gitlab_cve_2021_22205)
* [Unauthenticated RCE in Laravel <= 8.4.2 using Debug Mode (CVE-2021-3129) Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/laravel_cve_2021_3129)
* [CVE-2021-26084 Confluence Server RCE via Pre-Auth OGNL Injection (CVE-2021-26084) Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/confluence_cve_2021_26084)
* [GitLab CE/EE Unauthenticated RCE using ExifTool and disclosure
vulnerability
(CVE-2021-29441)](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/gitlab_cve_2021_22205)
* [Unauthenticated RCE in Laravel <= 8.4.2 using Debug Mode (CVE-2021-3129)
Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/laravel_cve_2021_3129)
* [CVE-2021-26084 Confluence Server RCE via Pre-Auth OGNL Injection
(CVE-2021-26084)
Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/confluence_cve_2021_26084)
* [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)
* [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)

#### Information Disclosure

* [Apache Sparks exposed Web UI Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/apache_spark_exposed_webui)
23 changes: 23 additions & 0 deletions community/detectors/apache_spark_exposed_webui/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Apache Sparks exposed Web UI

This detector checks for an exposed Apache Spark Web UI.

An Apache Spark Web Ui which is exposed to an attacker might disclose sensitive
information to them. An attacker can retrieve information such as the configured
workers and master node within the Apache Sparks environment. Furthermore, an
attacker gains access to the output logs of run tasks. This might disclose
sensitive information if a task is logging sensitive information during its
execution.

The Web UI is exposed on the root path of the Apache Sparks instance. An
exemplary URI might look like the following: `http://<apache_spark_host>:8080/`

## Build jar file for this plugin

Using `gradlew`:

```shell
./gradlew jar
```

Tsunami identifiable jar file is located at `build/libs` directory.
70 changes: 70 additions & 0 deletions community/detectors/apache_spark_exposed_webui/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
plugins {
id 'java'
}

description = 'Tsunami VulnDetector plugin to detect an exposed Apache Spark Web UI.'
group 'com.google.tsunami'
version '1.0-SNAPSHOT'

repositories {
maven { // The google mirror is less flaky than mavenCentral()
url 'https://maven-central.storage-download.googleapis.com/repos/central/data/'
}
mavenCentral()
mavenLocal()
}

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11

jar.manifest {
attributes('Implementation-Title': name,
'Implementation-Version': version,
'Built-By': System.getProperty('user.name'),
'Built-JDK': System.getProperty('java.version'),
'Source-Compatibility': sourceCompatibility,
'Target-Compatibility': targetCompatibility)
}

javadoc.options {
encoding = 'UTF-8'
use = true
links 'https://docs.oracle.com/javase/8/docs/api/'
}

// Log stacktrace to console when test fails.
test {
testLogging {
exceptionFormat = 'full'
showExceptions true
showCauses true
showStackTraces true
}
maxHeapSize = '1500m'
}
}

ext {
okhttpVersion = '3.12.0'
autoValueVersion = '1.7'
tsunamiVersion = 'latest.release'
junitVersion = '4.13'
mockitoVersion = '2.28.2'
truthVersion = '1.0.1'
}

dependencies {
implementation "com.google.auto.value:auto-value-annotations:${autoValueVersion}"
implementation "com.google.tsunami:tsunami-common:${tsunamiVersion}"
implementation "com.google.tsunami:tsunami-plugin:${tsunamiVersion}"
implementation "com.google.tsunami:tsunami-proto:${tsunamiVersion}"
annotationProcessor "com.google.auto.value:auto-value:${autoValueVersion}"

testImplementation "junit:junit:${junitVersion}"
testImplementation "org.mockito:mockito-core:${mockitoVersion}"
testImplementation "com.google.truth:truth:${truthVersion}"
testImplementation "com.google.truth.extensions:truth-java8-extension:${truthVersion}"
testImplementation "com.google.truth.extensions:truth-proto-extension:${truthVersion}"
testImplementation "com.squareup.okhttp3:mockwebserver:${okhttpVersion}"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
rootProject.name = 'apache_sparks_exposed_webui'

Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.google.tsunami.plugins.detectors.apachesparksexposedwebui;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.tsunami.common.net.http.HttpRequest.get;

import com.google.common.collect.ImmutableList;
import com.google.common.flogger.GoogleLogger;
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.HttpHeaders;
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.PluginInfo;
import com.google.tsunami.plugin.payload.PayloadGenerator;
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.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.Instant;
import java.util.regex.Pattern;
import javax.inject.Inject;

/** A Tsunami plugin for detecting an exposed Apache Spark Web UI. */
@PluginInfo(
type = PluginType.VULN_DETECTION,
name = "ApacheSparksExposedWebuiVulnDetector",
version = "0.1",
description =
"This plugin detects an exposed Apache Spark Web UI which discloses information about the"
+ " Apache Spark environment and its' tasks.",
author = "Timo Mueller ([email protected])",
bootstrapModule = ApacheSparksExposedWebuiVulnDetectorBootstrapModule.class)
public final class ApacheSparksExposedWebuiVulnDetector implements VulnDetector {

private final Clock utcClock;
private final HttpClient httpClient;
private final PayloadGenerator payloadGenerator;
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();

private static final Pattern VULNERABILITY_RESPONSE_PATTERN_TENTATIVE =
Pattern.compile("<title>Spark ");
private static final Pattern VULNERABILITY_RESPONSE_PATTERN_CONFIRMATION =
Pattern.compile("onClick=\"collapseTable\\('collapse-aggregated-");

@Inject
ApacheSparksExposedWebuiVulnDetector(
@UtcClock Clock utcClock, HttpClient httpClient, PayloadGenerator payloadGenerator) {
this.utcClock = checkNotNull(utcClock);
this.httpClient = checkNotNull(httpClient);
this.payloadGenerator = checkNotNull(payloadGenerator);
}

@Override
public DetectionReportList detect(
TargetInfo targetInfo, ImmutableList<NetworkService> matchedServices) {
logger.atInfo().log("ApacheSparksExposedWebuiVulnDetector starts detecting.");

return DetectionReportList.newBuilder()
.addAllDetectionReports(
matchedServices.stream()
.filter(NetworkServiceUtils::isWebService)
.filter(this::isServiceVulnerable)
.map(networkService -> buildDetectionReport(targetInfo, networkService))
.collect(toImmutableList()))
.build();
}

private boolean isServiceVulnerable(NetworkService networkService) {
String targetUri = NetworkServiceUtils.buildWebApplicationRootUrl(networkService);

try {
HttpResponse response =
httpClient.send(
get(targetUri)
.setHeaders(
HttpHeaders.builder().addHeader("User-Agent", "TSUNAMI_SCANNER").build())
.build(),
networkService);
if (response.status() == HttpStatus.OK && response.bodyString().isPresent()) {
String responseBody = response.bodyString().get();
if (VULNERABILITY_RESPONSE_PATTERN_TENTATIVE.matcher(responseBody).find()
&& VULNERABILITY_RESPONSE_PATTERN_CONFIRMATION.matcher(responseBody).find()) {
return true;
}
}
} catch (IOException e) {
logger.atWarning().withCause(e).log("Unable to query '%s'.", targetUri);
}

return false;
}

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(
Vulnerability.newBuilder()
.setMainId(
VulnerabilityId.newBuilder()
.setPublisher("Community")
.setValue("Apache_Spark_Exposed_WebUI"))
.setSeverity(Severity.MEDIUM)
.setTitle(
"Exposed Apache Spark UI which discloses information about the Apache Spark"
+ " environment and its' tasks.")
.setDescription(
"An exposed Apache Spark Web UI provides attackers information about the Apache"
+ " Spark UI and its' tasks. The disclosed information might leak other"
+ " configured Apache Spark nodes and the output of previously run tasks."
+ " Depending on the task, the output might contain sensitive information"
+ " which was logged during the task execution.")
.setRecommendation(
"Don't expose the Apache Spark Web UI to unauthenticated attackers."))
.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*
* Copyright 2024 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.apachesparksexposedwebui;

import com.google.tsunami.plugin.PluginBootstrapModule;

/** A {@link PluginBootstrapModule} for {@link ApacheSparksExposedWebuiVulnDetector}. */
public final class ApacheSparksExposedWebuiVulnDetectorBootstrapModule
extends PluginBootstrapModule {

@Override
protected void configurePlugin() {
registerPlugin(ApacheSparksExposedWebuiVulnDetector.class);
}
}
Loading

0 comments on commit ac368d2

Please sign in to comment.