From owner-freebsd-security Tue Oct 24 06:16:20 1995 Return-Path: owner-security Received: (from root@localhost) by freefall.freebsd.org (8.6.12/8.6.6) id GAA10831 for security-outgoing; Tue, 24 Oct 1995 06:16:20 -0700 Received: from time.cdrom.com (time.cdrom.com [192.216.222.226]) by freefall.freebsd.org (8.6.12/8.6.6) with ESMTP id GAA10825 for ; Tue, 24 Oct 1995 06:16:14 -0700 Received: from localhost (localhost [127.0.0.1]) by time.cdrom.com (8.6.12/8.6.9) with SMTP id GAA11891 for ; Tue, 24 Oct 1995 06:15:59 -0700 Prev-Resent: Tue, 24 Oct 1995 06:15:58 -0700 Prev-Resent: "security@freebsd.org " Received: from tertius.mit.edu (TERTIUS.MIT.EDU [18.245.0.93]) by time.cdrom.com (8.6.12/8.6.9) with ESMTP id AAA10911 for ; Tue, 24 Oct 1995 00:24:38 -0700 Received: (from hartmans@localhost) by tertius.mit.edu (8.6.12/8.6.9) id DAA15744; Tue, 24 Oct 1995 03:24:22 -0400 Date: Tue, 24 Oct 1995 03:24:22 -0400 From: Sam Hartman Message-Id: <199510240724.DAA15744@tertius.mit.edu> To: security-alert@sgi.com, miguel@sgi.com, security-alert@hp.com, rich.boren@cxo.mts.dec.com, eichin@cygnus.com, bjaspan@cam.ov.com, volkerdi@wcarchive.cdrom.com, mycroft@mit.edu, bruce@pixar.com, tobias@server.et-inf.fho-emden.de, ache@astral.msk.su, jkh@time.cdrom.com, bugs@redhat.com, mark.graff@eng.sun.com CC: tytso@mit.edu, jis@mit.edu, hartmans@mit.edu, brlewis@mit.edu, jhawk@mit.edu, cert@cert.org, lrr@cert.org Subject: timely: details on announcement of telnetd vulnerability Reply-to: hartmans@mit.edu, tytso@mit.edu Resent-To: security@freebsd.org Resent-Date: Tue, 24 Oct 1995 06:15:58 -0700 Resent-Message-ID: <11889.814540558@time.cdrom.com> Resent-From: "Jordan K. Hubbard" Sender: owner-security@freebsd.org Precedence: bulk -----BEGIN PGP SIGNED MESSAGE----- History and Preface NOTICE: Because we have found a temporary work around, Theodore Ts'o has asked me to announce this bug publicly next Tuesday. The announcement will be issued soon after 10:30 EDT on Tuesday, October 31, 1995. If your patch isn't listed, tell me about it by Monday, October 30. If your system is vulnerable and the suggested quick fix won't work, it's probably in your best interest to tell me this too; that way your users won't get a false sense of security. For such reports to be useful, I need to receive them by this Thursday evening. Also, if there are comments that can help the structure of this memo as it evolves from a memo for vendors to a bug description/announcement, let me know. I know the following changes will be made before the announcement: * The 'Public Exposure' section will go away -- the announcement will be very public, so exposure will no longer be an interesting issue. * Information in 'Availability of Patches' regarding the announcement date will go away. * A section describing how to test for the bug (not an exploit, although it'll probably have to be close enough that anyone who understands how to build a new library on their platform can figure out an exploit) will be added. * The section on verifying patches will be cleaned up/expanded. Things you should note that have changed: * Bugs have been found in the first Borman patch, and in the sample patch I originally sent out. * A few more environment variables have been added. The latest is ELF_LD_LIBRARY_PATH, which, according to Linux documentation is used as an ELF library search path. The code tends to disagree with the documentation, using LD_ELF_LIBRARY_PATH; I'm still waiting to hear from H. J. Lu on this one. * Other information has been added about patches. * Clarification: if you require external authentication, only your valid users can break in. On Sunday, October 15, I discovered a bug in some versions of telnetd on some platforms that allows a user making a connection to cause login to load an alternate C library from an arbitrary location in the filesystem of the machine running telnetd. In the case of machines mounting distributed filespaces such as AFS or NFS, containing publicly writable anonymous FTP directories, or on which the user already has a non-root account, it is possible to gain root access. The problem is that telnetd will allow the client to pass LD_LIBRARY_PATH, LD_PRELOAD, and other run-time linker options into the process environment of the process that runs login. If the runtime linker honors these options for login, the attacker can cause a custom libc to be loaded. Such a libc could, for example, start a shell whenever some function like crypt() is called. If login calls this function before the setuid call, then the attacker will gain root access. Note that the user must be able to convince telnetd to run login in order for this attack to be successful. In particular, if an authentication system such as Kerberos is employed, and the telnetd requires authentication, then only users with valid accounts will be able to use this attack. Quick Fix Most runtime linkers treat set user-id and set group-id programs specially: for these programs the environment variables are ignored when the program is run by a user other than the owner of the file, or by someone in a group other than the primary group of the file. Even though login is often set user-id, the environment variables are used because it is run by telnetd which runs as root. However, if you force login to be set-uid another user, or set-gid, you can cause the runtime linker to ignore the environment variables, protecting your system from this attack until your vendor prepares a patch. It turns out that login needs to be root, so making login set-uid doesn't work. However, there is nothing that stops you from making login set-gid. To do so, follow these steps: 1) Create a new group (you might want to call it 'login', 'telnet_bug', tnbug', '__login' or something of the sort). In the rest of this document, I will assume that you have called the group 'login'. Make sure the group doesn't already exist, and make sure that no other programs are moved into this group. For information on how to create a group, consult your vendor's manuals and the man page for /etc/group. 2) Find your login program; it is often /usr/bin/login or /bin/login. I will assume here that it is /bin/login. Under AIX and some other operating systems, login may be a symlink to another program; we are interested in changing the group of the actual program, not of the symlink. 3) Look at the current permissions on login: bash$ ls -l /bin/login lrwxrwxrwx 1 root system 13 Mar 8 1994 /bin/login -> /usr/sbin/tsm bash$ ls -lL /bin/login -r-sr-xr-x 3 root security 59217 Aug 23 1994 /bin/login bash$ Note that because I am running on an AIX system, I gave the -L option to the second ls in order to trace through the symlink and find the real login. You should remember what group login is in so you can change things back after you get a a vendor patch. 4) Change the group of login and set the set GID bit: bash$ su root's Password: bash# chgrp login /bin/login bash# chmod g+s /bin/login bash# ls -lL /bin/login -r-sr-sr-x 3 root login 59217 Aug 23 1994 /bin/login bash# Environment Variables that Matter This is not an exhaustive list of environment variables telnetd should filter, but it does contain several of the key variables on systems used at MIT and by people with whom I have consulted: LD_LIBRARY_PATH: At least Solaris, SunOS, NetBSD, Linux and Digital Unix use this as the path to look for shared libraries in. LD_PRELOAD: Solaris and possibly others load these object modules into the address space of the process before loading other shared libraries. LIBPATH: AIX uses this to locate its shared libraries. ELF_LD_LIBRARY_PATH: May be used by the Linux Elf loader; similar to LD_LIBRARY_PATH in function. LD_AOUT_LIBRARY_PATH: Another Linuxism from ld.so-1.7.3. Same as LD_LIBRARY_PATH but only for a.out libraries. _RLD_ROOT: Digital Unix uses this to specify a prefix prepended to library paths stored inside executables. _RLD_LIST: A list of objects dynamically loaded into an executable by Digital Unix. _RLD_*: Used by Digital Unix and SGI. There are several apparently undocumented variables in /sbin/loader on Digital Unix and in the SGI runtime linker. LD_*: Several other variables have special meaning to certain operating systems. Stripping all these variables would probably be a good idea. IFS: It is possible that setting IFS could cause damage in environments where the user logs into an account that runs a shell script instead of granting full access. Affected Telnetds All telnetds derived from the Telnet package distributed by David Borman allow the environment options to be passed. Mr. Borman has released a patch for the problem as of October 19. The patch released on October 19, while secure, has a bug that prevents any telnet environment options from being handled. Another patch was released on October 23 that appears to work; see below for details. Besides his original release, here are a list of operating systems and security packages I'm aware of that include derivatives of this work: * NetBSD and FreeBSD are distributed with a vulnerable telnetd. (See below for patch info) * The telnet94 with the fixed Kerberos version 4 authentication and encryption distributed by MIT on net-dist.mit.edu and used in MIT's Athena computing environment. (see below for patch location) * The version of telnetd maintained in the Kerberos version 5 distribution by MIT. (patch available) * The Cygnus Network Security V4 95q1 Free Network Release includes a vulnerable telnetd. (Previous releases did not contain telnetd.) A patch has been released. * Openvision's OVSecure may contain a telnetd that is vulnerable. Other Vulnerable Telnetd Implementations This problem is not unique to code derived from the Borman telnet distribution. Other vulnerable implementations are known to include: * SGI Irix 5.3 * Digital Unix. The telnetd distributed with stock Digital Unix appears to be vulnerable. * Linux. The telnetd distributed with Slackware Linux appears to be vulnerable, although I have not verified this. The maintainers of Debian GNU/Linux confirm their telnetd is vulnerable and released a patch; see below. Telnetds that Work Below is a list of operating systems which come with telnetds that we know are not vulnerable. * SunOS 4.1.4. The Sunos 4.1.4 telnetd does not support passing of environment variables, so it is not vulnerable. * IBM AIX 4.1. This telnetd does not support environment options. * BSDI's BSD/OS. While the telnetd will pass any environment option, there doesn't appear to be an option to override the shared library path, so BSD/OS is probably not vulnerable. On October 19, Dave Borman confirmed that BSDI is not vulnerable to the attack, although the telnetd will accept any environment variable. * Telnetd on other systems that do not support shared libraries. This includes DEC Ultrix, and Cray Unicos. Note that both AIX and SunOS can be vulnerable if the stock telnetd is replaced. Also, note that the stock Solaris telnetd has not been tested. Availability of Patches This is a list of patches I'm aware of at this time. As you develop a patch for your product/platform, please let me know; considering free operating systems affected by this problem, widely announcing the bug once patches are available is very important. Nevertheless, it is important that we cooperate in timing the announcement of patches so that all can be announced within a short time range. Hopefully, I will be able to wait until October 31 before announcing the bug, but if it becomes widely known (say, for example, discussed on bugtraq), I will announce the patches I know about at that time. Note that these patches are provided as-is, without any guarantee of correctness or security on the part of MIT, myself, or the patch creator. They are provided in a spirit of cooperation, not as a guaranteed fix. * On October 19, David Borman released a new version of his telnet package, containing a fix to the problem. This original patch disabled passing environment options entirely, but was revised on October 23. The revised patch, and instructions for obtaining it are contained at the bottom of this message. Note that this patch does not deal with the possibly problematic ELF_LD_LIBRARY_PATH. * Greg Hudson checked a patch into the NetBSD-current source tree. This patch will be incorporated by any NetBSD-current users who update to the current telnetd. It will be in the NetBSD 1.1 release. NetBSD developers have not indicated whether they plan on releasing a patch for NetBSD 1.0 users. Note that the sample NetBSD patch distributed with an earlier version of the memo was incomplete; the version in the source tree as of October 18 is correct. * Sam Hartman patched the upcoming release of Kerberos 5. In addition, patches were generated against Kerberos 5 beta 5 and beta 4-3. * Mark Eichin prepared patches for CNS. These patches will be available on the Cygnus web site ; support customers are being contacted directly. * Peter Tobias, released a patch for Debian GNU/Linux. This patch can be found in the networking utilities at ftp://ftp.debian.org/debian/debian-0.93/binary/net/netstd-1.20-1.deb Note that this patch does not currently deal ELF_LD_LIBRARY_PATH. * Andrey A. Chernov released a patch for FreeBSD, but did not include an URL where the patch could be obtained. * Bruce Lewis is preparing a patch for the MIT-distributed Athena telnet/telnet95. His patch is currently available within MIT and should be available soon in the version of telnet on net-dist.mit.edu. Public Exposure This problem is believed not to have wide circulation, and I am not aware of any incidents of illicit penetration. However, it has received public exposure in three places. First, Richard Basch's patch was inadvertently sent to the krb5-bugs mailing list, which is small but public; a publicly readable archive is maintained on an MIT Discuss server. In response to this exposure, the MIT Student Information Processing Board's Linux development group released a new kerberos package, including a fixed telnetd. The announcement of this package indicated the existence of a telnet security hole; SIPB's sources are publicly readable to the MIT community. Greg Hudson's patch to NetBSD was included in an automatic summary of source changes sent to the source-changes@netbsd.org mailing list. The summary said that the patch prevented telnetd from setting dangerous environment variables. Finally, David Borman's announcement of the new version of telnet was posted to several public lists on October 19. The announcement did not say anything about a security hole, nor did it contain a diff. However, a diff is available at the Cray ftp site. Verifying a Patch In the process of talking to vendors, distributing patches, and getting feedback, I've come up with a lot of 'almost solutions' -- patches that are good enough to make you think they work, but that can be compromised. * A clever trick to get around exact match patches is to embed an equals sign in a variable name. For example, ask your client to send an option requesting that the variable LD_LIBRARY_PATH=/home/hartmans/exploits/sun4lib: be set to the value invalid:/lib:/usr/lib. Naturally, the call to setenv in telnetd adds another =, but that's soaked up by 'invalid', and I still get to break into the system. I.E. Deal with variable names containing equals signs (=). * At least in the Borman BSD telnet, there are two calls to setenv: one for the last part of an environment option and one for the other parts. Make sure you cover both; this was the biggest problem with the sample patch I first distributed. * If it is possible to stuff a string into the environment twice with your telnetd, make sure you check all entries in the environment. For example, if you have a setenv() that doesn't check for duplicates, don't just use unsetenv() as this will remove the last item in the environment, leaving the others to be used by login. Sample Patch Below, I include the official patch to telnet from David Borman as of October 23. Before the patch, I include a message I received on October 19; this includes useful information. As I received the message, it was not PGP-signed; its inclusion in this signed summary indicates that it has not been modified since I received it, and says nothing about the integrity of the communications link between myself and Mr. Borman. However, I have examined the patch, and it appears to be a valid fix for the bug. It also corresponds to the appropriate sections of the diff on the ftp server. Again, patches are provided as-is without a guarantee of correctness; you assume all risk for applying this patch. (As with all PGP-signed patches, you will need to remove leading dashes.) Date: Thu, 19 Oct 95 13:54:56 CDT From: dab@berserkly.cray.com (David A. Borman) Message-Id: <9510191854.AA03474@frenzy.cray.com> To: hartmans@MIT.EDU Subject: Re: telnet vulnerability giving root access Cc: cert@cert.org, tytso@MIT.EDU I have placed a version of the BSD Telnet distribution at: ftp://ftp.cray.com/src/telnet/telnet.95.10.23.NE.tar.Z with a fix for this problem. It changes telnetd to remove the LD_*, _RLD_*, IFS and LIBPATH environment variables before execing login. The version on ftp.cray.com does not contain the encryption code, that is on net-dist.mit.edu, and I have sent a new copy off to them to replace the current distribution. (The attached diffs also show a bugfix for a problem that was screwing up /etc/utmp on Solaris.) Also, BSDI is not affected, as they do not provide any way for the user to override the search path for shared libraries. UNICOS is unaffected, since we don't have shared libraries. Please feel free to pass on this message. -David Borman, dab@cray.com diff -cbr telnet.95.05.31/telnetd/sys_term.c telnet.95.10.23/telnetd/sys_term.c *** telnet.95.05.31/telnetd/sys_term.c Wed May 31 00:50:57 1995 - --- telnet.95.10.23/telnetd/sys_term.c Mon Oct 23 09:47:17 1995 *************** *** 32,38 **** */ #ifndef lint ! static char sccsid[] = "@(#)sys_term.c 8.4 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" - --- 32,38 ---- */ #ifndef lint ! static char sccsid[] = "@(#)sys_term.c 8.4+1 (Berkeley) 5/30/95"; #endif /* not lint */ #include "telnetd.h" *************** *** 1570,1579 **** utmpx.ut_id[3] = SC_WILDC; utmpx.ut_type = LOGIN_PROCESS; (void) time(&utmpx.ut_tv.tv_sec); ! if (pututxline(&utmpx) == NULL) ! fatal(net, "pututxline failed"); #endif /* * -h : pass on name of host. * WARNING: -h is accepted by login if and only if - --- 1570,1581 ---- utmpx.ut_id[3] = SC_WILDC; utmpx.ut_type = LOGIN_PROCESS; (void) time(&utmpx.ut_tv.tv_sec); ! if (makeutx(&utmpx) == NULL) ! fatal(net, "makeutx failed"); #endif + scrub_env(); + /* * -h : pass on name of host. * WARNING: -h is accepted by login if and only if *************** *** 1809,1814 **** - --- 1811,1836 ---- return(argv); } #endif /* NEWINIT */ + + /* + * scrub_env() + * + * Remove a few things from the environment that + * don't need to be there. + */ + scrub_env() + { + register char **cpp, **cpp2; + + for (cpp2 = cpp = environ; *cpp; cpp++) { + if (strncmp(*cpp, "LD_", 3) && + strncmp(*cpp, "_RLD_", 5) && + strncmp(*cpp, "LIBPATH=", 8) && + strncmp(*cpp, "IFS=", 4)) + *cpp2++ = *cpp; + } + *cpp2 = 0; + } /* * cleanup() Acknowledgments In preparing this bug summary, I have received the help of several people. In particular, I would like to thank David Borman for quickly fixing the problem once notified, and Bruce Lewis for supplying a timely solution to the problem within MIT. In addition, John Hawkinson provided help developing exploit scripts and confirming that the bug existed on several systems. I would also like to thiank those at MIT who reviewed drafts of this announcement and suggested improvements. - - -- Sam Hartman, MIT Kerberos Development team -----BEGIN PGP SIGNATURE----- Version: 2.6.2 iQEUAwUBMIyQAEJYVPVo3rXRAQE4Lwf46xcucSdiA/uKBOfEIAZM394nIJ6mcYCD gQb7Le+R6Tx9dFYU7rbAvsaoxaeh70ikAXpl0U+wE8kV86u8NuM7RXPkLrwWJWPt Po2EjrPGneLvxBovAReZPUEZQxRbFvOWKU4tXSPsQJpAY3o6p4sRAG4d3hMal9KP miD5RB65ow8dq46n+VA+t1O4BfuiMkdTwToEt3tMV7dCTJCydZkMg0ZUmg6q6MeB BoXxMELmVJXxof2pmpg4bw1yWkoX1oWvdFJu2qpAF/oC/jY5f4VbtDnorEVpjgVz UMqQIcYpESisGuGk0xvJtPdo7ZPUXWgvk//Vo3sNnpMKvl2CTuH+ =CWs7 -----END PGP SIGNATURE-----