Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 27 Apr 2001 08:00:56 -0500
From:      "Jacques A. Vidrine" <n@nectar.com>
To:        Cy Schubert - ITSD Open Systems Group <Cy.Schubert@uumail.gov.bc.ca>
Cc:        freebsd-security@freebsd.org
Subject:   Re: Security advisory: krb5 ftpd buffer overflows (fwd)
Message-ID:  <20010427080055.A30839@spawn.nectar.com>
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
References:  <200104270215.f3R2FHP61668@cwsys.cwsent.com>

next in thread | previous in thread | raw e-mail | index | archive | help
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: <ldvsniw5vq3.fsf@saint-elmos-fire.mit.edu>
> Date: Wed, 25 Apr 2001 20:51:48 -0400
> Reply-To: Tom Yu <tlyu@MIT.EDU>
> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM>
> From: Tom Yu <tlyu@MIT.EDU>
> 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




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010427080055.A30839>