From efbb349ee4599366af1944ec045e4fd0381c049f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A5kon=20Nessj=C3=B8en?= Date: Sat, 6 Apr 2024 20:13:42 +0200 Subject: [PATCH] Handle invalid users and invalid passwords correctly --- src/mactelnetd.c | 57 +++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 30 deletions(-) diff --git a/src/mactelnetd.c b/src/mactelnetd.c index eb27ab5..00ff233 100644 --- a/src/mactelnetd.c +++ b/src/mactelnetd.c @@ -148,6 +148,7 @@ struct mt_connection { int pid; int wait_for_ack; int have_pass_salt; + int invalid_login; char username[MT_MNDP_MAX_STRING_SIZE]; unsigned char trypassword[32]; @@ -392,14 +393,19 @@ static void user_login(struct mt_connection *curconn, struct mt_mactelnet_hdr *p struct mt_packet pdata; unsigned char hashsum[32]; char hashdata[100]; - struct mt_credentials *user; + struct mt_credentials *user = NULL; char *slavename; int act_pass_len; + // In case we just got a duplicate login packet + if (curconn->state == STATE_ACTIVE) { + return; + } + /* Reparse user file before each login */ read_userfile(); - if ((user = find_user(curconn->username)) != NULL) { + if (!curconn->invalid_login && (user = find_user(curconn->username)) != NULL) { EVP_MD_CTX *context; const EVP_MD *md; unsigned int md_len; @@ -434,16 +440,12 @@ static void user_login(struct mt_connection *curconn, struct mt_mactelnet_hdr *p mtwei_id(curconn->username, user->password, curconn->pass_salt + MTWEI_PUBKEY_LEN, (uint8_t *)hashdata); mtwei_docryptos(&mtwei, curconn->private_key, curconn->client_key, curconn->pass_salt, (uint8_t *)hashdata, hashsum); } - - init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); - curconn->outcounter += add_control_packet(&pdata, MT_CPTYPE_END_AUTH, NULL, 0); - send_udp(curconn, &pdata); - - if (curconn->state == STATE_ACTIVE) { - return; - } } + init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); + curconn->outcounter += add_control_packet(&pdata, MT_CPTYPE_END_AUTH, NULL, 0); + send_udp(curconn, &pdata); + if (user == NULL || memcmp(hashsum, curconn->trypassword, use_md5 ? 17 : 32) != 0) { syslog(LOG_NOTICE, _("(%d) Invalid login by %s."), curconn->seskey, curconn->username); @@ -627,7 +629,8 @@ static void handle_data_packet(struct mt_connection *curconn, struct mt_mactelne send_udp(curconn, &pdata); - /* Don't change the username after the state is active */ + } else if (use_md5 == 0 && cpkt.cptype == MT_CPTYPE_BEGINAUTH) { + /* Ignore, the client wil immediately send a passsalt/encryption key control packet after this */ } else if (use_md5 == 0 && cpkt.cptype == MT_CPTYPE_PASSSALT && curconn->state != STATE_ACTIVE && cpkt.length > MTWEI_PUBKEY_LEN + 1) { strncpy(curconn->username, (const char *)cpkt.data, cpkt.length - MTWEI_PUBKEY_LEN); if (cpkt.length - strlen(curconn->username) - 1 == MTWEI_PUBKEY_LEN) { @@ -649,16 +652,20 @@ static void handle_data_packet(struct mt_connection *curconn, struct mt_mactelne mtwei_id(curconn->username, user->password, curconn->pass_salt + MTWEI_PUBKEY_LEN, validator); curconn->private_key = mtwei_keygen(&mtwei, curconn->pass_salt, validator); } else { - syslog(LOG_NOTICE, _("(%d) Invalid login by %s."), curconn->seskey, curconn->username); + /* Continue auth flow, so we do not let an attacker figure out if the user exists or not */ + curconn->have_pass_salt = 1; + curconn->invalid_login = 1; } init_packet(&pdata, MT_PTYPE_DATA, pkthdr->dstaddr, pkthdr->srcaddr, pkthdr->seskey, curconn->outcounter); - plen = add_control_packet(&pdata, MT_CPTYPE_PASSSALT, (curconn->pass_salt), user ? 49 : 33); + plen = add_control_packet(&pdata, MT_CPTYPE_PASSSALT, (curconn->pass_salt), 49); curconn->outcounter += plen; send_udp(curconn, &pdata); } else { syslog(LOG_NOTICE, _("(%d) Invalid mtwei key by %s."), curconn->seskey, curconn->username); + // Time out connection + curconn->state = STATE_CLOSED; } } else if (cpkt.cptype == MT_CPTYPE_USERNAME && curconn->state != STATE_ACTIVE) { @@ -681,31 +688,23 @@ static void handle_data_packet(struct mt_connection *curconn, struct mt_mactelne got_height_packet = 1; } else if (cpkt.cptype == MT_CPTYPE_TERM_TYPE) { - memcpy(curconn->terminal_type, cpkt.data, act_size = (cpkt.length > 30 - 1 ? 30 - 1 : cpkt.length)); curconn->terminal_type[act_size] = 0; - } else if (cpkt.cptype == MT_CPTYPE_PASSWORD && cpkt.length == 17) { - + } else if (cpkt.cptype == MT_CPTYPE_PASSWORD && (cpkt.length == 17 || cpkt.length == 32)) { #if defined(_POSIX_MEMLOCK_RANGE) && _POSIX_MEMLOCK_RANGE > 0 - mlock(curconn->trypassword, 17); + mlock(curconn->trypassword, cpkt.length); #endif - memcpy(curconn->trypassword, cpkt.data, 17); + memcpy(curconn->trypassword, cpkt.data, cpkt.length); got_pass_packet = 1; - } else if (cpkt.cptype == MT_CPTYPE_PASSWORD && cpkt.length == 32) { - -#if defined(_POSIX_MEMLOCK_RANGE) && _POSIX_MEMLOCK_RANGE > 0 - mlock(curconn->trypassword, 32); -#endif - memcpy(curconn->trypassword, cpkt.data, 32); + } else if (cpkt.cptype == MT_CPTYPE_PASSWORD && cpkt.length == 0) { got_pass_packet = 1; - + curconn->invalid_login = 1; } else if (cpkt.cptype == MT_CPTYPE_PLAINDATA) { - /* relay data from client to shell */ if (curconn->state == STATE_ACTIVE && curconn->ptsfd != -1) { - write_wrapped(curconn->ptsfd, cpkt.data, cpkt.length); + write_wrapped(curconn->ptsfd, cpkt.data, cpkt.length); } } else { @@ -722,7 +721,6 @@ static void handle_data_packet(struct mt_connection *curconn, struct mt_mactelne if (curconn->state == STATE_ACTIVE && (got_width_packet || got_height_packet)) { set_terminal_size(curconn->ptsfd, curconn->terminal_width, curconn->terminal_height); - } } @@ -744,7 +742,6 @@ static void handle_packet(unsigned char *data, int data_len, const struct sockad } switch (pkthdr.ptype) { - case MT_PTYPE_PING: if (pings++ > MT_MAXPPS) { /* Don't want it to wrap around back to the valid range */ @@ -851,7 +848,7 @@ static void handle_packet(unsigned char *data, int data_len, const struct sockad init_packet(&pdata, MT_PTYPE_ACK, pkthdr.dstaddr, pkthdr.srcaddr, pkthdr.seskey, pkthdr.counter); send_udp(curconn, &pdata); } - } + } if (0 && curconn != NULL) { printf("Packet, incounter %d, outcounter %d\n", curconn->incounter, curconn->outcounter); }