Coordinated Disclosure Timeline

Summary

The public key signature checking code in pki_verify_data_signature has a logic bug, which, under certain conditions, could enable an attacker to bypass the check.

Product

libssh

Tested Version

0.10.4

Details

auth bypass in pki_verify_data_signature (GHSL-2023-085)

The function pki_verify_data_signature is used during pubkey authentication to check that the client has provided a valid cryptographic signature. It returns SSH_OK if the signature is valid, or SSH_ERROR if it isn’t. At the beginning of the function (line 3169), rc is initialized with SSH_ERROR to avoid accidentally returning SSH_OK :

int rc = SSH_ERROR;

Unfortunately, this is undermined on line 3185, where the value of rc is updated:

rc = pki_key_check_hash_compatible(pubkey, signature->hash_type);
if (rc != SSH_OK) {
    return SSH_ERROR;
}

signature->hash_type is an enum like SSH_DIGEST_SHA1 so it is easy for an attacker to supply an invalid signature that still passes the above check. So from line 3185 onward, the value of rc is SSH_OK and there is now a risk of pki_verify_data_signature accidentally returning SSH_OK. This could potentially happen on line 3221:

/* Create the context */
ctx = EVP_MD_CTX_new();
if (ctx == NULL) {
    SSH_LOG(SSH_LOG_TRACE,
            "Failed to create EVP_MD_CTX: %s",
            ERR_error_string(ERR_get_error(), NULL));
    goto out;
}

/* Verify the signature */
evp_rc = EVP_DigestVerifyInit(ctx, NULL, md, NULL, pkey);
if (evp_rc != 1){
    SSH_LOG(SSH_LOG_TRACE,
            "EVP_DigestVerifyInit() failed: %s",
            ERR_error_string(ERR_get_error(), NULL));
    goto out;
}

If one of the calls to either EVP_MD_CTX_new or EVP_DigestVerifyInit fails then the goto out will bypass the cryptographic check and the function will return SSH_OK:

out:
    if (ctx != NULL) {
        EVP_MD_CTX_free(ctx);
    }
    EVP_PKEY_free(pkey);
    return rc;

This bug may or may not be exploitable, depending on how libssh is used. Because libssh is a library, rather than a full standalone application, the exploitability will depend on how libssh has been integrated into another application and whether the integration enables one of these error conditions to be triggered. The most likely scenario for exploitation is that EVP_MD_CTX_new fails due to an out-of-memory error. An out-of-memory error will be much easier for an attacker to trigger if libssh has been integrated into an application that uses a lot of memory or has a memory leak bug (forgetting to free malloc’ed memory). Out-of-memory errors can also be much easier to trigger if the memory use of the application has been constrained, for example with ulimit or by running in a memory-constrained container.

Impact

This issue may enable a remote attacker to gain unauthorized access to another user’s account via ssh login.

CVE

Credit

This issue was discovered and reported by GHSL team member @kevinbackhouse (Kevin Backhouse).

Contact

You can contact the GHSL team at securitylab@github.com, please include a reference to GHSL-2023-085 in any communication regarding this issue.