The OpenNET Project
 
Search (keywords):  SOFT ARTICLES TIPS & TRICKS SECURITY
LINKS NEWS MAN DOCUMENTATION


Security advisory: krb5 ftpd buffer overflows


<< Previous INDEX Search src Set bookmark Go to bookmark Next >>
Date: Wed, 25 Apr 2001 20:51:48 -0400
From: Tom Yu <[email protected]>
To: [email protected]
Subject: Security advisory: krb5 ftpd buffer overflows

-----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-----

<< Previous INDEX Search src Set bookmark Go to bookmark Next >>



Партнёры:
PostgresPro
Inferno Solutions
Hosting by Hoster.ru
Хостинг:

Закладки на сайте
Проследить за страницей
Created 1996-2025 by Maxim Chirkov
Добавить, Поддержать, Вебмастеру