|
COMMAND setlocale() SYSTEMS AFFECTED FreeBSD 2.1.x, 2.2 (prior to December 1996) PROBLEM Thomas H. Ptacek reported that anyone who installed FreeBSD 2.2 prior to December of 1996 is vulnerable to locale routine problems similar to the one that afflicts crt0 start() in FreeBSD 2.1.x (take a look at crt0 bug on this page). Specifically, You are able to cause a shell to be executed from any program that calls setlocale() in FreeBSD 2.2. Thomas tested this out with dmesg, which promptly gave him an SGID "kmem" shell. Note that programs that shed privilege using saved-set UIDs are vulnerable to this problem as well, as the machine code used to take over the affected programs can easily restore privilege. The setlocale() call contains a number of potential exploits through string overflows during environment variable expansion. Because the 2.1.6 and earlier versions of FreeBSD called setlocale() in the C runtime code, the problem is especially acute there in that it essentially effects all binaries on the system. In FreeBSD 2.2 BETA and later releases, the setlocale() call was removed from crt0.c and the exploit closed through additional checks. The setlocale() library function looks for the environment variable "PATH_LOCALE" in the current process's environment, and if it exists, later copies the contents of this variable to a stack buffer without doing proper bounds checking. If the environment variable was specially initialized with the proper amount and type of data prior to running a setuid program, it is possible to cause the program to overflow its stack and execute arbitrary code which could allow the user to become root. Any binary linked on a system with setlocale() built into crt0.c or which calls setlocale() directly has the buffer overrun vulnerability. If this binary has the setuid or setgid bits set, or is called by another setuid/setgid binary (even if that other setuid/setgid binary does not have this vulnerability), unauthorized access may be allowed. Update (18 september 2002) ====== Beleive it or not, but this issue existed until now in NetBSD too. From NetBSD security advisory [2002-012: buffer overrun in setlocale] : The setlocale (or its subcontractor, __setlocale) function, defined in lib/libc/locale/setlocale.c, is used to change the locale of each locale category. setlocale() function switches the locale of the category specified by the first argument to the second argument. The special category LC_ALL can be used to change all locale categories at the same time. In this case, the NetBSD implementation of setlocale allows a special form of the second argument string to specify individual locales per category. In this form, each locale is given in a single string separated by slashes ('/'), as "A/B/C/D/E/F". Here, each element corresponds to categories LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME and LC_MESSAGES, respectively. The setlocale() function attempts to decomposit these elements into an array object named new_categories locally defined in lib/libc/locale/setlocale.c. However, the code to check the array boundary was lacking and thus this decomposition code could destroy data segment if a string having over six elements was given. If the program which has set[ug]id bit or which is called from set[ug]id program calls setlocale() with LC_ALL as the first argument and with the string derived from user-given data (e.g. setlocale(LC_ALL, getenv("FOO")) ) as the second argument, then such program could be exploitable. DefaultLanguageProc function of X Toolkit Intrinsics (Xt) is a example of such usage. DefaultLanguageProc calls setlocale as "setlocale(LC_ALL, xnl)". Here, xnl variable is null string ("") by default, but can be overriden by user via - -xnllanguage option. Most Xt programs, including xterm, use this language procedure. xterm is a setuid root program and thus any local user could illegally acquire root account by using this problem. On the other hand, the frequently used special form, setlocale(LC_ALL, ""), does not have this problem because the decomposition code is never executed in this form, although user-given LC_ALL environment variable is similarly referred. SOLUTION The locale routines were patched at the end of 1996 to cause PATH_LOCALE (the environment variable who's contents are trampling all over the stack frames of locale routines) to be ignored if the euid doesn't match the uid; the patch also avoids the stack overrun by allocating space for the variable on the heap with strdup(). People running FreeBSD revisions that don't have this patch will want to make sure they've applied these patches as soon as possible. Vulnerability can easily be assessed by setting LC_CTYPE, filling PATH_LOCALE with 2000 random characters, and attempting to run /sbin/dmesg (which will segfault if the problem exists). FreeBSD recommends recompiling libc with the following patches and then recompiling all staticly linked binaries (all in /sbin and /bin as well as chflags, gunzip, gzcat, gzip, ld, tar and zcat in /usr/bin) eliminates this vulnerability in FreeBSD 2.1.6 and earlier releases: However, a full solution may require a re-link of all setuid/setgid local binaries or all local binaries likely to be called from another setuid/setgid program that were originally linked statically under one of the affected OSs. Dynamically linked executables will benefit directly from this patch once libc is rebuilt and reinstalled and do not need to be relinked. Because of the severity of this security hole, a full update release for FreeBSD 2.1.6 will also be released very shortly, that release being provisionally assigned the version number of 2.1.7. Patch for this can be found at following address: ftp://freebsd.org/pub/CERT/patches/SA-97:01/ NetBSD ====== Updates available, check : http://www.NetBSD.ORG/Security/