Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

HyperSQL weak credential tester #582

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

GiuseppePorcu
Copy link

Hi there,
This PR contains the implementation of the weak credential tester for HyperSQL.
As described within the Issue, the service has default credentials that if not changed allow an attacker to access the DBMS.

Below it is possible to find the necessary information for review:
Issue: #576
PR Testbed: google/security-testbeds#117
PR Scanner: google/tsunami-security-scanner#128
Thank you.

Copy link
Collaborator

@giacomo-doyensec giacomo-doyensec left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hello @GiuseppePorcu, thanks for your submission!

I found multiple issues that need to be addressed before proceeding with approval. I report them as follows:

  • Missing optimization of credential testing against the service: HyperSQL returns well-known error codes on exceptions, which can be leveraged to avoid unnecessary credential attempts, saving both time and network resources. I've provided suggestions for this optimization in this review (note that all suggestions I provided must be taken as recommendations. Please feel free to improve the code or adopt an alternative solution that you believe might be more optimal).

  • Missing proper handling of non-existent DB error: The DB name, testdb, used for the connection is hardcoded, as no default database is automatically created during service creation. The code does not handle the case when this DB does not exist. Error -458: database alias does not exist is returned when the name is not associated with anything. Please add logic to either find other potential valid names or minimize attempts to that service and log the results.

  • Missing entry in target_service.proto file: To generate the correct TargetService entry, add HSQLDB = 26; // HyperSQL (SQL Database) at the end of the enum TargetService in google/detectors/credentials/generic_weak_credential_detector/src/main/proto/target_service.proto. Also, please update the "Next ID" field in the comment above it.

  • Update tests accordingly.

Let me know if anything is unclear, and I'll be happy to provide further assistance.

import com.google.tsunami.proto.NetworkService;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Import the necessary libraries

Suggested change
import java.util.List;
import java.util.HashSet;
import java.util.List;

public final class HyperSQLCredentialTester extends CredentialTester {
private static final GoogleLogger logger = GoogleLogger.forEnclosingClass();
private final ConnectionProviderInterface connectionProvider;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add error code constant

Suggested change
private static final int HSQL_INVALID_USER_ERROR = -4001;


@Override
public boolean batched() {
return true;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Disable batching to avoid unnecessary credential attempts

Suggested change
return true;
return false;

Comment on lines +71 to +80
public ImmutableList<TestCredential> testValidCredentials(
NetworkService networkService, List<TestCredential> credentials) {
if (!canAccept(networkService)) {
return ImmutableList.of();
}

return credentials.stream()
.filter(cred -> isHsqlAccessible(networkService, cred))
.collect(toImmutableList());
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The invalidUsernames variable will contain a set of all usernames that have been tried and have failed, so they should be removed from the list of valid credentials.

Suggested change
public ImmutableList<TestCredential> testValidCredentials(
NetworkService networkService, List<TestCredential> credentials) {
if (!canAccept(networkService)) {
return ImmutableList.of();
}
return credentials.stream()
.filter(cred -> isHsqlAccessible(networkService, cred))
.collect(toImmutableList());
}
public ImmutableList<TestCredential> testValidCredentials(
NetworkService networkService, List<TestCredential> credentials) {
HashSet<String> invalidUsernames = new HashSet<String>();
if (!canAccept(networkService)) {
return ImmutableList.of();
}
return credentials.stream()
.filter(cred -> !invalidUsernames.contains(cred.username()))
.filter(cred -> isHsqlAccessible(networkService, cred, invalidUsernames))
.collect(toImmutableList());
}

* 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) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The method signature should be updated to accept the newly introduced variable.

Suggested change
private boolean isHsqlAccessible(NetworkService networkService, TestCredential credential) {
private boolean isHsqlAccessible(
NetworkService networkService, TestCredential credential, HashSet<String> invalidUsernames) {

Comment on lines +104 to +107
} catch (SQLException e) {
logger.atSevere().log(
"HyperSQLCredentialTester sql error: %s (%d)", e.getMessage(), e.getErrorCode());
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Error code -4001 is returned when the user is invalid.
Error code -4000 is returned when the user exists but the password is invalid.

This check optimizes testing by an order of magnitude, as it tries common passwords only on valid usernames.

Suggested change
} catch (SQLException e) {
logger.atSevere().log(
"HyperSQLCredentialTester sql error: %s (%d)", e.getMessage(), e.getErrorCode());
}
} catch (SQLException e) {
if (e.getErrorCode() == HSQL_INVALID_USER_ERROR) {
invalidUsernames.add(credential.username());
}
logger.atSevere().log(
"HyperSQLCredentialTester sql error: %s (%d)", e.getMessage(), e.getErrorCode());
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants