From 0e0fc3d87afb56ecb16c3305e2f2d8b95aeee56e Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 1 May 2026 10:06:27 -0400 Subject: [PATCH 1/4] converted elasticsearch exposedui detector to templated --- .../Elasticsearch_ExposedUI.textproto | 63 +++++++++++++++++++ .../Elasticsearch_ExposedUI_test.textproto | 53 ++++++++++++++++ 2 files changed, 116 insertions(+) create mode 100644 templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI.textproto create mode 100644 templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI_test.textproto diff --git a/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI.textproto b/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI.textproto new file mode 100644 index 000000000..a77b7ad32 --- /dev/null +++ b/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI.textproto @@ -0,0 +1,63 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "Elasticsearch_ExposedUI" + author: + "Robert Dick (robert@doyensec.com) for the Templated version," + " Tsunami Team (tsunami-dev@google.com) for the original Java version" + version: "2.0" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "ELASTICSEARCH_EXPOSED_UI" + } + severity: CRITICAL + title: "Elasticsearch Exposed UI" + description: + "Elasticsearch API endpoint is exposed." + recommendation: + "Do not expose Elasticsearch externally.\n" + "Bind it to localhost, or run it on a host that is not exposed to the" + " Internet." +} + +########### +# ACTIONS # +########### + +# this action isn't very strong, probably a little bit prone to false positives, +# but it's what the original plugin did + +actions: { + name: "fingerprint_elasticsearch" + http_request: { + method: GET + uri: "/" + response: { + http_status: 200 + expect_all { + conditions: [ + { body: {} contains: '"tagline" : "You Know, for Search"' } + ] + } + } + } +} + +############# +# WORKFLOWS # +############# + +workflows: { + actions: [ + "fingerprint_elasticsearch" + ] +} \ No newline at end of file diff --git a/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI_test.textproto b/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI_test.textproto new file mode 100644 index 000000000..94800a583 --- /dev/null +++ b/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI_test.textproto @@ -0,0 +1,53 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "Elasticsearch_ExposedUI" +} + +tests: { + name: "whenVulnerable_returnsTrue" + expect_vulnerability: true + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: + '{\n' + ' "name" : "es01",\n' + ' "cluster_name" : "docker-cluster",\n' + ' "cluster_uuid" : "Pee3wQ9qQLendzHZ_2Ng5A",\n' + ' "version" : {\n' + ' "number" : "9.3.4",\n' + ' "build_flavor" : "default",\n' + ' "build_type" : "docker",\n' + ' "build_hash" : "69a3e6c50ebb57a1fdbf3f235be9f11061ac7d86",\n' + ' "build_date" : "2026-04-22T22:10:58.242616321Z",\n' + ' "build_snapshot" : false,\n' + ' "lucene_version" : "10.3.2",\n' + ' "minimum_wire_compatibility_version" : "8.19.0",\n' + ' "minimum_index_compatibility_version" : "8.0.0"\n' + ' },\n' + ' "tagline" : "You Know, for Search"\n' + '}' + } + ] + } +} + +tests: { + name: "whenNotElasticsearch_returnsFalse" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "Hello world" + } + ] + } +} From 488d98d9c30fc1036780d4418c2713390f4c1566 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Wed, 3 Jun 2026 01:16:31 -0400 Subject: [PATCH 2/4] removed original elasticsearch detector --- .../exposedui/elasticsearch/README.md | 13 - .../exposedui/elasticsearch/build.gradle | 39 --- .../exposedui/elasticsearch/settings.gradle | 12 - .../ElasticsearchApiExposedDetector.java | 145 ----------- ...archApiExposedDetectorBootstrapModule.java | 27 -- .../ElasticsearchApiExposedDetectorTest.java | 231 ------------------ .../testdata/validApiResponse.json | 17 -- 7 files changed, 484 deletions(-) delete mode 100644 google/detectors/exposedui/elasticsearch/README.md delete mode 100644 google/detectors/exposedui/elasticsearch/build.gradle delete mode 100644 google/detectors/exposedui/elasticsearch/settings.gradle delete mode 100644 google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetector.java delete mode 100644 google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorBootstrapModule.java delete mode 100644 google/detectors/exposedui/elasticsearch/src/test/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorTest.java delete mode 100644 google/detectors/exposedui/elasticsearch/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/testdata/validApiResponse.json diff --git a/google/detectors/exposedui/elasticsearch/README.md b/google/detectors/exposedui/elasticsearch/README.md deleted file mode 100644 index e8e0dc16e..000000000 --- a/google/detectors/exposedui/elasticsearch/README.md +++ /dev/null @@ -1,13 +0,0 @@ -# Elasticsearch API Exposed Detector - -This Tsunami plugin tests to see if the Elasticsearch REST API endpoint is exposed. - -## Build jar file for this plugin - -Using `gradlew`: - -```shell -./gradlew jar -``` - -Tsunami identifiable jar file is located at `build/libs` directory. diff --git a/google/detectors/exposedui/elasticsearch/build.gradle b/google/detectors/exposedui/elasticsearch/build.gradle deleted file mode 100644 index d216679c1..000000000 --- a/google/detectors/exposedui/elasticsearch/build.gradle +++ /dev/null @@ -1,39 +0,0 @@ -plugins { - id 'java-library' -} - -description = 'Tsunami Elasticsearch API exposed 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 "com.google.truth:truth:1.4.4" - testImplementation "com.google.truth.extensions:truth-java8-extension:1.4.4" - testImplementation "com.google.truth.extensions:truth-proto-extension:1.4.4" - testImplementation "com.squareup.okhttp3:mockwebserver:3.12.0" -} - diff --git a/google/detectors/exposedui/elasticsearch/settings.gradle b/google/detectors/exposedui/elasticsearch/settings.gradle deleted file mode 100644 index 292cd51b0..000000000 --- a/google/detectors/exposedui/elasticsearch/settings.gradle +++ /dev/null @@ -1,12 +0,0 @@ -rootProject.name = 'elasticsearch_api_exposed' - -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/google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetector.java b/google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetector.java deleted file mode 100644 index 055487bb9..000000000 --- a/google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetector.java +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2020 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.exposedui.elasticsearch; - -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.gson.JsonSyntaxException; -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.HttpResponse; -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.proto.AdditionalDetail; -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.TextData; -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 javax.inject.Inject; - -/** A {@link VulnDetector} that detects exposed Elasticsearch REST API endpoints. */ -@PluginInfo( - type = PluginType.VULN_DETECTION, - name = "ElasticsearchApiExposedDetector", - version = "0.1", - description = "This plugin detects exposed Elasticsearch REST API endpoints.", - author = "Tsunami Team (tsunami-dev@google.com)", - bootstrapModule = ElasticsearchApiExposedDetectorBootstrapModule.class) -public final class ElasticsearchApiExposedDetector implements VulnDetector { - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - - private final Clock utcClock; - private final HttpClient httpClient; - - @Inject - ElasticsearchApiExposedDetector(@UtcClock Clock utcClock, HttpClient httpClient) { - this.utcClock = checkNotNull(utcClock); - this.httpClient = checkNotNull(httpClient).modify().setFollowRedirects(false).build(); - } - - @Override - public ImmutableList getAdvisories() { - return ImmutableList.of(getAdvisory(AdditionalDetail.getDefaultInstance())); - } - - @Override - public DetectionReportList detect( - TargetInfo targetInfo, ImmutableList matchedServices) { - logger.atInfo().log("Starting Elasticsearch API exposed detection."); - return DetectionReportList.newBuilder() - .addAllDetectionReports( - matchedServices.stream() - .filter(NetworkServiceUtils::isWebService) - .filter(this::isServiceVulnerable) - .map(networkService -> buildDetectionReport(targetInfo, networkService)) - .collect(toImmutableList())) - .build(); - } - - Vulnerability getAdvisory(AdditionalDetail details) { - return Vulnerability.newBuilder() - .setMainId( - VulnerabilityId.newBuilder() - .setPublisher("GOOGLE") - .setValue("ELASTICSEARCH_API_EXPOSED")) - .setSeverity(Severity.CRITICAL) - .setTitle("Elasticsearch API Exposed") - .setDescription("Elasticsearch API endpoint is exposed.") - .setRecommendation( - "Do not expose Elasticsearch externally.\n" - + "Bind it to localhost, or run it on a host that is not exposed to the" - + " Internet.") - .addAdditionalDetails(details) - .build(); - } - - /** Checks if a {@link NetworkService} has a Elasticsearch REST API endpoint exposed. */ - private boolean isServiceVulnerable(NetworkService networkService) { - String targetUri = NetworkServiceUtils.buildWebApplicationRootUrl(networkService); - try { - // This is a blocking call. - HttpResponse response = - httpClient.send(get(targetUri).withEmptyHeaders().build(), networkService); - - return response.status().isSuccess() - && response.jsonFieldEqualsToValue("tagline", "You Know, for Search"); - } catch (IOException e) { - logger.atWarning().withCause(e).log("Unable to query '%s'.", targetUri); - return false; - } catch (JsonSyntaxException e) { - logger.atWarning().withCause(e).log( - "JSON syntax error occurred parsing response for target URI: '%s'.", targetUri); - return false; - } catch (IllegalStateException e) { - logger.atWarning().withCause(e).log( - "JSON object parsing error for target URI: '%s'.", targetUri); - return false; - } - } - - private DetectionReport buildDetectionReport( - TargetInfo targetInfo, NetworkService vulnerableNetworkService) { - TextData details = - TextData.newBuilder() - .setText( - String.format( - "The Elasticsearch REST API endpoint at %s is exposed.", - NetworkServiceUtils.buildWebApplicationRootUrl(vulnerableNetworkService))) - .build(); - return DetectionReport.newBuilder() - .setTargetInfo(targetInfo) - .setNetworkService(vulnerableNetworkService) - .setDetectionTimestamp(Timestamps.fromMillis(Instant.now(utcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(getAdvisory(AdditionalDetail.newBuilder().setTextData(details).build())) - .build(); - } -} diff --git a/google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorBootstrapModule.java b/google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorBootstrapModule.java deleted file mode 100644 index afd3f7bc2..000000000 --- a/google/detectors/exposedui/elasticsearch/src/main/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorBootstrapModule.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2020 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.exposedui.elasticsearch; - -import com.google.tsunami.plugin.PluginBootstrapModule; - -/** A {@link PluginBootstrapModule} for {@link ElasticsearchApiExposedDetector}. */ -public final class ElasticsearchApiExposedDetectorBootstrapModule extends PluginBootstrapModule { - - @Override - protected void configurePlugin() { - registerPlugin(ElasticsearchApiExposedDetector.class); - } -} diff --git a/google/detectors/exposedui/elasticsearch/src/test/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorTest.java b/google/detectors/exposedui/elasticsearch/src/test/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorTest.java deleted file mode 100644 index ec67162e4..000000000 --- a/google/detectors/exposedui/elasticsearch/src/test/java/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/ElasticsearchApiExposedDetectorTest.java +++ /dev/null @@ -1,231 +0,0 @@ -/* - * Copyright 2020 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.exposedui.elasticsearch; - -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 static java.nio.charset.StandardCharsets.UTF_8; - -import com.google.common.collect.ImmutableList; -import com.google.common.io.Resources; -import com.google.inject.Guice; -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.proto.AdditionalDetail; -import com.google.tsunami.proto.DetectionReport; -import com.google.tsunami.proto.DetectionStatus; -import com.google.tsunami.proto.NetworkEndpoint; -import com.google.tsunami.proto.NetworkService; -import com.google.tsunami.proto.Software; -import com.google.tsunami.proto.TargetInfo; -import com.google.tsunami.proto.TextData; -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 ElasticsearchApiExposedDetector}. */ -@RunWith(JUnit4.class) -public final class ElasticsearchApiExposedDetectorTest { - private final FakeUtcClock fakeUtcClock = - FakeUtcClock.create().setNow(Instant.parse("2020-01-01T00:00:00.00Z")); - - private MockWebServer mockWebServer; - - @Inject private ElasticsearchApiExposedDetector detector; - - @Before - public void setUp() { - mockWebServer = new MockWebServer(); - - Guice.createInjector( - new FakeUtcClockModule(fakeUtcClock), - new HttpClientModule.Builder().build(), - new ElasticsearchApiExposedDetectorBootstrapModule()) - .injectMembers(this); - } - - @After - public void tearDown() throws IOException { - mockWebServer.shutdown(); - } - - @Test - public void detect_whenApiEndpointExposed_reportsVuln() throws IOException { - startMockWebServer( - "/", - HttpStatus.OK.code(), - Resources.toString( - Resources.getResource(this.getClass(), "testdata/validApiResponse.json"), UTF_8)); - NetworkService httpService = - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("Elasticsearch API")) - .setServiceName("http") - .build(); - ImmutableList httpServices = ImmutableList.of(httpService); - - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .containsExactly( - DetectionReport.newBuilder() - .setTargetInfo(buildTargetInfo(forHostname(mockWebServer.getHostName()))) - .setNetworkService(httpService) - .setDetectionTimestamp(Timestamps.fromMillis(fakeUtcClock.millis())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability( - detector.getAdvisory( - AdditionalDetail.newBuilder() - .setTextData( - TextData.newBuilder() - .setText( - String.format( - "The Elasticsearch REST API endpoint at" - + " http://%s:%d/ is exposed.", - mockWebServer.getHostName(), mockWebServer.getPort()))) - .build())) - .build()); - } - - @Test - public void detect_whenApiEndpointNotFound_doesNotReportVuln() throws IOException { - startMockWebServer("/", HttpStatus.NOT_FOUND.code(), ""); - ImmutableList httpServices = - ImmutableList.of( - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("Elasticsearch API")) - .setServiceName("http") - .build()); - - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .isEmpty(); - } - - @Test - public void detect_whenApiEndpointReturnsEmptyBody_doesNotReportVuln() throws IOException { - startMockWebServer("/", HttpStatus.OK.code(), ""); - NetworkService httpService = - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("Elasticsearch API")) - .setServiceName("http") - .build(); - ImmutableList httpServices = ImmutableList.of(httpService); - - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .isEmpty(); - } - - @Test - public void detect_whenApiEndpointReturnsEmptyJson_doesNotReportVuln() throws IOException { - startMockWebServer("/", HttpStatus.OK.code(), "{}"); - NetworkService httpService = - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("Elasticsearch API")) - .setServiceName("http") - .build(); - ImmutableList httpServices = ImmutableList.of(httpService); - - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .isEmpty(); - } - - @Test - public void detect_whenNonElasticsearchWebApp_ignoresServices() throws IOException { - startMockWebServer("/", HttpStatus.OK.code(), "This is WordPress."); - ImmutableList httpServices = - ImmutableList.of( - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("WordPress")) - .setServiceName("http") - .build()); - - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .isEmpty(); - } - - @Test - public void detect_whenNonHttpNetworkService_ignoresServices() { - ImmutableList nonHttpServices = - ImmutableList.of( - NetworkService.newBuilder().setServiceName("ssh").build(), - NetworkService.newBuilder().setServiceName("rdp").build()); - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), nonHttpServices) - .getDetectionReportsList()) - .isEmpty(); - } - - @Test - public void detect_whenEmptyNetworkService_generatesEmptyDetectionReports() { - assertThat( - detector - .detect( - buildTargetInfo(forHostname(mockWebServer.getHostName())), ImmutableList.of()) - .getDetectionReportsList()) - .isEmpty(); - } - - private void startMockWebServer(String url, int responseCode, String response) - throws IOException { - mockWebServer.enqueue(new MockResponse().setResponseCode(responseCode).setBody(response)); - mockWebServer.start(); - mockWebServer.url(url); - } - - private static TargetInfo buildTargetInfo(NetworkEndpoint networkEndpoint) { - return TargetInfo.newBuilder().addNetworkEndpoints(networkEndpoint).build(); - } -} diff --git a/google/detectors/exposedui/elasticsearch/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/testdata/validApiResponse.json b/google/detectors/exposedui/elasticsearch/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/testdata/validApiResponse.json deleted file mode 100644 index 09d8790b5..000000000 --- a/google/detectors/exposedui/elasticsearch/src/test/resources/com/google/tsunami/plugins/detectors/exposedui/elasticsearch/testdata/validApiResponse.json +++ /dev/null @@ -1,17 +0,0 @@ -{ - "name" : "aabbccddeeff", - "cluster_name" : "docker-cluster", - "cluster_uuid" : "abc", - "version" : { - "number" : "7.9.3", - "build_flavor" : "default", - "build_type" : "docker", - "build_hash" : "aabbcc", - "build_date" : "2020-10-16T10:36:16.141335Z", - "build_snapshot" : false, - "lucene_version" : "8.6.2", - "minimum_wire_compatibility_version" : "6.8.0", - "minimum_index_compatibility_version" : "6.0.0-beta1" - }, - "tagline" : "You Know, for Search" -} From 1afb3a018cb046afa2f7a22083f2238a39f1a07d Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Thu, 11 Jun 2026 06:41:51 -0400 Subject: [PATCH 3/4] fixed link --- google/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google/README.md b/google/README.md index f9493cf98..091381d7f 100644 --- a/google/README.md +++ b/google/README.md @@ -21,7 +21,7 @@ This directory contains all Tsunami plugins published by Google. * [Ncrack Weak Credential Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/credentials/ncrack) #### Exposed Sensitive UI/API -* [Exposed Elasticsearch API Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/elasticsearch) +* [Exposed Elasticsearch API Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI.textproto) * [Exposed Hadoop Yarn ResourceManager API Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/hadoop/yarn) * [Exposed Jenkins UI Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/jenkins) * [Exposed Jupyter Notebook Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/jupyter) From 3ac6433ccdb39e4258e2abbd1e16cdf6164ccc2b Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Thu, 11 Jun 2026 06:43:24 -0400 Subject: [PATCH 4/4] changed wording --- google/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/google/README.md b/google/README.md index 091381d7f..c55c0aa96 100644 --- a/google/README.md +++ b/google/README.md @@ -21,7 +21,7 @@ This directory contains all Tsunami plugins published by Google. * [Ncrack Weak Credential Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/credentials/ncrack) #### Exposed Sensitive UI/API -* [Exposed Elasticsearch API Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI.textproto) +* [Exposed Elasticsearch API Detector, now updated to Templated format](https://github.com/google/tsunami-security-scanner-plugins/tree/master/templated/templateddetector/plugins/exposedui/Elasticsearch_ExposedUI.textproto) * [Exposed Hadoop Yarn ResourceManager API Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/hadoop/yarn) * [Exposed Jenkins UI Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/jenkins) * [Exposed Jupyter Notebook Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/google/detectors/exposedui/jupyter)