# HG changeset patch # User Matt Johnston # Date 1469115522 -28800 # Node ID 2c9dac2d6707cc90554e7ff2fdfd3c12abf15820 # Parent 251c5f7a6e96c0b7770d9592013c2d31600b2496# Parent a4878e9aa73a1010e5419c4c5a88189031573e50 merge 2016.74 diff -r 251c5f7a6e96 -r 2c9dac2d6707 .hgsigs --- a/.hgsigs Sun Jun 19 20:38:38 2016 +0800 +++ b/.hgsigs Thu Jul 21 23:38:42 2016 +0800 @@ -21,3 +21,4 @@ 926e7275cef4f4f2a4251597ee4814748394824c 0 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 diff -r 251c5f7a6e96 -r 2c9dac2d6707 .hgtags --- a/.hgtags Sun Jun 19 20:38:38 2016 +0800 +++ b/.hgtags Thu Jul 21 23:38:42 2016 +0800 @@ -53,3 +53,4 @@ 9a944a243f08be6b22d32f166a0690eb4872462b DROPBEAR_2015.71 78b12b6549be08b0bea3da329b2578060a76ca31 DROPBEAR_2016.72 309e1c4a87682b6ca7d80b8555a1db416c3cb7ac DROPBEAR_2016.73 +0ed3d2bbf956cb8a9bf0f4b5a86b7dd9688205cb DROPBEAR_2016.74 diff -r 251c5f7a6e96 -r 2c9dac2d6707 CHANGES --- a/CHANGES Sun Jun 19 20:38:38 2016 +0800 +++ b/CHANGES Thu Jul 21 23:38:42 2016 +0800 @@ -1,3 +1,35 @@ +2016.74 - 21 July 2016 + +- Security: Message printout was vulnerable to format string injection. + + If specific usernames including "%" symbols can be created on a system + (validated by getpwnam()) then an attacker could run arbitrary code as root + when connecting to Dropbear server. + + A dbclient user who can control username or host arguments could potentially + run arbitrary code as the dbclient user. This could be a problem if scripts + or webpages pass untrusted input to the dbclient program. + +- Security: dropbearconvert import of OpenSSH keys could run arbitrary code as + the local dropbearconvert user when parsing malicious key files + +- Security: dbclient could run arbitrary code as the local dbclient user if + particular -m or -c arguments are provided. This could be an issue where + dbclient is used in scripts. + +- Security: dbclient or dropbear server could expose process memory to the + running user if compiled with DEBUG_TRACE and running with -v + + The security issues were reported by an anonymous researcher working with + Beyond Security's SecuriTeam Secure Disclosure www.beyondsecurity.com/ssd.html + +- Fix port forwarding failure when connecting to domains that have both + IPv4 and IPv6 addresses. The bug was introduced in 2015.68 + +- Fix 100% CPU use while waiting for rekey to complete. Thanks to Zhang Hui P + for the patch + + 2016.73 - 18 March 2016 - Support syslog in dbclient, option -o usesyslog=yes. Patch from Konstantin Tokarev diff -r 251c5f7a6e96 -r 2c9dac2d6707 buffer.c --- a/buffer.c Sun Jun 19 20:38:38 2016 +0800 +++ b/buffer.c Thu Jul 21 23:38:42 2016 +0800 @@ -141,9 +141,10 @@ /* increment the position by incr, negative values are allowed, to * decrement the pos*/ void buf_incrpos(buffer* buf, int incr) { - if (incr > BUF_MAX_INCR || - (unsigned int)((int)buf->pos + incr) > buf->len - || ((int)buf->pos + incr) < 0) { + if (incr > BUF_MAX_INCR + || incr < -BUF_MAX_INCR + || (unsigned int)((int)buf->pos + incr) > buf->len + || ((int)buf->pos + incr) < 0) { dropbear_exit("Bad buf_incrpos"); } buf->pos += incr; @@ -184,7 +185,7 @@ * the next len bytes from that position can be used */ unsigned char* buf_getptr(buffer* buf, unsigned int len) { - if (buf->pos + len > buf->len) { + if (len > BUF_MAX_INCR || buf->pos + len > buf->len) { dropbear_exit("Bad buf_getptr"); } return &buf->data[buf->pos]; @@ -194,7 +195,7 @@ * This allows writing past the used length, but not past the size */ unsigned char* buf_getwriteptr(buffer* buf, unsigned int len) { - if (buf->pos + len > buf->size) { + if (len > BUF_MAX_INCR || buf->pos + len > buf->size) { dropbear_exit("Bad buf_getwriteptr"); } return &buf->data[buf->pos]; diff -r 251c5f7a6e96 -r 2c9dac2d6707 cli-main.c --- a/cli-main.c Sun Jun 19 20:38:38 2016 +0800 +++ b/cli-main.c Thu Jul 21 23:38:42 2016 +0800 @@ -98,29 +98,30 @@ #endif /* DBMULTI stuff */ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { + char exitmsg[150]; + char fullmsg[300]; - char fmtbuf[300]; - char exitmsg[500]; + /* Note that exit message must be rendered before session cleanup */ + /* Render the formatted exit message */ + vsnprintf(exitmsg, sizeof(exitmsg), format, param); + + /* Add the prefix depending on session/auth state */ if (!sessinitdone) { - snprintf(fmtbuf, sizeof(fmtbuf), "Exited: %s", - format); + snprintf(fullmsg, sizeof(fullmsg), "Exited: %s", exitmsg); } else { - snprintf(fmtbuf, sizeof(fmtbuf), + snprintf(fullmsg, sizeof(fullmsg), "Connection to %s@%s:%s exited: %s", cli_opts.username, cli_opts.remotehost, - cli_opts.remoteport, format); + cli_opts.remoteport, exitmsg); } - /* Arguments to the exit printout may be unsafe to use after session_cleanup() */ - vsnprintf(exitmsg, sizeof(exitmsg), fmtbuf, param); - /* Do the cleanup first, since then the terminal will be reset */ session_cleanup(); /* Avoid printing onwards from terminal cruft */ fprintf(stderr, "\n"); - dropbear_log(LOG_INFO, "%s", exitmsg);; + dropbear_log(LOG_INFO, "%s", fullmsg); exit(exitcode); } diff -r 251c5f7a6e96 -r 2c9dac2d6707 common-algo.c --- a/common-algo.c Sun Jun 19 20:38:38 2016 +0800 +++ b/common-algo.c Thu Jul 21 23:38:42 2016 +0800 @@ -529,21 +529,6 @@ return NULL; } -static void -try_add_algo(const char *algo_name, algo_type *algos, - const char *algo_desc, algo_type * new_algos, int *num_ret) -{ - algo_type *match_algo = check_algo(algo_name, algos); - if (!match_algo) - { - dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", algo_name, algo_desc); - return; - } - - new_algos[*num_ret] = *match_algo; - (*num_ret)++; -} - /* Checks a user provided comma-separated algorithm list for available * options. Any that are not acceptable are removed in-place. Returns the * number of valid algorithms. */ @@ -551,30 +536,43 @@ check_user_algos(const char* user_algo_list, algo_type * algos, const char *algo_desc) { - algo_type new_algos[MAX_PROPOSED_ALGO]; - /* this has two passes. first we sweep through the given list of - * algorithms and mark them as usable=2 in the algo_type[] array... */ - int num_ret = 0; + algo_type new_algos[MAX_PROPOSED_ALGO+1]; char *work_list = m_strdup(user_algo_list); - char *last_name = work_list; + char *start = work_list; char *c; - for (c = work_list; *c; c++) + int n; + /* So we can iterate and look for null terminator */ + memset(new_algos, 0x0, sizeof(new_algos)); + for (c = work_list, n = 0; ; c++) { - if (*c == ',') - { + char oc = *c; + if (n >= MAX_PROPOSED_ALGO) { + dropbear_exit("Too many algorithms '%s'", user_algo_list); + } + if (*c == ',' || *c == '\0') { + algo_type *match_algo = NULL; *c = '\0'; - try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret); + match_algo = check_algo(start, algos); + if (match_algo) { + if (check_algo(start, new_algos)) { + TRACE(("Skip repeated algorithm '%s'", start)) + } else { + new_algos[n] = *match_algo; + n++; + } + } else { + dropbear_log(LOG_WARNING, "This Dropbear program does not support '%s' %s algorithm", start, algo_desc); + } c++; - last_name = c; + start = c; + } + if (oc == '\0') { + break; } } - try_add_algo(last_name, algos, algo_desc, new_algos, &num_ret); m_free(work_list); - - new_algos[num_ret].name = NULL; - - /* Copy one more as a blank delimiter */ - memcpy(algos, new_algos, sizeof(*new_algos) * (num_ret+1)); - return num_ret; + /* n+1 to include a null terminator */ + memcpy(algos, new_algos, sizeof(*new_algos) * (n+1)); + return n; } #endif /* DROPBEAR_USER_ALGO_LIST */ diff -r 251c5f7a6e96 -r 2c9dac2d6707 common-session.c --- a/common-session.c Sun Jun 19 20:38:38 2016 +0800 +++ b/common-session.c Thu Jul 21 23:38:42 2016 +0800 @@ -361,7 +361,7 @@ } if (!done) { - TRACE(("err: %s for '%s'\n", strerror(errno), linebuf)) + TRACE(("error reading remote ident: %s\n", strerror(errno))) ses.remoteclosed(); } else { /* linebuf is already null terminated */ diff -r 251c5f7a6e96 -r 2c9dac2d6707 debian/changelog --- a/debian/changelog Sun Jun 19 20:38:38 2016 +0800 +++ b/debian/changelog Thu Jul 21 23:38:42 2016 +0800 @@ -1,3 +1,9 @@ +dropbear (2016.74-0.1) unstable; urgency=low + + * New upstream release. + + -- Matt Johnston Thu, 21 Jul 2016 22:51:57 +0800 + dropbear (2016.73-0.1) unstable; urgency=low * New upstream release. diff -r 251c5f7a6e96 -r 2c9dac2d6707 keyimport.c --- a/keyimport.c Sun Jun 19 20:38:38 2016 +0800 +++ b/keyimport.c Thu Jul 21 23:38:42 2016 +0800 @@ -62,6 +62,8 @@ static int dropbear_write(const char*filename, sign_key * key); static sign_key *dropbear_read(const char* filename); +static int toint(unsigned u); + #if 0 static int sshcom_encrypted(const char *filename, char **comment); static struct ssh2_userkey *sshcom_read(const char *filename, char *passphrase); @@ -243,12 +245,11 @@ if ((*p & 0x1F) == 0x1F) { *id = 0; while (*p & 0x80) { - *id = (*id << 7) | (*p & 0x7F); p++, sourcelen--; if (sourcelen == 0) return -1; + *id = (*id << 7) | (*p & 0x7F); } - *id = (*id << 7) | (*p & 0x7F); p++, sourcelen--; } else { *id = *p & 0x1F; @@ -259,19 +260,26 @@ return -1; if (*p & 0x80) { + unsigned len; int n = *p & 0x7F; p++, sourcelen--; if (sourcelen < n) return -1; - *length = 0; + len = 0; while (n--) - *length = (*length << 8) | (*p++); + len = (len << 8) | (*p++); sourcelen -= n; + *length = toint(len); } else { *length = *p; p++, sourcelen--; } + if (*length < 0) { + printf("Negative ASN.1 length\n"); + return -1; + } + return p - (unsigned char *) source; } @@ -469,7 +477,7 @@ m_burn(buffer, sizeof(buffer)); return ret; - error: +error: m_burn(buffer, sizeof(buffer)); if (ret) { if (ret->keyblob) { @@ -584,8 +592,9 @@ /* Expect the SEQUENCE header. Take its absence as a failure to decrypt. */ ret = ber_read_id_len(p, key->keyblob_len, &id, &len, &flags); p += ret; - if (ret < 0 || id != 16) { - errmsg = "ASN.1 decoding failure - wrong password?"; + if (ret < 0 || id != 16 || len < 0 || + key->keyblob+key->keyblob_len-p < len) { + errmsg = "ASN.1 decoding failure"; goto error; } @@ -619,7 +628,7 @@ ret = ber_read_id_len(p, key->keyblob+key->keyblob_len-p, &id, &len, &flags); p += ret; - if (ret < 0 || id != 2 || + if (ret < 0 || id != 2 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -685,7 +694,7 @@ &id, &len, &flags); p += ret; /* id==4 for octet string */ - if (ret < 0 || id != 4 || + if (ret < 0 || id != 4 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -699,7 +708,7 @@ &id, &len, &flags); p += ret; /* id==0 */ - if (ret < 0 || id != 0) { + if (ret < 0 || id != 0 || len < 0) { errmsg = "ASN.1 decoding failure"; goto error; } @@ -708,7 +717,7 @@ &id, &len, &flags); p += ret; /* id==6 for object */ - if (ret < 0 || id != 6 || + if (ret < 0 || id != 6 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -747,7 +756,7 @@ &id, &len, &flags); p += ret; /* id==1 */ - if (ret < 0 || id != 1) { + if (ret < 0 || id != 1 || len < 0) { errmsg = "ASN.1 decoding failure"; goto error; } @@ -756,7 +765,7 @@ &id, &len, &flags); p += ret; /* id==3 for bit string */ - if (ret < 0 || id != 3 || + if (ret < 0 || id != 3 || len < 0 || key->keyblob+key->keyblob_len-p < len) { errmsg = "ASN.1 decoding failure"; goto error; @@ -1381,7 +1390,7 @@ memset(ret->keyblob, 0, ret->keyblob_size); m_free(ret->keyblob); } - memset(&ret, 0, sizeof(ret)); + memset(ret, 0, sizeof(*ret)); m_free(ret); } return NULL; @@ -1409,11 +1418,12 @@ pos = 8; if (key->keyblob_len < pos+4) goto done; /* key is far too short */ - pos += 4 + GET_32BIT(key->keyblob + pos); /* skip key type */ - if (key->keyblob_len < pos+4) + len = toint(GET_32BIT(key->keyblob + pos)); + if (len < 0 || len > key->keyblob_len - pos - 4) goto done; /* key is far too short */ - len = GET_32BIT(key->keyblob + pos); /* find cipher-type length */ - if (key->keyblob_len < pos+4+len) + pos += 4 + len; /* skip key type */ + len = toint(GET_32BIT(key->keyblob + pos)); /* find cipher-type length */ + if (len < 0 || len > key->keyblob_len - pos - 4) goto done; /* cipher type string is incomplete */ if (len != 4 || 0 != memcmp(key->keyblob + pos + 4, "none", 4)) answer = 1; @@ -1422,15 +1432,14 @@ *comment = dupstr(key->comment); memset(key->keyblob, 0, key->keyblob_size); m_free(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); m_free(key); return answer; } static int sshcom_read_mpint(void *data, int len, struct mpint_pos *ret) { - int bits; - int bytes; + unsigned bits, bytes; unsigned char *d = (unsigned char *) data; if (len < 4) @@ -1483,7 +1492,7 @@ struct ssh2_userkey *ret = NULL, *retkey; const struct ssh_signkey *alg; unsigned char *blob = NULL; - int blobsize, publen, privlen; + int blobsize = 0, publen, privlen; if (!key) return NULL; @@ -1603,8 +1612,8 @@ /* * Strip away the containing string to get to the real meat. */ - len = GET_32BIT(ciphertext); - if (len > cipherlen-4) { + len = toint(GET_32BIT(ciphertext)); + if (len < 0 || len > cipherlen-4) { errmsg = "containing string was ill-formed"; goto error; } @@ -1671,7 +1680,8 @@ publen = pos; pos += put_mp(blob+pos, x.start, x.bytes); privlen = pos - publen; - } + } else + return NULL; dropbear_assert(privlen > 0); /* should have bombed by now if not */ @@ -1695,7 +1705,7 @@ } memset(key->keyblob, 0, key->keyblob_size); m_free(key->keyblob); - memset(&key, 0, sizeof(key)); + memset(key, 0, sizeof(*key)); m_free(key); return ret; } @@ -1908,3 +1918,27 @@ return ret; } #endif /* ssh.com stuff disabled */ + +/* From PuTTY misc.c */ +static int toint(unsigned u) +{ + /* + * Convert an unsigned to an int, without running into the + * undefined behaviour which happens by the strict C standard if + * the value overflows. You'd hope that sensible compilers would + * do the sensible thing in response to a cast, but actually I + * don't trust modern compilers not to do silly things like + * assuming that _obviously_ you wouldn't have caused an overflow + * and so they can elide an 'if (i < 0)' test immediately after + * the cast. + * + * Sensible compilers ought of course to optimise this entire + * function into 'just return the input value'! + */ + if (u <= (unsigned)INT_MAX) + return (int)u; + else if (u >= (unsigned)INT_MIN) /* wrap in cast _to_ unsigned is OK */ + return INT_MIN + (int)(u - (unsigned)INT_MIN); + else + return INT_MIN; /* fallback; should never occur on binary machines */ +} diff -r 251c5f7a6e96 -r 2c9dac2d6707 netio.c diff -r 251c5f7a6e96 -r 2c9dac2d6707 svr-session.c --- a/svr-session.c Sun Jun 19 20:38:38 2016 +0800 +++ b/svr-session.c Thu Jul 21 23:38:42 2016 +0800 @@ -144,31 +144,33 @@ /* failure exit - format must be <= 100 chars */ void svr_dropbear_exit(int exitcode, const char* format, va_list param) { - - char fmtbuf[300]; + char exitmsg[150]; + char fullmsg[300]; int i; + /* Render the formatted exit message */ + vsnprintf(exitmsg, sizeof(exitmsg), format, param); + + /* Add the prefix depending on session/auth state */ if (!sessinitdone) { /* before session init */ - snprintf(fmtbuf, sizeof(fmtbuf), - "Early exit: %s", format); + snprintf(fullmsg, sizeof(fullmsg), "Early exit: %s", exitmsg); } else if (ses.authstate.authdone) { /* user has authenticated */ - snprintf(fmtbuf, sizeof(fmtbuf), + snprintf(fullmsg, sizeof(fullmsg), "Exit (%s): %s", - ses.authstate.pw_name, format); + ses.authstate.pw_name, exitmsg); } else if (ses.authstate.pw_name) { /* we have a potential user */ - snprintf(fmtbuf, sizeof(fmtbuf), + snprintf(fullmsg, sizeof(fullmsg), "Exit before auth (user '%s', %u fails): %s", - ses.authstate.pw_name, ses.authstate.failcount, format); + ses.authstate.pw_name, ses.authstate.failcount, exitmsg); } else { /* before userauth */ - snprintf(fmtbuf, sizeof(fmtbuf), - "Exit before auth: %s", format); + snprintf(fullmsg, sizeof(fullmsg), "Exit before auth: %s", exitmsg); } - _dropbear_log(LOG_INFO, fmtbuf, param); + dropbear_log(LOG_INFO, "%s", fullmsg); #if DROPBEAR_VFORK /* For uclinux only the main server process should cleanup - we don't want diff -r 251c5f7a6e96 -r 2c9dac2d6707 sysoptions.h --- a/sysoptions.h Sun Jun 19 20:38:38 2016 +0800 +++ b/sysoptions.h Thu Jul 21 23:38:42 2016 +0800 @@ -4,7 +4,7 @@ *******************************************************************/ #ifndef DROPBEAR_VERSION -#define DROPBEAR_VERSION "2016.73" +#define DROPBEAR_VERSION "2016.74" #endif #define LOCAL_IDENT "SSH-2.0-dropbear_" DROPBEAR_VERSION