From f7ba7444e8fa4aae31070cc93822962d78941276 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Sun, 26 May 2013 18:39:24 +0800 Subject: improve auth failure delays to avoid indicating which users exist --- svr-auth.c | 48 +++++++++++++++++++++++++++--------------------- 1 file changed, 27 insertions(+), 21 deletions(-) (limited to 'svr-auth.c') diff --git a/svr-auth.c b/svr-auth.c index 1912660..01d4520 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -110,6 +110,7 @@ void recv_msg_userauth_request() { unsigned char *username = NULL, *servicename = NULL, *methodname = NULL; unsigned int userlen, servicelen, methodlen; + int valid_user = 0; TRACE(("enter recv_msg_userauth_request")) @@ -124,7 +125,6 @@ void recv_msg_userauth_request() { send_msg_userauth_banner(); } - username = buf_getstring(ses.payload, &userlen); servicename = buf_getstring(ses.payload, &servicelen); methodname = buf_getstring(ses.payload, &methodlen); @@ -141,12 +141,12 @@ void recv_msg_userauth_request() { dropbear_exit("unknown service in auth"); } - /* check username is good before continuing */ - if (checkusername(username, userlen) == DROPBEAR_FAILURE) { - /* username is invalid/no shell/etc - send failure */ - TRACE(("sending checkusername failure")) - send_msg_userauth_failure(0, 1); - goto out; + /* check username is good before continuing. + * the 'incrfail' varies depending on the auth method to + * avoid giving away which users exist on the system through + * the time delay. */ + if (checkusername(username, userlen) == DROPBEAR_SUCCESS) { + valid_user = 1; } /* user wants to know what methods are supported */ @@ -154,7 +154,8 @@ void recv_msg_userauth_request() { strncmp(methodname, AUTH_METHOD_NONE, AUTH_METHOD_NONE_LEN) == 0) { TRACE(("recv_msg_userauth_request: 'none' request")) - if (svr_opts.allowblankpass + if (valid_user + && svr_opts.allowblankpass && !svr_opts.noauthpass && !(svr_opts.norootpass && ses.authstate.pw_uid == 0) && ses.authstate.pw_passwd[0] == '\0') @@ -168,6 +169,7 @@ void recv_msg_userauth_request() { } else { + /* 'none' has no failure delay */ send_msg_userauth_failure(0, 0); goto out; } @@ -180,8 +182,10 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PASSWORD_LEN && strncmp(methodname, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN) == 0) { - svr_auth_password(); - goto out; + if (valid_user) { + svr_auth_password(); + goto out; + } } } #endif @@ -193,8 +197,10 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PASSWORD_LEN && strncmp(methodname, AUTH_METHOD_PASSWORD, AUTH_METHOD_PASSWORD_LEN) == 0) { - svr_auth_pam(); - goto out; + if (valid_user) { + svr_auth_pam(); + goto out; + } } } #endif @@ -204,12 +210,17 @@ void recv_msg_userauth_request() { if (methodlen == AUTH_METHOD_PUBKEY_LEN && strncmp(methodname, AUTH_METHOD_PUBKEY, AUTH_METHOD_PUBKEY_LEN) == 0) { - svr_auth_pubkey(); + if (valid_user) { + svr_auth_pubkey(); + } else { + /* pubkey has no failure delay */ + send_msg_userauth_failure(0, 0); + } goto out; } #endif - /* nothing matched, we just fail */ + /* nothing matched, we just fail with a delay */ send_msg_userauth_failure(0, 1); out: @@ -252,7 +263,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) { dropbear_log(LOG_WARNING, "Login attempt for nonexistent user from %s", svr_ses.addrstring); - send_msg_userauth_failure(0, 1); return DROPBEAR_FAILURE; } @@ -264,7 +274,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) { "Login attempt with wrong user %s from %s", ses.authstate.pw_name, svr_ses.addrstring); - send_msg_userauth_failure(0, 1); return DROPBEAR_FAILURE; } @@ -272,7 +281,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) { if (svr_opts.norootlogin && ses.authstate.pw_uid == 0) { TRACE(("leave checkusername: root login disabled")) dropbear_log(LOG_WARNING, "root login rejected"); - send_msg_userauth_failure(0, 1); return DROPBEAR_FAILURE; } @@ -301,7 +309,6 @@ static int checkusername(unsigned char *username, unsigned int userlen) { TRACE(("no matching shell")) dropbear_log(LOG_WARNING, "User '%s' has invalid shell, rejected", ses.authstate.pw_name); - send_msg_userauth_failure(0, 1); return DROPBEAR_FAILURE; goodshell: @@ -311,7 +318,6 @@ goodshell: TRACE(("uid = %d", ses.authstate.pw_uid)) TRACE(("leave checkusername")) return DROPBEAR_SUCCESS; - } /* Send a failure message to the client, in responds to a userauth_request. @@ -358,8 +364,8 @@ void send_msg_userauth_failure(int partial, int incrfail) { if (incrfail) { unsigned int delay; genrandom((unsigned char*)&delay, sizeof(delay)); - /* We delay for 300ms +- 50ms, 0.1ms granularity */ - delay = 250000 + (delay % 1000)*100; + /* We delay for 300ms +- 50ms */ + delay = 250000 + (delay % 100000); usleep(delay); ses.authstate.failcount++; } -- cgit v1.2.3 From 142a0f8a83262b278d7d4eeaada2801a039c94c8 Mon Sep 17 00:00:00 2001 From: Matt Johnston Date: Thu, 3 Oct 2013 23:04:11 +0800 Subject: Send PAM error messages as a banner messages Patch from Martin Donnelly, modified. --- auth.h | 1 + svr-auth.c | 17 ++++++----------- svr-authpam.c | 16 ++++++++++++++++ 3 files changed, 23 insertions(+), 11 deletions(-) (limited to 'svr-auth.c') diff --git a/auth.h b/auth.h index df6634e..3aed57b 100644 --- a/auth.h +++ b/auth.h @@ -36,6 +36,7 @@ void cli_authinitialise(); void recv_msg_userauth_request(); void send_msg_userauth_failure(int partial, int incrfail); void send_msg_userauth_success(); +void send_msg_userauth_banner(buffer *msg); void svr_auth_password(); void svr_auth_pubkey(); void svr_auth_pam(); diff --git a/svr-auth.c b/svr-auth.c index 01d4520..b8f0119 100644 --- a/svr-auth.c +++ b/svr-auth.c @@ -37,7 +37,6 @@ static void authclear(); static int checkusername(unsigned char *username, unsigned int userlen); -static void send_msg_userauth_banner(); /* initialise the first time for a session, resetting all parameters */ void svr_authinitialise() { @@ -82,24 +81,18 @@ static void authclear() { /* Send a banner message if specified to the client. The client might * ignore this, but possibly serves as a legal "no trespassing" sign */ -static void send_msg_userauth_banner() { +void send_msg_userauth_banner(buffer *banner) { TRACE(("enter send_msg_userauth_banner")) - if (svr_opts.banner == NULL) { - TRACE(("leave send_msg_userauth_banner: banner is NULL")) - return; - } CHECKCLEARTOWRITE(); buf_putbyte(ses.writepayload, SSH_MSG_USERAUTH_BANNER); - buf_putstring(ses.writepayload, buf_getptr(svr_opts.banner, - svr_opts.banner->len), svr_opts.banner->len); + buf_putstring(ses.writepayload, buf_getptr(banner, banner->len), + banner->len); buf_putstring(ses.writepayload, "en", 2); encrypt_packet(); - buf_free(svr_opts.banner); - svr_opts.banner = NULL; TRACE(("leave send_msg_userauth_banner")) } @@ -122,7 +115,9 @@ void recv_msg_userauth_request() { /* send the banner if it exists, it will only exist once */ if (svr_opts.banner) { - send_msg_userauth_banner(); + send_msg_userauth_banner(svr_opts.banner); + buf_free(svr_opts.banner); + svr_opts.banner = NULL; } username = buf_getstring(ses.payload, &userlen); diff --git a/svr-authpam.c b/svr-authpam.c index e84f076..a586727 100644 --- a/svr-authpam.c +++ b/svr-authpam.c @@ -142,6 +142,22 @@ pamConvFunc(int num_msg, (*respp) = resp; break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + + if (msg_len > 0) { + buffer * pam_err = buf_new(msg_len + 4); + buf_setpos(pam_err, 0); + buf_putbytes(pam_err, "\r\n", 2); + buf_putbytes(pam_err, (*msg)->msg, msg_len); + buf_putbytes(pam_err, "\r\n", 2); + buf_setpos(pam_err, 0); + + send_msg_userauth_banner(pam_err); + buf_free(pam_err); + } + break; + default: TRACE(("Unknown message type")) rc = PAM_CONV_ERR; -- cgit v1.2.3