From bcd35c292f1116bb7211764ac09d76ac74684529 Mon Sep 17 00:00:00 2001 From: JamesFoxxx Date: Thu, 13 Jun 2024 05:19:46 +0200 Subject: [PATCH 1/7] Initiating the integration of the Argo CD weak credential tester plugin. --- ...WeakCredentialDetectorBootstrapModule.java | 2 + .../argocd/ArgoCdCredentialTester.java | 125 +++++++++++++ .../service_default_credentials.textproto | 8 + .../argocd/ArgoCdCredentialTesterTest.java | 177 ++++++++++++++++++ .../web/WebServiceFingerprinter.java | 41 ++++ 5 files changed, 353 insertions(+) create mode 100644 google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java create mode 100644 google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/GenericWeakCredentialDetectorBootstrapModule.java b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/GenericWeakCredentialDetectorBootstrapModule.java index 7c46ce6b4..520597f46 100644 --- a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/GenericWeakCredentialDetectorBootstrapModule.java +++ b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/GenericWeakCredentialDetectorBootstrapModule.java @@ -39,6 +39,7 @@ import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.grafana.GrafanaCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.hydra.HydraCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.jenkins.JenkinsCredentialTester; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.argocd.ArgoCdCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.mlflow.MlFlowCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.mysql.MysqlCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.ncrack.NcrackCredentialTester; @@ -65,6 +66,7 @@ protected void configurePlugin() { Multibinder credentialTesterBinder = Multibinder.newSetBinder(binder(), CredentialTester.class); + credentialTesterBinder.addBinding().to(ArgoCdCredentialTester.class); credentialTesterBinder.addBinding().to(JenkinsCredentialTester.class); credentialTesterBinder.addBinding().to(MlFlowCredentialTester.class); credentialTesterBinder.addBinding().to(MysqlCredentialTester.class); diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java new file mode 100644 index 000000000..8be69e6c2 --- /dev/null +++ b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java @@ -0,0 +1,125 @@ +/* + * 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.credentials.genericweakcredentialdetector.testers.argocd; + +import static com.google.common.base.Preconditions.checkNotNull; +import static com.google.tsunami.common.net.http.HttpRequest.get; +import static com.google.tsunami.common.net.http.HttpRequest.post; +import static java.nio.charset.StandardCharsets.UTF_8; + +import com.google.common.base.Strings; +import com.google.common.collect.ImmutableList; +import com.google.common.flogger.GoogleLogger; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import com.google.gson.JsonSyntaxException; +import com.google.protobuf.ByteString; +import com.google.tsunami.common.data.NetworkEndpointUtils; +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.plugins.detectors.credentials.genericweakcredentialdetector.provider.TestCredential; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.tester.CredentialTester; +import com.google.tsunami.proto.NetworkService; +import java.io.IOException; +import java.util.Base64; +import java.util.List; +import javax.inject.Inject; + +import jdk.jfr.ContentType; +import org.jsoup.Jsoup; +import org.jsoup.select.Elements; + +/** Credential tester specifically for argocd. */ +public final class ArgoCdCredentialTester extends CredentialTester { + private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); + private final HttpClient httpClient; + + private static final String ARGOCD_SERVICE = "argocd"; + + @Inject + ArgoCdCredentialTester(HttpClient httpClient) { + this.httpClient = checkNotNull(httpClient); + } + + @Override + public String name() { + return "ArgoCdCredentialTester"; + } + + @Override + public String description() { + return "ArgoCd credential tester."; + } + + @Override + public boolean canAccept(NetworkService networkService) { + return NetworkServiceUtils.getWebServiceName(networkService).equals(ARGOCD_SERVICE); + } + + @Override + public boolean batched() { + return true; + } + + @Override + public ImmutableList testValidCredentials( + NetworkService networkService, List credentials) { + // Always return 1st weak credential to gracefully handle no auth configured case, where we + // return empty credential instead of all the weak credentials + return credentials.stream() + .filter(cred -> isArgoCdAccessible(networkService, cred)) + .findFirst() + .map(ImmutableList::of) + .orElseGet(ImmutableList::of); + } + + private boolean isArgoCdAccessible(NetworkService networkService, TestCredential credential) { + var uriAuthority = NetworkEndpointUtils.toUriAuthority(networkService.getNetworkEndpoint()); + var url = String.format("http://%s/", uriAuthority) + "api/v1/session"; + try { + logger.atInfo().log( + "url: %s, username: %s, password: %s", + url, credential.username(), credential.password().orElse("")); + HttpResponse response = + httpClient.send( + post(url) + .setHeaders( + HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) + .setRequestBody( + ByteString.copyFromUtf8( + String.format( + "{\"username\":\"%s\",\"password\":\"%s\"}", + credential.username(), credential.password().get()))) + .build()); + return response.status().isSuccess() + && response.bodyString().isPresent() + && bodyContainsToken(response.bodyString().get()); + } catch (IOException e) { + logger.atWarning().withCause(e).log("Unable to query '%s'.", url); + return false; + } + } + + private static boolean bodyContainsToken(String responseBody) { + try { + return JsonParser.parseString(responseBody).getAsJsonObject().has("token"); + } catch (IllegalStateException | JsonSyntaxException e) { + return false; + } + } +} diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto b/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto index 86293f939..28406d36a 100644 --- a/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto +++ b/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto @@ -77,3 +77,11 @@ service_default_credentials { default_usernames: "username" default_passwords: "password" } + +service_default_credentials { + service_name: "argocd" + default_usernames: "admin" + default_passwords: "Password1!" + default_passwords: "password" + default_passwords: "YOUR-PASSWORD-HERE" +} diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java b/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java new file mode 100644 index 000000000..ec0ab17f1 --- /dev/null +++ b/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java @@ -0,0 +1,177 @@ +/* + * 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.credentials.genericweakcredentialdetector.testers.argocd; + +import static com.google.common.net.HttpHeaders.CONTENT_TYPE; +import static com.google.common.truth.Truth.assertThat; +import static com.google.tsunami.common.data.NetworkEndpointUtils.forHostnameAndPort; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.verifyNoInteractions; +import static org.mockito.Mockito.when; + +import com.google.common.collect.ImmutableList; +import com.google.inject.Guice; +import com.google.tsunami.common.net.db.ConnectionProviderInterface; +import com.google.tsunami.common.net.http.HttpClientModule; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.provider.TestCredential; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.argocd.ArgoCdCredentialTester; +import com.google.tsunami.proto.NetworkService; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.sql.Connection; +import java.util.Objects; +import java.util.Optional; +import javax.inject.Inject; +import okhttp3.mockwebserver.Dispatcher; +import okhttp3.mockwebserver.MockResponse; +import okhttp3.mockwebserver.MockWebServer; +import okhttp3.mockwebserver.RecordedRequest; +import org.junit.Before; +import org.junit.Rule; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnit; +import org.mockito.junit.MockitoRule; + +/** Tests for {@link ArgoCdCredentialTester}. */ +@RunWith(JUnit4.class) +public class ArgoCdCredentialTesterTest { + @Rule public MockitoRule rule = MockitoJUnit.rule(); + @Mock private ConnectionProviderInterface mockConnectionProvider; + @Mock private Connection mockConnection; + @Inject private ArgoCdCredentialTester tester; + private MockWebServer mockWebServer; + private static final TestCredential WEAK_CRED_1 = + TestCredential.create("admin", Optional.of("password")); + private static final TestCredential WEAK_CRED_2 = + TestCredential.create("admin", Optional.of("Password1!")); + private static final TestCredential WEAK_CRED_3 = + TestCredential.create("admin", Optional.of("YOUR-PASSWORD-HERE")); + private static final TestCredential WRONG_CRED_1 = + TestCredential.create("wrong", Optional.of("wrong")); + + @Before + public void setup() { + mockWebServer = new MockWebServer(); + Guice.createInjector(new HttpClientModule.Builder().build()).injectMembers(this); + } + + @Test + public void detect_weakCredentialsExists_returnsWeakCredentials() throws Exception { + startMockWebServer(); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint( + forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) + .setServiceName("argocd") + .build(); + + assertThat(tester.testValidCredentials(targetNetworkService, ImmutableList.of(WEAK_CRED_1))) + .containsExactly(WEAK_CRED_1); + mockWebServer.shutdown(); + } + + @Test + public void detect_weakCredentialsExist_returnsFirstWeakCredentials() throws Exception { + startMockWebServer(); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint( + forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) + .setServiceName("argocd") + .build(); + + assertThat( + tester.testValidCredentials( + targetNetworkService, ImmutableList.of(WEAK_CRED_1, WEAK_CRED_2, WEAK_CRED_3))) + .containsExactly(WEAK_CRED_1); + } + + @Test + public void detect_argocdService_canAccept() throws Exception { + startMockWebServer(); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint( + forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) + .setServiceName("argocd") + .build(); + + assertThat(tester.canAccept(targetNetworkService)).isTrue(); + } + + @Test + public void detect_noWeakCredentials_returnsNoCredentials() throws Exception { + startMockWebServer(); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint( + forHostnameAndPort(mockWebServer.getHostName(), mockWebServer.getPort())) + .setServiceName("argocd") + .build(); + assertThat(tester.testValidCredentials(targetNetworkService, ImmutableList.of(WRONG_CRED_1))) + .isEmpty(); + } + + @Test + public void detect_nonArgoCdService_skips() throws Exception { + when(mockConnectionProvider.getConnection(any(), any(), any())).thenReturn(mockConnection); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint(forHostnameAndPort("example.com", 8080)) + .setServiceName("http") + .build(); + + assertThat(tester.testValidCredentials(targetNetworkService, ImmutableList.of(WEAK_CRED_1))) + .isEmpty(); + verifyNoInteractions(mockConnectionProvider); + } + + private void startMockWebServer() throws IOException { + final Dispatcher dispatcher = + new Dispatcher() { + @Override + public MockResponse dispatch(RecordedRequest request) { + String authorizationRequestBody = request.getBody().readString(StandardCharsets.UTF_8); + if (request.getPath().equals("/api/v1/session") + && Objects.equals(request.getMethod(), "POST") + && Objects.equals(request.getHeader(CONTENT_TYPE), "application/json")) { + boolean isDefaultCredentials = + authorizationRequestBody.equals( + "{\"username\":\"admin\",\"password\":\"Password1!\"}") + || authorizationRequestBody.equals( + "{\"username\":\"admin\",\"password\":\"password\"}") + || authorizationRequestBody.equals( + "{\"username\":\"admin\",\"password\":\"YOUR-PASSWORD-HERE\"}"); + if (isDefaultCredentials) { + return new MockResponse() + .setResponseCode(200) + .setBody("{\"token\": \"AToken\"\n" + "}"); + } else { + return new MockResponse().setResponseCode(401); + } + } + return new MockResponse().setResponseCode(404); + } + }; + mockWebServer.setDispatcher(dispatcher); + mockWebServer.start(); + mockWebServer.url("/"); + } +} diff --git a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java index 835fe8f88..0601756b4 100644 --- a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java +++ b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java @@ -19,6 +19,7 @@ import static com.google.common.collect.ImmutableList.toImmutableList; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.tsunami.common.net.http.HttpRequest.get; +import static com.google.tsunami.common.net.http.HttpRequest.post; import static java.util.stream.Collectors.joining; import com.google.common.collect.ImmutableMap; @@ -27,6 +28,7 @@ import com.google.tsunami.common.data.NetworkEndpointUtils; import com.google.tsunami.common.data.NetworkServiceUtils; import com.google.tsunami.common.net.http.HttpClient; +import com.google.tsunami.common.net.http.HttpHeaders; import com.google.tsunami.common.net.http.HttpResponse; import com.google.tsunami.common.net.http.HttpStatus; import com.google.tsunami.plugin.PluginType; @@ -277,6 +279,7 @@ private ImmutableSet detectSoftwareByCustomHeuristics( HashSet detectedSoftware = new HashSet<>(); checkForMlflow(detectedSoftware, networkService, startingUrl); + checkForArgoCd(detectedSoftware, networkService, startingUrl); return ImmutableSet.copyOf(detectedSoftware); } @@ -316,4 +319,42 @@ private void checkForMlflow( logger.atWarning().withCause(e).log("Unable to query '%s'.", pingApiUrl); } } + + private void checkForArgoCd( + Set software, NetworkService networkService, String startingUrl) { + logger.atInfo().log("probing Argo CD - custom fingerprint phase"); + + var uriAuthority = NetworkEndpointUtils.toUriAuthority(networkService.getNetworkEndpoint()); + var applicationsApiUrl = String.format("http://%s/%s", uriAuthority, "api/v1/applications"); + try { + HttpResponse apiApplicationsResponse = + httpClient.send( + post(applicationsApiUrl) + .setHeaders( + HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) + .build()); + + if (apiApplicationsResponse.status() != HttpStatus.INTERNAL_SERVER_ERROR + || apiApplicationsResponse.bodyString().isEmpty()) { + return; + } + + if (apiApplicationsResponse + .bodyString() + .get() + .contains( + "{\"error\":\"grpc: error while marshaling: proto: required field \\\"application\\\"" + + " not set\",\"code\":13,\"message\":\"grpc: error while marshaling: " + + "proto: required field \\\"application\\\" not set\"}")) { + software.add( + DetectedSoftware.builder() + .setSoftwareIdentity(SoftwareIdentity.newBuilder().setSoftware("argocd").build()) + .setRootPath(startingUrl) + .setContentHashes(ImmutableMap.of()) + .build()); + } + } catch (IOException e) { + logger.atWarning().withCause(e).log("Unable to query '%s'.", applicationsApiUrl); + } + } } From fae65a9f59552b07ea28f76d6841a4a6b428de8d Mon Sep 17 00:00:00 2001 From: JamesFoxxx Date: Fri, 11 Oct 2024 10:44:21 +0200 Subject: [PATCH 2/7] resolve confilicts and update the branch to master --- .../web/WebServiceFingerprinter.java | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java index b713d30d3..d3f314847 100644 --- a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java +++ b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java @@ -25,6 +25,7 @@ import com.google.common.collect.ImmutableMap; import com.google.common.collect.ImmutableSet; import com.google.common.flogger.GoogleLogger; +import com.google.tsunami.common.data.NetworkEndpointUtils; import com.google.protobuf.ByteString; import com.google.tsunami.common.data.NetworkServiceUtils; import com.google.tsunami.common.net.http.HttpClient; @@ -280,6 +281,7 @@ private ImmutableSet detectSoftwareByCustomHeuristics( checkForMlflow(detectedSoftware, networkService, startingUrl); checkForZenMl(detectedSoftware, networkService, startingUrl); + checkForArgoCd(detectedSoftware, networkService, startingUrl); return ImmutableSet.copyOf(detectedSoftware); } @@ -372,4 +374,42 @@ private void checkForZenMl( logger.atWarning().withCause(e).log("Unable to query '%s'.", loginUrl); } } + + private void checkForArgoCd( + Set software, NetworkService networkService, String startingUrl) { + logger.atInfo().log("probing Argo CD - custom fingerprint phase"); + + var uriAuthority = NetworkEndpointUtils.toUriAuthority(networkService.getNetworkEndpoint()); + var applicationsApiUrl = String.format("http://%s/%s", uriAuthority, "api/v1/applications"); + try { + HttpResponse apiApplicationsResponse = + httpClient.send( + post(applicationsApiUrl) + .setHeaders( + HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) + .build()); + + if (apiApplicationsResponse.status() != HttpStatus.INTERNAL_SERVER_ERROR + || apiApplicationsResponse.bodyString().isEmpty()) { + return; + } + + if (apiApplicationsResponse + .bodyString() + .get() + .contains( + "{\"error\":\"grpc: error while marshaling: proto: required field \\\"application\\\"" + + " not set\",\"code\":13,\"message\":\"grpc: error while marshaling: " + + "proto: required field \\\"application\\\" not set\"}")) { + software.add( + DetectedSoftware.builder() + .setSoftwareIdentity(SoftwareIdentity.newBuilder().setSoftware("argocd").build()) + .setRootPath(startingUrl) + .setContentHashes(ImmutableMap.of()) + .build()); + } + } catch (IOException e) { + logger.atWarning().withCause(e).log("Unable to query '%s'.", applicationsApiUrl); + } + } } From 1d5085fefe778a2590acab750e77b82c2bd99d86 Mon Sep 17 00:00:00 2001 From: JamesFoxxx Date: Fri, 11 Oct 2024 10:45:33 +0200 Subject: [PATCH 3/7] resolve confilicts and update the branch to master --- .../data/service_default_credentials.textproto | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto b/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto index 653b4e5ae..4da9fbe5f 100644 --- a/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto +++ b/google/detectors/credentials/generic_weak_credential_detector/src/main/resources/detectors/credentials/genericweakcredentialdetector/data/service_default_credentials.textproto @@ -83,3 +83,11 @@ service_default_credentials { default_usernames: "default" default_passwords: "" } + +service_default_credentials { + service_name: "argocd" + default_usernames: "admin" + default_passwords: "Password1!" + default_passwords: "password" + default_passwords: "YOUR-PASSWORD-HERE" +} \ No newline at end of file From 226dad8f80521b0a0c49d76a33e07c53bcb3f017 Mon Sep 17 00:00:00 2001 From: JamesFoxxx Date: Fri, 11 Oct 2024 11:29:58 +0200 Subject: [PATCH 4/7] add redirect for 307 status code when redirecting from http to https the http client doesn't redirect in response of this status code --- .../argocd/ArgoCdCredentialTester.java | 36 +++++++++++-------- .../web/WebServiceFingerprinter.java | 11 +++++- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java index 8be69e6c2..191182f1c 100644 --- a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java +++ b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java @@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkNotNull; import static com.google.tsunami.common.net.http.HttpRequest.get; import static com.google.tsunami.common.net.http.HttpRequest.post; +import static com.google.tsunami.common.net.http.HttpStatus.TEMPORARY_REDIRECT; import static java.nio.charset.StandardCharsets.UTF_8; import com.google.common.base.Strings; @@ -31,6 +32,7 @@ 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.plugins.detectors.credentials.genericweakcredentialdetector.provider.TestCredential; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.tester.CredentialTester; @@ -90,25 +92,29 @@ public ImmutableList testValidCredentials( private boolean isArgoCdAccessible(NetworkService networkService, TestCredential credential) { var uriAuthority = NetworkEndpointUtils.toUriAuthority(networkService.getNetworkEndpoint()); - var url = String.format("http://%s/", uriAuthority) + "api/v1/session"; + var url = String.format("http://%s/%s", uriAuthority, "api/v1/session"); try { logger.atInfo().log( "url: %s, username: %s, password: %s", url, credential.username(), credential.password().orElse("")); - HttpResponse response = - httpClient.send( - post(url) - .setHeaders( - HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) - .setRequestBody( - ByteString.copyFromUtf8( - String.format( - "{\"username\":\"%s\",\"password\":\"%s\"}", - credential.username(), credential.password().get()))) - .build()); - return response.status().isSuccess() - && response.bodyString().isPresent() - && bodyContainsToken(response.bodyString().get()); + ByteString loginReqBody = + ByteString.copyFromUtf8( + String.format( + "{\"username\":\"%s\",\"password\":\"%s\"}", + credential.username(), credential.password().get())); + HttpHeaders loginHeaders = + HttpHeaders.builder().addHeader("Content-Type", "application/json").build(); + HttpResponse loginResponse = + httpClient.send(post(url).setHeaders(loginHeaders).setRequestBody(loginReqBody).build()); + if (loginResponse.status() == TEMPORARY_REDIRECT) { + url = String.format("https://%s/%s", uriAuthority, "api/v1/session"); + loginResponse = + httpClient.send( + post(url).setHeaders(loginHeaders).setRequestBody(loginReqBody).build()); + } + return loginResponse.status().isSuccess() + && loginResponse.bodyString().isPresent() + && bodyContainsToken(loginResponse.bodyString().get()); } catch (IOException e) { logger.atWarning().withCause(e).log("Unable to query '%s'.", url); return false; diff --git a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java index d3f314847..c9d588603 100644 --- a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java +++ b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java @@ -20,6 +20,7 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.tsunami.common.net.http.HttpRequest.get; import static com.google.tsunami.common.net.http.HttpRequest.post; +import static com.google.tsunami.common.net.http.HttpStatus.TEMPORARY_REDIRECT; import static java.util.stream.Collectors.joining; import com.google.common.collect.ImmutableMap; @@ -388,7 +389,15 @@ private void checkForArgoCd( .setHeaders( HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) .build()); - + if (apiApplicationsResponse.status() == TEMPORARY_REDIRECT) { + applicationsApiUrl = String.format("https://%s/%s", uriAuthority, "api/v1/applications"); + apiApplicationsResponse = + httpClient.send( + post(applicationsApiUrl) + .setHeaders( + HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) + .build()); + } if (apiApplicationsResponse.status() != HttpStatus.INTERNAL_SERVER_ERROR || apiApplicationsResponse.bodyString().isEmpty()) { return; From 2e90a0d98368f90ed3f837209d36f2b3e54be4c5 Mon Sep 17 00:00:00 2001 From: JamesFoxxx Date: Fri, 11 Oct 2024 11:34:55 +0200 Subject: [PATCH 5/7] chores --- .../web/WebServiceFingerprinter.java | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java index c9d588603..556dd4e69 100644 --- a/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java +++ b/google/fingerprinters/web/src/main/java/com/google/tsunami/plugins/fingerprinters/web/WebServiceFingerprinter.java @@ -383,20 +383,14 @@ private void checkForArgoCd( var uriAuthority = NetworkEndpointUtils.toUriAuthority(networkService.getNetworkEndpoint()); var applicationsApiUrl = String.format("http://%s/%s", uriAuthority, "api/v1/applications"); try { + HttpHeaders apiApplicationsReqHeaders = + HttpHeaders.builder().addHeader("Content-Type", "application/json").build(); HttpResponse apiApplicationsResponse = - httpClient.send( - post(applicationsApiUrl) - .setHeaders( - HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) - .build()); + httpClient.send(post(applicationsApiUrl).setHeaders(apiApplicationsReqHeaders).build()); if (apiApplicationsResponse.status() == TEMPORARY_REDIRECT) { applicationsApiUrl = String.format("https://%s/%s", uriAuthority, "api/v1/applications"); apiApplicationsResponse = - httpClient.send( - post(applicationsApiUrl) - .setHeaders( - HttpHeaders.builder().addHeader("Content-Type", "application/json").build()) - .build()); + httpClient.send(post(applicationsApiUrl).setHeaders(apiApplicationsReqHeaders).build()); } if (apiApplicationsResponse.status() != HttpStatus.INTERNAL_SERVER_ERROR || apiApplicationsResponse.bodyString().isEmpty()) { From 100682fb4f77c29566fc30ca331e0d6e284aa940 Mon Sep 17 00:00:00 2001 From: JamesFoxxx Date: Wed, 16 Oct 2024 21:27:42 +0200 Subject: [PATCH 6/7] remove imports which we don't need anymore --- .../testers/argocd/ArgoCdCredentialTester.java | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java index 191182f1c..714f2c099 100644 --- a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java +++ b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTester.java @@ -16,15 +16,11 @@ package com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.argocd; import static com.google.common.base.Preconditions.checkNotNull; -import static com.google.tsunami.common.net.http.HttpRequest.get; import static com.google.tsunami.common.net.http.HttpRequest.post; import static com.google.tsunami.common.net.http.HttpStatus.TEMPORARY_REDIRECT; -import static java.nio.charset.StandardCharsets.UTF_8; -import com.google.common.base.Strings; import com.google.common.collect.ImmutableList; import com.google.common.flogger.GoogleLogger; -import com.google.gson.JsonObject; import com.google.gson.JsonParser; import com.google.gson.JsonSyntaxException; import com.google.protobuf.ByteString; @@ -32,20 +28,14 @@ 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.plugins.detectors.credentials.genericweakcredentialdetector.provider.TestCredential; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.tester.CredentialTester; import com.google.tsunami.proto.NetworkService; import java.io.IOException; -import java.util.Base64; import java.util.List; import javax.inject.Inject; -import jdk.jfr.ContentType; -import org.jsoup.Jsoup; -import org.jsoup.select.Elements; - /** Credential tester specifically for argocd. */ public final class ArgoCdCredentialTester extends CredentialTester { private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); From 190a4ca0104acb78f0d9eae5336cbc78a1239d5a Mon Sep 17 00:00:00 2001 From: JamesFoxxx Date: Wed, 16 Oct 2024 21:30:20 +0200 Subject: [PATCH 7/7] remove imports which we don't need anymore --- .../testers/argocd/ArgoCdCredentialTesterTest.java | 1 - 1 file changed, 1 deletion(-) diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java b/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java index ec0ab17f1..b6f68d013 100644 --- a/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java +++ b/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/argocd/ArgoCdCredentialTesterTest.java @@ -28,7 +28,6 @@ import com.google.tsunami.common.net.db.ConnectionProviderInterface; import com.google.tsunami.common.net.http.HttpClientModule; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.provider.TestCredential; -import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.argocd.ArgoCdCredentialTester; import com.google.tsunami.proto.NetworkService; import java.io.IOException; import java.nio.charset.StandardCharsets;