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 b27c7693c..3bde33709 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 @@ -37,18 +37,18 @@ import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.provider.Top100Passwords; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.tester.CredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.grafana.GrafanaCredentialTester; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.hive.HiveCredentialTester; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.hsqldb.HyperSQLCredentialTester; 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.mlflow.MlFlowCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.mysql.MysqlCredentialTester; -import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.hive.HiveCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.ncrack.NcrackCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.postgres.PostgresCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.rabbitmq.RabbitMQCredentialTester; -import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.wordpress.WordpressCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.rstudio.RStudioCredentialTester; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.wordpress.WordpressCredentialTester; import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.testers.zenml.ZenMlCredentialTester; - import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; @@ -80,6 +80,7 @@ protected void configurePlugin() { credentialTesterBinder.addBinding().to(RStudioCredentialTester.class); credentialTesterBinder.addBinding().to(RabbitMQCredentialTester.class); credentialTesterBinder.addBinding().to(ZenMlCredentialTester.class); + credentialTesterBinder.addBinding().to(HyperSQLCredentialTester.class); Multibinder credentialProviderBinder = Multibinder.newSetBinder(binder(), CredentialProvider.class); diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/hsqldb/HyperSQLCredentialTester.java b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/hsqldb/HyperSQLCredentialTester.java new file mode 100644 index 000000000..0a52e88bc --- /dev/null +++ b/google/detectors/credentials/generic_weak_credential_detector/src/main/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/hsqldb/HyperSQLCredentialTester.java @@ -0,0 +1,110 @@ +/* + * 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.credentials.genericweakcredentialdetector.testers.hsqldb; + +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.collect.ImmutableMap; +import com.google.common.flogger.GoogleLogger; +import com.google.tsunami.common.data.NetworkEndpointUtils; +import com.google.tsunami.common.data.NetworkServiceUtils; +import com.google.tsunami.common.net.db.ConnectionProviderInterface; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.proto.TargetService; +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.sql.Connection; +import java.sql.SQLException; +import java.util.List; +import javax.inject.Inject; + +/** Credential tester specifically for HyperSQL. */ +public final class HyperSQLCredentialTester extends CredentialTester { + private static final GoogleLogger logger = GoogleLogger.forEnclosingClass(); + private final ConnectionProviderInterface connectionProvider; + + private static final ImmutableMap SERVICE_MAP = + ImmutableMap.of("jdbc", TargetService.HSQLDB); + + @Inject + HyperSQLCredentialTester(ConnectionProviderInterface connectionProvider) { + this.connectionProvider = checkNotNull(connectionProvider); + } + + @Override + public String name() { + return "HyperSQLCredentialTester"; + } + + @Override + public String description() { + return "HyperSQL credential tester."; + } + + @Override + public boolean canAccept(NetworkService networkService) { + String serviceName = NetworkServiceUtils.getServiceName(networkService); + return SERVICE_MAP.containsKey(serviceName); + } + + @Override + public boolean batched() { + return true; + } + + @Override + public ImmutableList testValidCredentials( + NetworkService networkService, List credentials) { + if (!canAccept(networkService)) { + return ImmutableList.of(); + } + + return credentials.stream() + .filter(cred -> isHsqlAccessible(networkService, cred)) + .collect(toImmutableList()); + } + + /** + * Using testdb as database name since hsqldb requires a database name in order to perform the + * connection However hsqldb does not create a default database during installation testdb is the + * database name used within the documentation + */ + private boolean isHsqlAccessible(NetworkService networkService, TestCredential credential) { + try { + var url = + String.format( + "jdbc:hsqldb:hsql://%s/testdb", + NetworkEndpointUtils.toUriAuthority(networkService.getNetworkEndpoint())); + logger.atInfo().log( + "url: %s, username: %s, password: %s", + url, credential.username(), credential.password().orElse("")); + Connection conn = + connectionProvider.getConnection( + url, credential.username(), credential.password().orElse("")); + + if (conn != null) { + logger.atInfo().log("Connected to the Hyper SQL server successfully."); + return true; + } + } catch (SQLException e) { + logger.atSevere().log( + "HyperSQLCredentialTester sql error: %s (%d)", e.getMessage(), e.getErrorCode()); + } + 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 653b4e5ae..fa154af53 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,12 @@ service_default_credentials { default_usernames: "default" default_passwords: "" } + +service_default_credentials { + service_name: "jdbc" + # https://hsqldb.org/doc/guide/running-chapt.html + default_usernames: "sa" + default_passwords: "" +} + + diff --git a/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/hsqldb/HyperSQLCredentialTesterTest.java b/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/hsqldb/HyperSQLCredentialTesterTest.java new file mode 100644 index 000000000..68ae1299b --- /dev/null +++ b/google/detectors/credentials/generic_weak_credential_detector/src/test/java/com/google/tsunami/plugins/detectors/credentials/genericweakcredentialdetector/testers/hsqldb/HyperSQLCredentialTesterTest.java @@ -0,0 +1,120 @@ +/* + * 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.credentials.genericweakcredentialdetector.testers.hsqldb; + +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.tsunami.common.net.db.ConnectionProviderInterface; +import com.google.tsunami.plugins.detectors.credentials.genericweakcredentialdetector.provider.TestCredential; +import com.google.tsunami.proto.NetworkService; +import java.sql.Connection; +import java.util.Optional; +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 HyperSQLCredentialTester}. */ +@RunWith(JUnit4.class) +public class HyperSQLCredentialTesterTest { + @Rule public MockitoRule rule = MockitoJUnit.rule(); + @Mock private ConnectionProviderInterface mockConnectionProvider; + @Mock private Connection mockConnection; + private HyperSQLCredentialTester tester; + + private static final TestCredential WEAK_CRED_1 = + TestCredential.create("sa", Optional.of("test")); + private static final TestCredential WEAK_CRED_2 = + TestCredential.create("admin", Optional.of("weakpassword")); + + @Before + public void setup() { + tester = new HyperSQLCredentialTester(mockConnectionProvider); + } + + @Test + public void detect_weakCredExists_returnsWeakCred() throws Exception { + when(mockConnectionProvider.getConnection( + "jdbc:hsqldb:hsql://example.com:9001/testdb", "sa", "test")) + .thenReturn(mockConnection); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint(forHostnameAndPort("example.com", 9001)) + .setServiceName("jdbc") + .build(); + + assertThat(tester.testValidCredentials(targetNetworkService, ImmutableList.of(WEAK_CRED_1))) + .containsExactly(WEAK_CRED_1); + } + + @Test + public void detect_weakCredsExist_returnsAllWeakCreds() throws Exception { + when(mockConnectionProvider.getConnection( + "jdbc:hsqldb:hsql://example.com:9001/testdb", "sa", "test")) + .thenReturn(mockConnection); + when(mockConnectionProvider.getConnection( + "jdbc:hsqldb:hsql://example.com:9001/testdb", "admin", "weakpassword")) + .thenReturn(mockConnection); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint(forHostnameAndPort("example.com", 9001)) + .setServiceName("jdbc") + .build(); + + assertThat( + tester.testValidCredentials( + targetNetworkService, ImmutableList.of(WEAK_CRED_1, WEAK_CRED_2))) + .containsExactly(WEAK_CRED_1, WEAK_CRED_2); + } + + @Test + public void detect_noWeakCred_returnsNoCred() throws Exception { + when(mockConnectionProvider.getConnection( + "jdbc:hsqldb:hsql://example.com:9001/testdb", "hardtoguess", "hardtoguess")) + .thenReturn(mockConnection); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint(forHostnameAndPort("example.com", 9001)) + .setServiceName("jdbc") + .build(); + + assertThat(tester.testValidCredentials(targetNetworkService, ImmutableList.of(WEAK_CRED_1))) + .isEmpty(); + } + + @Test + public void detect_mySqlService_skips() throws Exception { + when(mockConnectionProvider.getConnection(any(), any(), any())).thenReturn(mockConnection); + NetworkService targetNetworkService = + NetworkService.newBuilder() + .setNetworkEndpoint(forHostnameAndPort("example.com", 9001)) + .setServiceName("mysql") + .build(); + + assertThat(tester.testValidCredentials(targetNetworkService, ImmutableList.of(WEAK_CRED_1))) + .isEmpty(); + verifyNoInteractions(mockConnectionProvider); + } +}