AbreQueVoy
AbreQueVoy

Reputation: 2316

Loop hangs forever when server responds with SSH_MSG_DISCONNECT

For security scan reasons, I want to assess if local hosts handle SSH sessions in a way configured in /etc/ssh/sshd_config, e.g. MaxAuthTries limits, or PAM settings.

The scenario in this case is the following: the program wants to establish connection using non-existing user and incorrect password credentials and measure time each try takes.

Here's a working example:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <unistd.h>
#include <libssh/libssh.h>

#define BILLION 1000000000.0
#define REPETITIONS 10

int main(void) {
    struct timespec start, finish;
    time_t t = time(NULL);

    ssh_session session;

    int rc;
    int log_verbosity = SSH_LOG_WARNING;
    int session_status;
    session = ssh_new();

    const char *host = "127.0.0.1";
    const char *port = "22";
    const char *username = "someuser";
    const char *password = "somepass";

    char *reply;

    ssh_options_set(session, SSH_OPTIONS_HOST, host);
    ssh_options_set(session, SSH_OPTIONS_PORT_STR, port);
    ssh_options_set(session, SSH_OPTIONS_USER, username);
    ssh_options_set(session, SSH_OPTIONS_LOG_VERBOSITY, &log_verbosity);

    session_status = ssh_get_status(session);
    printf("Session status: %d\n", session_status);

    rc = ssh_connect(session);

    for (int i = 0; i < REPETITIONS; ++i) {
        clock_gettime(CLOCK_REALTIME, &start);

        if (rc != SSH_OK) {
            fprintf(stderr, "Error connecting to %s: %s\n", host, ssh_get_error(session));
            ssh_free(session);
            exit(-1);
        }

        if (ssh_userauth_password(session, NULL, password) == SSH_AUTH_SUCCESS) {
            reply = "Authentication succeeded with incorrect password.";
        }
        else {
            reply = "Authentication failed with incorrect password.";
            fprintf(stderr, "Error authenticating with incorrect password: %s\n", ssh_get_error(session));
        }
        clock_gettime(CLOCK_REALTIME, &finish);

        double time_spent = (finish.tv_sec - start.tv_sec) + (finish.tv_nsec - start.tv_nsec) / BILLION;

        struct tm tm = *localtime(&start.tv_sec);
        printf("[%d-%02d-%02d %02d:%02d:%02d] (%d/%d) Status: %s ",
                tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec,
                (i + 1), REPETITIONS, reply);
        printf("Elapsed time: %.4f seconds.\n", time_spent);
    }

    ssh_disconnect(session);
    ssh_free(session);

    return (0);
}

However, after reaching MaxAuthTries limit, the program started to hang forever. Logs didn't disclose any message when log_verbosity was unset:

Session status: 0
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:22:33] (1/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0882 seconds.
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:22:37] (2/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0439 seconds.
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:22:41] (3/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0437 seconds.
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:22:45] (4/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0438 seconds.
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:22:49] (5/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0440 seconds.
^C

I decided to experiment with SSH_OPTIONS_LOG_VERBOSITY. It was enough to increase the level by one to SSH_LOG_WARNING to get the information I needed (see the last line):

Session status: 0
[2024/01/15 13:45:57.322797, 1] ssh_config_parse_line:  Unsupported option: HashKnownHosts, line: 52
[2024/01/15 13:45:57.322947, 1] ssh_options_set:  Setting method: no known public key algorithm (+ssh-rsa)
[2024/01/15 13:45:57.322975, 1] ssh_options_set_algo:  Setting method: no allowed algorithm for method "server host key algo" (+ssh-rsa)
[2024/01/15 13:45:57.323442, 1] socket_callback_connected:  Socket connection callback: 1 (0)
[2024/01/15 13:45:57.337184, 1] ssh_known_hosts_read_entries:  Failed to open the known_hosts file '/etc/ssh/ssh_known_hosts': No such file or directory
[2024/01/15 13:46:01.482304, 1] ssh_packet_userauth_failure:  Access denied for 'password'. Authentication that can continue: publickey,password
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:45:57] (1/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0896 seconds.
[2024/01/15 13:46:05.525550, 1] ssh_packet_userauth_failure:  Access denied for 'password'. Authentication that can continue: publickey,password
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:46:01] (2/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0432 seconds.
[2024/01/15 13:46:09.569074, 1] ssh_packet_userauth_failure:  Access denied for 'password'. Authentication that can continue: publickey,password
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:46:05] (3/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0436 seconds.
[2024/01/15 13:46:13.612965, 1] ssh_packet_userauth_failure:  Access denied for 'password'. Authentication that can continue: publickey,password
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:46:09] (4/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0439 seconds.
[2024/01/15 13:46:17.656704, 1] ssh_packet_userauth_failure:  Access denied for 'password'. Authentication that can continue: publickey,password
Error authenticating with incorrect password: Access denied for 'password'. Authentication that can continue: publickey,password
[2024-01-15 13:46:13] (5/10) Status: Authentication failed with incorrect password. Elapsed time: 4.0437 seconds.
[2024/01/15 13:46:21.700467, 1] ssh_packet_disconnect_callback:  Received SSH_MSG_DISCONNECT: 2:Too many authentication failures

The SSH_MSG_DISCONNECT message seems not to be returned by libssh's ssh_get_error(session).

  1. How to extract the SSH_MSG_DISCONNECT from the output to be usable by the program?
  2. How to handle occurrences of SSH_MSG_DISCONNECT: would checking for them with if clause, and then closing current session and opening a new one be enough?

Upvotes: 1

Views: 89

Answers (0)

Related Questions