From owner-freebsd-security Fri Apr 27 6: 1:15 2001 Delivered-To: freebsd-security@freebsd.org Received: from gw.nectar.com (gw.nectar.com [208.42.49.153]) by hub.freebsd.org (Postfix) with ESMTP id F1C1D37B423 for ; Fri, 27 Apr 2001 06:00:56 -0700 (PDT) (envelope-from nectar@nectar.com) Received: by gw.nectar.com (Postfix, from userid 1001) id 2207B193BD; Fri, 27 Apr 2001 08:00:56 -0500 (CDT) Date: Fri, 27 Apr 2001 08:00:56 -0500 From: "Jacques A. Vidrine" To: Cy Schubert - ITSD Open Systems Group Cc: freebsd-security@freebsd.org Subject: Re: Security advisory: krb5 ftpd buffer overflows (fwd) Message-ID: <20010427080055.A30839@spawn.nectar.com> Mail-Followup-To: "Jacques A. Vidrine" , Cy Schubert - ITSD Open Systems Group , freebsd-security@freebsd.org References: <200104270215.f3R2FHP61668@cwsys.cwsent.com> Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline User-Agent: Mutt/1.2.5i In-Reply-To: <200104270215.f3R2FHP61668@cwsys.cwsent.com>; from Cy.Schubert@uumail.gov.bc.ca on Thu, Apr 26, 2001 at 07:15:02PM -0700 X-Url: http://www.nectar.com/ Sender: owner-freebsd-security@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.org Will do today. Thanks. Please cc: maintainers on port issues. -- Jacques Vidrine / n@nectar.com / jvidrine@verio.net / nectar@FreeBSD.org On Thu, Apr 26, 2001 at 07:15:02PM -0700, Cy Schubert - ITSD Open Systems Group wrote: > Looks like we need to patch our krb5 port. > > > Regards, Phone: (250)387-8437 > Cy Schubert Fax: (250)387-5766 > Team Leader, Sun/Alpha Team Internet: Cy.Schubert@osg.gov.bc.ca > Open Systems Group, ITSD, ISTA > Province of BC > > > ------- Forwarded Message > > [headers removed] > Message-ID: > Date: Wed, 25 Apr 2001 20:51:48 -0400 > Reply-To: Tom Yu > Sender: Bugtraq List > From: Tom Yu > Subject: Security advisory: krb5 ftpd buffer overflows > X-To: kerberos@MIT.EDU > X-cc: krbdev@MIT.EDU > To: BUGTRAQ@SECURITYFOCUS.COM > > - -----BEGIN PGP SIGNED MESSAGE----- > > KRB5 FTPD BUFFER OVERFLOWS > > 2001-04-25 > > SUMMARY: > > Buffer overflows exist in the FTP daemon included with MIT krb5. > > IMPACT: > > * If anonymous FTP is enabled, a remote user may gain unauthorized > root access. > > * A user with access to a local account may gain unauthorized root > access. > > * A remote user who can successfully authenticate to the FTP daemon > may obtain unauthorized root access, regardless of whether anonymous > FTP is enabled or whether access is granted to a local account. > This vulnerability is believed to be somewhat difficult to exploit. > > VULNERABLE DISTRIBUTIONS: > > * MIT Kerberos 5, all releases. > > FIXES: > > The recommended approach is to apply the included patches and to > rebuild your ftpd. The included patches are against krb5-1.2.2. > > If you cannot patch your ftpd currently, workarounds include disabling > anonymous FTP access, if you have it enabled; this will limit the most > likely exploitation to users with local account access or who can > successfully authenticate to the daemon. > > This announcement and code patches related to it may be found on the > MIT Kerberos security advisory page at: > > http://web.mit.edu/kerberos/www/advisories/index.html > > The main MIT Kerberos web page is at: > > http://web.mit.edu/kerberos/www/index.html > > ACKNOWLEDGEMENTS: > > Thanks to Matt Crawford for providing some insight into the specific > ways in which krb5 ftpd is vulnerable. > > DETAILS: > > The remote vulnerability exploitable via anonymous FTP or local > account access results from a buffer overflow in code that calls > ftpglob(), a function responsible for expanding glob characters in > pathnames. Recent versions of ftpd (krb5-1.2 or later) should not > contain buffer overflows in the ftpglob() function itself. > > Remote users able to authenticate to the FTP daemon may be able to > exploit a lack of bounds-checking in calling radix_encode(). Login > access is not required; the ability to force arbitrary data to be > base64-encoded by radix_encode() is sufficient. > > This vulnerability is believed to be somewhat difficult to exploit > (but by no means impossible) due to the need for an attacker to inject > data that will base64-encode to the desired machine code and target > address. > > PATCHES AGAINST krb5-1.2.2: > > These patches are against the krb5-1.2.2 release. They may also apply > against earlier releases, though. The patches may also be found at: > > http://web.mit.edu/kerberos/www/advisories/ftpbuf_122_patch.txt > > Index: ftpcmd.y > =================================================================== > RCS file: /cvs/krbdev/krb5/src/appl/gssftp/ftpd/ftpcmd.y,v > retrieving revision 1.14.4.2 > diff -c -r1.14.4.2 ftpcmd.y > *** ftpcmd.y 2001/01/17 23:25:16 1.14.4.2 > - - --- ftpcmd.y 2001/04/25 20:16:45 > *************** > *** 805,815 **** > * This is a valid reply in some cases but not in others. > */ > if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) { > ! *(char **)&($$) = *ftpglob((char *) $1); > ! if (globerr != NULL) { > reply(550, globerr); > $$ = NULL; > ! } > free((char *) $1); > } else > $$ = $1; > - - --- 805,819 ---- > * This is a valid reply in some cases but not in others. > */ > if (logged_in && $1 && strncmp((char *) $1, "~", 1) == 0) { > ! char **vv; > ! > ! vv = ftpglob((char *) $1); > ! if (vv == NULL || globerr != NULL) { > reply(550, globerr); > $$ = NULL; > ! } else > ! $$ = *vv; > ! > free((char *) $1); > } else > $$ = $1; > Index: ftpd.c > =================================================================== > RCS file: /cvs/krbdev/krb5/src/appl/gssftp/ftpd/ftpd.c,v > retrieving revision 1.43.2.1 > diff -c -r1.43.2.1 ftpd.c > *** ftpd.c 2000/05/23 21:39:07 1.43.2.1 > - - --- ftpd.c 2001/04/25 20:16:48 > *************** > *** 761,767 **** > - - --- 761,777 ---- > int result; > #ifdef GSSAPI > if (auth_type && strcmp(auth_type, "GSSAPI") == 0) { > + int len; > + > authorized = ftpd_gss_userok(&client_name, name) == 0; > + len = sizeof("GSSAPI user is not authorized as " > + "; Password required.") > + + strlen(client_name.value) > + + strlen(name); > + if (len >= sizeof(buf)) { > + syslog(LOG_ERR, "user: username too long"); > + name = "[username too long]"; > + } > sprintf(buf, "GSSAPI user %s is%s authorized as %s", > client_name.value, authorized ? "" : " not", > name); > *************** > *** 772,778 **** > - - --- 782,800 ---- > #endif /* GSSAPI */ > #ifdef KRB5_KRB4_COMPAT > if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) { > + int len; > + > authorized = kuserok(&kdata,name) == 0; > + len = sizeof("Kerberos user .@ is not authorized as " > + "; Password required.") > + + strlen(kdata.pname) > + + strlen(kdata.pinst) > + + strlen(kdata.prealm) > + + strlen(name); > + if (len >= sizeof(buf)) { > + syslog(LOG_ERR, "user: username too long"); > + name = "[username too long]"; > + } > sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s", > kdata.pname, *kdata.pinst ? "." : "", > kdata.pinst, kdata.prealm, > *************** > *** 1179,1184 **** > - - --- 1201,1211 ---- > } else { > char line[FTP_BUFSIZ]; > > + if (strlen(cmd) + strlen(name) + 1 >= sizeof(line)) { > + syslog(LOG_ERR, "retrieve: filename too long"); > + reply(501, "filename too long"); > + return; > + } > (void) sprintf(line, cmd, name), name = line; > fin = ftpd_popen(line, "r"), closefunc = ftpd_pclose; > st.st_size = -1; > *************** > *** 1417,1422 **** > - - --- 1444,1453 ---- > return (file); > } > > + /* > + * XXX callers need to limit total length of output string to > + * FTP_BUFSIZ > + */ > #ifdef STDARG > secure_error(char *fmt, ...) > #else > *************** > *** 1616,1628 **** > { > char line[FTP_BUFSIZ]; > FILE *fin; > ! int c; > char str[FTP_BUFSIZ], *p; > > (void) sprintf(line, "/bin/ls -lgA %s", filename); > fin = ftpd_popen(line, "r"); > lreply(211, "status of %s:", filename); > p = str; > while ((c = getc(fin)) != EOF) { > if (c == '\n') { > if (ferror(stdout)){ > - - --- 1647,1665 ---- > { > char line[FTP_BUFSIZ]; > FILE *fin; > ! int c, n; > char str[FTP_BUFSIZ], *p; > > + if (strlen(filename) + sizeof("/bin/ls -lgA ") > + >= sizeof(line)) { > + reply(501, "filename too long"); > + return; > + } > (void) sprintf(line, "/bin/ls -lgA %s", filename); > fin = ftpd_popen(line, "r"); > lreply(211, "status of %s:", filename); > p = str; > + n = 0; > while ((c = getc(fin)) != EOF) { > if (c == '\n') { > if (ferror(stdout)){ > *************** > *** 1639,1645 **** > *p = '\0'; > reply(0, "%s", str); > p = str; > ! } else *p++ = c; > } > if (p != str) { > *p = '\0'; > - - --- 1676,1691 ---- > *p = '\0'; > reply(0, "%s", str); > p = str; > ! n = 0; > ! } else { > ! *p++ = c; > ! n++; > ! if (n >= sizeof(str)) { > ! reply(551, "output line too long"); > ! (void) ftpd_pclose(fin); > ! return; > ! } > ! } > } > if (p != str) { > *p = '\0'; > *************** > *** 1723,1728 **** > - - --- 1769,1778 ---- > > char cont_char = ' '; > > + /* > + * XXX callers need to limit total length of output string to > + * FTP_BUFSIZ bytes for now. > + */ > #ifdef STDARG > reply(int n, char *fmt, ...) > #else > *************** > *** 1744,1765 **** > #endif > > if (auth_type) { > ! char in[FTP_BUFSIZ], out[FTP_BUFSIZ]; > int length, kerror; > if (n) sprintf(in, "%d%c", n, cont_char); > else in[0] = '\0'; > strncat(in, buf, sizeof (in) - strlen(in) - 1); > #ifdef KRB5_KRB4_COMPAT > if (strcmp(auth_type, "KERBEROS_V4") == 0) { > ! if ((length = clevel == PROT_P ? > ! krb_mk_priv((unsigned char *)in, > ! (unsigned char *)out, > ! strlen(in), schedule, &kdata.session, > ! &ctrl_addr, &his_addr) > ! : krb_mk_safe((unsigned char *)in, > ! (unsigned char *)out, > ! strlen(in), &kdata.session, > ! &ctrl_addr, &his_addr)) == -1) { > syslog(LOG_ERR, > "krb_mk_%s failed for KERBEROS_V4", > clevel == PROT_P ? "priv" : "safe"); > - - --- 1794,1825 ---- > #endif > > if (auth_type) { > ! /* > ! * Deal with expansion in mk_{safe,priv}, > ! * radix_encode, gss_seal, plus slop. > ! */ > ! char in[FTP_BUFSIZ*3/2], out[FTP_BUFSIZ*3/2]; > int length, kerror; > if (n) sprintf(in, "%d%c", n, cont_char); > else in[0] = '\0'; > strncat(in, buf, sizeof (in) - strlen(in) - 1); > #ifdef KRB5_KRB4_COMPAT > if (strcmp(auth_type, "KERBEROS_V4") == 0) { > ! if (clevel == PROT_P) > ! length = krb_mk_priv((unsigned char *)in, > ! (unsigned char *)out, > ! strlen(in), > ! schedule, &kdata.session, > ! &ctrl_addr, > ! &his_addr); > ! else > ! length = krb_mk_safe((unsigned char *)in, > ! (unsigned char *)out, > ! strlen(in), > ! &kdata.session, > ! &ctrl_addr, > ! &his_addr); > ! if (length == -1) { > syslog(LOG_ERR, > "krb_mk_%s failed for KERBEROS_V4", > clevel == PROT_P ? "priv" : "safe"); > *************** > *** 1803,1815 **** > } > #endif /* GSSAPI */ > /* Other auth types go here ... */ > ! if (kerror = radix_encode(out, in, &length, 0)) { > syslog(LOG_ERR, "Couldn't encode reply (%s)", > radix_error(kerror)); > fputs(in,stdout); > } else > ! printf("%s%c%s", clevel == PROT_P ? "632" : "631", > ! n ? cont_char : '-', in); > } else { > if (n) printf("%d%c", n, cont_char); > fputs(buf, stdout); > - - --- 1863,1878 ---- > } > #endif /* GSSAPI */ > /* Other auth types go here ... */ > ! if (length >= sizeof(in) / 4 * 3) { > ! syslog(LOG_ERR, "input to radix_encode too long"); > ! fputs(in, stdout); > ! } else if (kerror = radix_encode(out, in, &length, 0)) { > syslog(LOG_ERR, "Couldn't encode reply (%s)", > radix_error(kerror)); > fputs(in,stdout); > } else > ! printf("%s%c%s", clevel == PROT_P ? "632" : "631", > ! n ? cont_char : '-', in); > } else { > if (n) printf("%d%c", n, cont_char); > fputs(buf, stdout); > *************** > *** 1822,1827 **** > - - --- 1885,1894 ---- > } > } > > + /* > + * XXX callers need to limit total length of output string to > + * FTP_BUFSIZ > + */ > #ifdef STDARG > lreply(int n, char *fmt, ...) > #else > *************** > *** 1866,1872 **** > > if (cp = strchr(cbuf,'\n')) > *cp = '\0'; > ! reply(500, "'%s': command not understood.", cbuf); > } > > delete_file(name) > - - --- 1933,1940 ---- > > if (cp = strchr(cbuf,'\n')) > *cp = '\0'; > ! reply(500, "'%.*s': command not understood.", > ! FTP_BUFSIZ - sizeof("'': command not understood."), cbuf); > } > > delete_file(name) > *************** > *** 2143,2149 **** > int code; > char *string; > { > ! reply(code, "%s: %s.", string, strerror(errno)); > } > > auth(type) > - - --- 2211,2233 ---- > int code; > char *string; > { > ! char *err_string; > ! size_t extra_len; > ! > ! err_string = strerror(errno); > ! if (err_string == NULL) > ! err_string = "(unknown error)"; > ! extra_len = strlen(err_string) + sizeof("(truncated): ."); > ! > ! /* > ! * XXX knows about FTP_BUFSIZ in reply() > ! */ > ! if (strlen(string) + extra_len > FTP_BUFSIZ) { > ! reply(code, "(truncated)%.*s: %s.", > ! FTP_BUFSIZ - extra_len, string, err_string); > ! } else { > ! reply(code, "%s: %s.", string, err_string); > ! } > } > > auth(type) > *************** > *** 2226,2231 **** > - - --- 2310,2319 ---- > secure_error("ADAT: krb_mk_safe failed"); > return(0); > } > + if (length >= (FTP_BUFSIZ - sizeof("ADAT=")) / 4 * 3) { > + secure_error("ADAT: reply too long"); > + return(0); > + } > if (kerror = radix_encode(out_buf, buf, &length, 0)) { > secure_error("Couldn't encode ADAT reply (%s)", > radix_error(kerror)); > *************** > *** 2360,2365 **** > - - --- 2448,2463 ---- > } > > if (out_tok.length) { > + if (out_tok.length >= ((FTP_BUFSIZ - sizeof("ADAT=")) > + / 4 * 3)) { > + secure_error("ADAT: reply too long"); > + syslog(LOG_ERR, "ADAT: reply too long"); > + (void) gss_release_cred(&stat_min, &server_creds); > + if (ret_flags & GSS_C_DELEG_FLAG) > + (void) gss_release_cred(&stat_min, > + &deleg_creds); > + return(0); > + } > if (kerror = radix_encode(out_tok.value, gbuf, &out_tok.length, > 0)) { > secure_error("Couldn't encode ADAT reply (%s)", > radix_error(kerror)); > *************** > *** 2458,2463 **** > - - --- 2556,2564 ---- > * n>=0 on success > * -1 on error > * -2 on security error > + * > + * XXX callers need to limit total length of output string to > + * FTP_BUFSIZ > */ > #ifdef STDARG > secure_fprintf(FILE *stream, char *fmt, ...) > *************** > *** 2575,2580 **** > - - --- 2676,2690 ---- > dir->d_name[2] == '\0') > continue; > > + if (strlen(dirname) + strlen(dir->d_name) > + + 1 /* slash */ > + + 2 /* CRLF */ > + + 1 > sizeof(nbuf)) { > + syslog(LOG_ERR, > + "send_file_list: pathname too long"); > + ret = -2; /* XXX */ > + goto data_err; > + } > sprintf(nbuf, "%s/%s", dirname, dir->d_name); > > /* > > - -----BEGIN PGP SIGNATURE----- > Version: PGP 6.5.8 > > iQCVAwUBOudtAKbDgE/zdoE9AQHhJgP/RFEDX/KL3YoavQSP9jJYO+GTg2MBfWRd > B4wakx2PYbt4LSGSNu/VyZKFGQhVqe0F38C7oGBrCyRzZfC5MPSBmo/B6pxaeM9P > oUo3Bny+JgybyOZ9wp7pGW2cRHH/zKbakrsaGFWgeAucceZeDana+TEZqGlQLIst > wfRPsXU7WA8= > =+0c0 > - -----END PGP SIGNATURE----- > > ------- End of Forwarded Message > > > > > To Unsubscribe: send mail to majordomo@FreeBSD.org > with "unsubscribe freebsd-security" in the body of the message > To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-security" in the body of the message