Package: release.debian.org Severity: normal Tags: jessie User: release.debian....@packages.debian.org Usertags: pu
Moritz Mühlenhoff from the Security Team suggested to fix dropbear's known vulnerabilities (CVE-2016-3116 and CVE-2016-740[6-8]) via a point release, since they don't warrant a DSA. I enclosed a debdiff against dropbear_2014.65-1.dsc. As mentioned in the Changelog, the backported patches address the following: * If X11 forwarding is enabled a user could bypass any "command=" restrictions in authorized_keys and run any command as their own user. Cherry-picked from 2016.72, changeset 1229:a3e8389e01ff https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff Fixes CVE-2016-3116 * Message printout was vulnerable to format string injection. If specific usernames including "%" symbols can be created on a system then an attacker could run arbitrary code as root when connecting to Dropbear server. Cherry-picked from 2016.74, changeset 1304:b66a483f3dcb https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb Fixes CVE-2016-7406 * dropbearconvert import of OpenSSH keys could run arbitrary code as the local dropbearconvert user when parsing malicious key files Cherry-picked from 2016.74, changeset 1306:34e6127ef02e, ignoring space/tab changes. https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e Fixes CVE-2016-7407 * dbclient could run arbitrary code as the local dbclient user if particular -m or -c arguments are provided. Cherry-picked from 2016.74, changeset 1303:eed9376a4ad6 https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6 Fixes CVE-2016-7408 Could you consider to have it included in the upcoming point release? (BTW I was not maintaining dropbear yet when Jessie was released. Therefore -1+deb8u1 looks like an NMU with invalid version number. Should I leave it like this, should I add the proper suffix, or should I add myself as maintainer?) Thanks! Cheers, -- Guilhem.
diff -u dropbear-2014.65/debian/changelog dropbear-2014.65/debian/changelog --- dropbear-2014.65/debian/changelog +++ dropbear-2014.65/debian/changelog @@ -1,3 +1,19 @@ +dropbear (2014.65-1+deb8u1) jessie; urgency=medium + + * Backport security fix from 2016.72: If X11 forwarding is enabled a user + could bypass any "command=" restrictions in authorized_keys and run any + command as their own user (CVE-2016-3116). + * Backport security fixes from 2016.74: + - Message printout was vulnerable to format string injection + (CVE-2016-7406). + - dropbearconvert import of OpenSSH keys could run arbitrary code as the + local dropbearconvert user when parsing malicious key files + (CVE-2016-7407). + - dbclient could run arbitrary code as the local dbclient user if + particular -m or -c arguments are provided (CVE-2016-7408). + + -- Guilhem Moulin <guil...@guilhem.org> Sat, 28 Jan 2017 18:23:47 +0100 + dropbear (2014.65-1) unstable; urgency=low [ Matt Johnston ] only in patch2: unchanged: --- dropbear-2014.65.orig/debian/diff/003-Validate-xauth-input.diff +++ dropbear-2014.65/debian/diff/003-Validate-xauth-input.diff @@ -0,0 +1,78 @@ +From 3d0143c962d2514b512b25d2518fa9e5993922e1 Mon Sep 17 00:00:00 2001 +From: Guilhem Moulin <guil...@guilhem.org> +Date: Sat, 28 Jan 2017 19:45:24 +0100 +Subject: [PATCH] Validate xauth input + +Cherry-picked from upstream changeset 1229:a3e8389e01ff +https://secure.ucc.asn.au/hg/dropbear/rev/a3e8389e01ff + +Fixes CVE-2016-3116. Quoting the 2016.72 release notes, + + If X11 forwarding is enabled a user could bypass any "command=" + restrictions in authorized_keys and run any command as their own + user (or perform other operations allowed by the "xauth" binary such + as writing files). It does not affect systems where command= + restrictions are not used. +--- + svr-x11fwd.c | 27 +++++++++++++++++++++++++-- + 1 file changed, 25 insertions(+), 2 deletions(-) + +diff --git a/svr-x11fwd.c b/svr-x11fwd.c +index ceca26a..5a489d4 100644 +--- a/svr-x11fwd.c ++++ b/svr-x11fwd.c +@@ -42,11 +42,29 @@ static void x11accept(struct Listener* listener, int sock); + static int bindport(int fd); + static int send_msg_channel_open_x11(int fd, struct sockaddr_in* addr); + ++/* Check untrusted xauth strings for metacharacters */ ++/* Returns DROPBEAR_SUCCESS/DROPBEAR_FAILURE */ ++static int ++xauth_valid_string(const char *s) ++{ ++ size_t i; ++ ++ for (i = 0; s[i] != '\0'; i++) { ++ if (!isalnum(s[i]) && ++ s[i] != '.' && s[i] != ':' && s[i] != '/' && ++ s[i] != '-' && s[i] != '_') { ++ return DROPBEAR_FAILURE; ++ } ++ } ++ return DROPBEAR_SUCCESS; ++} ++ ++ + /* called as a request for a session channel, sets up listening X11 */ + /* returns DROPBEAR_SUCCESS or DROPBEAR_FAILURE */ + int x11req(struct ChanSess * chansess) { + +- int fd; ++ int fd = -1; + + if (!svr_pubkey_allows_x11fwd()) { + return DROPBEAR_FAILURE; +@@ -62,6 +80,11 @@ int x11req(struct ChanSess * chansess) { + chansess->x11authcookie = buf_getstring(ses.payload, NULL); + chansess->x11screennum = buf_getint(ses.payload); + ++ if (xauth_valid_string(chansess->x11authprot) == DROPBEAR_FAILURE || ++ xauth_valid_string(chansess->x11authcookie) == DROPBEAR_FAILURE) { ++ dropbear_log(LOG_WARNING, "Bad xauth request"); ++ goto fail; ++ } + /* create listening socket */ + fd = socket(PF_INET, SOCK_STREAM, 0); + if (fd < 0) { +@@ -159,7 +182,7 @@ void x11setauth(struct ChanSess *chansess) { + return; + } + +- /* popen is a nice function - code is strongly based on OpenSSH's */ ++ /* code is strongly based on OpenSSH's */ + authprog = popen(XAUTH_COMMAND, "w"); + if (authprog) { + fprintf(authprog, "add %s %s %s\n", +-- +2.11.0 + only in patch2: unchanged: --- dropbear-2014.65.orig/debian/diff/004-Improve-exit-message-formatting.diff +++ dropbear-2014.65/debian/diff/004-Improve-exit-message-formatting.diff @@ -0,0 +1,115 @@ +From ce6faa122f49386583dd7d377bd3edb6cd22df76 Mon Sep 17 00:00:00 2001 +From: Guilhem Moulin <guil...@guilhem.org> +Date: Sat, 28 Jan 2017 18:17:28 +0100 +Subject: [PATCH] Improve exit message formatting + +Cherry-picked from upstream changeset 1304:b66a483f3dcb +https://secure.ucc.asn.au/hg/dropbear/rev/b66a483f3dcb + +Fixes CVE-2016-7406. Quoting the 2016.74 release notes, + + 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. +--- + cli-main.c | 17 +++++++++++------ + svr-session.c | 22 ++++++++++++---------- + 2 files changed, 23 insertions(+), 16 deletions(-) + +diff --git a/cli-main.c b/cli-main.c +index 0b4047c..3f8a43b 100644 +--- a/cli-main.c ++++ b/cli-main.c +@@ -89,17 +89,22 @@ int main(int argc, char ** argv) { + #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]; ++ /* 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); + } + + /* Do the cleanup first, since then the terminal will be reset */ +@@ -107,7 +112,7 @@ static void cli_dropbear_exit(int exitcode, const char* format, va_list param) { + /* Avoid printing onwards from terminal cruft */ + fprintf(stderr, "\n"); + +- _dropbear_log(LOG_INFO, fmtbuf, param); ++ dropbear_log(LOG_INFO, "%s", fullmsg); + exit(exitcode); + } + +diff --git a/svr-session.c b/svr-session.c +index 4d3c058..5d899aa 100644 +--- a/svr-session.c ++++ b/svr-session.c +@@ -144,30 +144,32 @@ void svr_session(int sock, int childpipe) { + + /* failure exit - format must be <= 100 chars */ + void svr_dropbear_exit(int exitcode, const char* format, va_list param) { ++ char exitmsg[150]; ++ char fullmsg[300]; + +- char fmtbuf[300]; ++ /* 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', %d 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); + + #ifdef USE_VFORK + /* For uclinux only the main server process should cleanup - we don't want +-- +2.11.0 + only in patch2: unchanged: --- dropbear-2014.65.orig/debian/diff/005-Merge-fixes-from-PuTTY-import.c.diff +++ dropbear-2014.65/debian/diff/005-Merge-fixes-from-PuTTY-import.c.diff @@ -0,0 +1,151 @@ +From c81c9206f4c2367d4ed134e0688d39b836bb4167 Mon Sep 17 00:00:00 2001 +From: Guilhem Moulin <guil...@guilhem.org> +Date: Sat, 28 Jan 2017 19:24:20 +0100 +Subject: [PATCH] Merge fixes from PuTTY import.c + +Cherry-picked from upstream changeset 1306:34e6127ef02e, ignoring space +vs. tab changes. https://secure.ucc.asn.au/hg/dropbear/rev/34e6127ef02e + +Fixes CVE-2016-7407. Quoting the 2016.74 release notes, + + Security: dropbearconvert import of OpenSSH keys could run arbitrary + code as the local dropbearconvert user when parsing malicious key + files +--- + keyimport.c | 56 +++++++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 43 insertions(+), 13 deletions(-) + +diff --git a/keyimport.c b/keyimport.c +index 66a7f55..f487e87 100644 +--- a/keyimport.c ++++ b/keyimport.c +@@ -60,6 +60,8 @@ static int openssh_write(const char *filename, sign_key *key, + 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); +@@ -241,12 +243,11 @@ static int ber_read_id_len(void *source, int sourcelen, + 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; +@@ -257,14 +258,16 @@ static int ber_read_id_len(void *source, int sourcelen, + 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--; +@@ -584,7 +587,8 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) + /* 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) { ++ if (ret < 0 || id != 16 || len < 0 || ++ key->keyblob+key->keyblob_len-p < len) { + errmsg = "ASN.1 decoding failure - wrong password?"; + goto error; + } +@@ -619,7 +623,7 @@ static sign_key *openssh_read(const char *filename, char * UNUSED(passphrase)) + 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; +@@ -1408,11 +1412,12 @@ int sshcom_encrypted(const char *filename, char **comment) + 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; +@@ -1602,8 +1607,8 @@ sign_key *sshcom_read(const char *filename, char *passphrase) + /* + * 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; + } +@@ -1670,7 +1675,8 @@ sign_key *sshcom_read(const char *filename, char *passphrase) + 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 */ + +@@ -1907,3 +1913,27 @@ int sshcom_write(const char *filename, sign_key *key, + 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 */ ++} +-- +2.11.0 + only in patch2: unchanged: --- dropbear-2014.65.orig/debian/diff/006-Improve-algorithm-list-parsing.diff +++ dropbear-2014.65/debian/diff/006-Improve-algorithm-list-parsing.diff @@ -0,0 +1,107 @@ +From a628d54c4f4481c02d7767e2e8767c9a71362ce1 Mon Sep 17 00:00:00 2001 +From: Guilhem Moulin <guil...@guilhem.org> +Date: Sat, 28 Jan 2017 19:37:39 +0100 +Subject: [PATCH] Improve algorithm list parsing + +Cherry-picked from upstream changeset 1303:eed9376a4ad6 +https://secure.ucc.asn.au/hg/dropbear/rev/eed9376a4ad6 + +Fixes CVE-2016-7408. Quoting the the 2016.74 release notes, + + 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. +--- + common-algo.c | 62 +++++++++++++++++++++++++++++------------------------------ + 1 file changed, 30 insertions(+), 32 deletions(-) + +diff --git a/common-algo.c b/common-algo.c +index e57f37c..e5aaaf1 100644 +--- a/common-algo.c ++++ b/common-algo.c +@@ -491,21 +491,6 @@ check_algo(const char* algo_name, algo_type *algos) + 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. */ +@@ -513,30 +498,43 @@ int + 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 /* ENABLE_USER_ALGO_LIST */ +-- +2.11.0 +
signature.asc
Description: PGP signature