CVE-2018-15473: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') (CWE-362)
value: OpenSSH through 7.7 is prone to a user enumeration vulnerability due to not delaying bailout for an invalid authenticating user until after the packet containing the request has been fully parsed, related to auth2-gss.c, auth2-hostbased.c, and auth2-pubkey.c.
CWE description: The product contains a code sequence that can run concurrently with other code, and the code sequence requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence that is operating concurrently.
CVSS v3 base score: 5.3
Published: 2018-08-17T19:29Z
Repository: https://github.com/openbsd/src
Language: C
Files changed: usr.bin/ssh/auth2-gss.c, usr.bin/ssh/auth2-hostbased.c, usr.bin/ssh/auth2-pubkey.c
Commit date: 2018-07-31 03:10:27 +0000
Commit message: delay bailout for invalid authenticating user until after the packet
containing the request has been fully parsed. Reported by Dariusz Tytko
and Michał Sajdak; ok deraadt

Diff: diff --git a/usr.bin/ssh/auth2-gss.c b/usr.bin/ssh/auth2-gss.c
index 649c830916a3..c919ef4c353b 100644
--- a/usr.bin/ssh/auth2-gss.c
+++ b/usr.bin/ssh/auth2-gss.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: auth2-gss.c,v 1.28 2018/07/10 09:13:30 djm Exp $ */
+/* $OpenBSD: auth2-gss.c,v 1.29 2018/07/31 03:10:27 djm Exp $ */
 
 /*
  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
@@ -63,13 +63,10 @@ userauth_gssapi(struct ssh *ssh)
 	u_int mechs;
 	OM_uint32 ms;
 	size_t len;
 	u_char *doid = NULL;
 
-	if (!authctxt->valid || authctxt->user == NULL)
-		return (0);
-
 	if ((r = sshpkt_get_u32(ssh, &mechs)) != 0)
 		fatal("%s: %s", __func__, ssh_err(r));
 
 	if (mechs == 0) {
 		debug("Mechanism negotiation is not supported");
@@ -99,10 +96,16 @@ userauth_gssapi(struct ssh *ssh)
 		free(doid);
 		authctxt->server_caused_failure = 1;
 		return (0);
 	}
 
+	if (!authctxt->valid || authctxt->user == NULL) {
+		debug2("%s: disabled because of invalid user", __func__);
+		free(doid);
+		return (0);
+	}
+
 	if (GSS_ERROR(PRIVSEP(ssh_gssapi_server_ctx(&ctxt, &goid)))) {
 		if (ctxt != NULL)
 			ssh_gssapi_delete_ctx(&ctxt);
 		free(doid);
 		authctxt->server_caused_failure = 1;
diff --git a/usr.bin/ssh/auth2-hostbased.c b/usr.bin/ssh/auth2-hostbased.c
index ad3355559342..fb5e5f422724 100644
--- a/usr.bin/ssh/auth2-hostbased.c
+++ b/usr.bin/ssh/auth2-hostbased.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: auth2-hostbased.c,v 1.35 2018/07/09 21:35:50 markus Exp $ */
+/* $OpenBSD: auth2-hostbased.c,v 1.36 2018/07/31 03:10:27 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -64,14 +64,10 @@ userauth_hostbased(struct ssh *ssh)
 	char *pkalg, *cuser, *chost;
 	u_char *pkblob, *sig;
 	size_t alen, blen, slen;
 	int r, pktype, authenticated = 0;
 
-	if (!authctxt->valid) {
-		debug2("%s: disabled because of invalid user", __func__);
-		return 0;
-	}
 	/* XXX use sshkey_froms() */
 	if ((r = sshpkt_get_cstring(ssh, &pkalg, &alen)) != 0 ||
 	    (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 ||
 	    (r = sshpkt_get_cstring(ssh, &chost, NULL)) != 0 ||
 	    (r = sshpkt_get_cstring(ssh, &cuser, NULL)) != 0 ||
@@ -114,10 +110,15 @@ userauth_hostbased(struct ssh *ssh)
 		logit("%s: key type %s not in HostbasedAcceptedKeyTypes",
 		    __func__, sshkey_type(key));
 		goto done;
 	}
 
+	if (!authctxt->valid || authctxt->user == NULL) {
+		debug2("%s: disabled because of invalid user", __func__);
+		goto done;
+	}
+
 	if ((b = sshbuf_new()) == NULL)
 		fatal("%s: sshbuf_new failed", __func__);
 	/* reconstruct packet */
 	if ((r = sshbuf_put_string(b, session_id2, session_id2_len)) != 0 ||
 	    (r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
diff --git a/usr.bin/ssh/auth2-pubkey.c b/usr.bin/ssh/auth2-pubkey.c
index 195da5e2111c..af9e5f04c45f 100644
--- a/usr.bin/ssh/auth2-pubkey.c
+++ b/usr.bin/ssh/auth2-pubkey.c
@@ -1,6 +1,6 @@
-/* $OpenBSD: auth2-pubkey.c,v 1.82 2018/07/11 18:55:11 markus Exp $ */
+/* $OpenBSD: auth2-pubkey.c,v 1.83 2018/07/31 03:10:27 djm Exp $ */
 /*
  * Copyright (c) 2000 Markus Friedl.  All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -84,23 +84,19 @@ format_key(const struct sshkey *key)
 static int
 userauth_pubkey(struct ssh *ssh)
 {
 	Authctxt *authctxt = ssh->authctxt;
 	struct passwd *pw = authctxt->pw;
-	struct sshbuf *b;
+	struct sshbuf *b = NULL;
 	struct sshkey *key = NULL;
-	char *pkalg, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
-	u_char *pkblob, *sig, have_sig;
+	char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
+	u_char *pkblob = NULL, *sig = NULL, have_sig;
 	size_t blen, slen;
 	int r, pktype;
 	int authenticated = 0;
 	struct sshauthopt *authopts = NULL;
 
-	if (!authctxt->valid) {
-		debug2("%s: disabled because of invalid user", __func__);
-		return 0;
-	}
 	if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 ||
 	    (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 ||
 	    (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0)
 		fatal("%s: parse request failed: %s", __func__, ssh_err(r));
 	pktype = sshkey_type_from_name(pkalg);
@@ -162,10 +158,15 @@ userauth_pubkey(struct ssh *ssh)
 			if ((r = sshbuf_put_string(b, session_id2,
 			    session_id2_len)) != 0)
 				fatal("%s: sshbuf_put_string session id: %s",
 				    __func__, ssh_err(r));
 		}
+		if (!authctxt->valid || authctxt->user == NULL) {
+			debug2("%s: disabled because of invalid user",
+			    __func__);
+			goto done;
+		}
 		/* reconstruct packet */
 		xasprintf(&userstyle, "%s%s%s", authctxt->user,
 		    authctxt->style ? ":" : "",
 		    authctxt->style ? authctxt->style : "");
 		if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 ||
@@ -178,32 +179,35 @@ userauth_pubkey(struct ssh *ssh)
 			fatal("%s: build packet failed: %s",
 			    __func__, ssh_err(r));
 #ifdef DEBUG_PK
 		sshbuf_dump(b, stderr);
 #endif
-
 		/* test for correct signature */
 		authenticated = 0;
 		if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) &&
 		    PRIVSEP(sshkey_verify(key, sig, slen,
 		    sshbuf_ptr(b), sshbuf_len(b),
 		    (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL,
 		    ssh->compat)) == 0) {
 			authenticated = 1;
 		}
 		sshbuf_free(b);
-		free(sig);
 		auth2_record_key(authctxt, authenticated, key);
 	} else {
 		debug("%s: test pkalg %s pkblob %s%s%s",
 		    __func__, pkalg, key_s,
 		    ca_s == NULL ? "" : " CA ",
 		    ca_s == NULL ? "" : ca_s);
 
 		if ((r = sshpkt_get_end(ssh)) != 0)
 			fatal("%s: %s", __func__, ssh_err(r));
 
+		if (!authctxt->valid || authctxt->user == NULL) {
+			debug2("%s: disabled because of invalid user",
+			    __func__);
+			goto done;
+		}
 		/* XXX fake reply and always send PK_OK ? */
 		/*
 		 * XXX this allows testing whether a user is allowed
 		 * to login: if you happen to have a valid pubkey this
 		 * message is sent. the message is NEVER sent at all
@@ -233,10 +237,11 @@ done:
 	free(userstyle);
 	free(pkalg);
 	free(pkblob);
 	free(key_s);
 	free(ca_s);
+	free(sig);
 	return authenticated;
 }
 
 static int
 match_principals_option(const char *principal_list, struct sshkey_cert *cert)

Vulnerable code: /* $OpenBSD: auth2-gss.c,v 1.28 2018/07/10 09:13:30 djm Exp $ */
	if (!authctxt->valid || authctxt->user == NULL)
		return (0);

/* $OpenBSD: auth2-hostbased.c,v 1.35 2018/07/09 21:35:50 markus Exp $ */
	if (!authctxt->valid) {
		debug2("%s: disabled because of invalid user", __func__);
		return 0;
	}
/* $OpenBSD: auth2-pubkey.c,v 1.82 2018/07/11 18:55:11 markus Exp $ */
	struct sshbuf *b;
	char *pkalg, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
	u_char *pkblob, *sig, have_sig;
	if (!authctxt->valid) {
		debug2("%s: disabled because of invalid user", __func__);
		return 0;
	}

		free(sig);
Fixed code: /* $OpenBSD: auth2-gss.c,v 1.29 2018/07/31 03:10:27 djm Exp $ */
	if (!authctxt->valid || authctxt->user == NULL) {
		debug2("%s: disabled because of invalid user", __func__);
		free(doid);
		return (0);
	}

/* $OpenBSD: auth2-hostbased.c,v 1.36 2018/07/31 03:10:27 djm Exp $ */
	if (!authctxt->valid || authctxt->user == NULL) {
		debug2("%s: disabled because of invalid user", __func__);
		goto done;
	}

/* $OpenBSD: auth2-pubkey.c,v 1.83 2018/07/31 03:10:27 djm Exp $ */
	struct sshbuf *b = NULL;
	char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL;
	u_char *pkblob = NULL, *sig = NULL, have_sig;
		if (!authctxt->valid || authctxt->user == NULL) {
			debug2("%s: disabled because of invalid user",
			    __func__);
			goto done;
		}
		if (!authctxt->valid || authctxt->user == NULL) {
			debug2("%s: disabled because of invalid user",
			    __func__);
			goto done;
		}
	free(sig);