..:-={{Collaborative Security Information Center}}=-:.. X-TREME & TECHNOTRONIC Security Collaboration Project http://www.technotronic.com -=©=- http://www.x-treme.abyss.com L0pht Security Advisory Application: Sendmail 8.7.5 Platforms: All Severity: any local user can gain root priveledges. Author: mudge@l0pht.com Scenario: Due to a problem with the code in sendmail a buffer overflow condition exists that allows a user to overwrite the information in a saved stack frame. When the function returns, the saved frame is popped off of the stack and user code can be executed. An exploit script will be made public upon the actual release of Sendmail 8.8 which fixes this particular exploitable code segment. Example: > id uid=621(mudge) gid=200(users) > ./sploit.sh 3883 chfn: rebuilding the database... chfn: done using arg of [0x-------- (hex) + 3883(dec)] # id uid=621(mudge) euid=0(root) gid=200(users) # ./up # id uid=0(root) gid=200(users) If a user is able to alter his/her gecos field then that user can exploit a coding flaw in sendmail to elevate their effective UID to 0. Various operating systems ship with chfn(1) which enables users to change their gecos field. Some of the operating systems that ship with this program are NetBSD, FreeBSD, BSDI, OpenBSD, and Linux. It has not been extensively researched as to what others come out of the box with this functionality. Even if your operating system does not ship with this functionality, it has been witnessed that many service providers offering shell accounts add these, or equivalent utils, in order to minimize their administrative tasks and to facilitate user functionality. No matter, the flaw is a coding problem in sendmail and not the fact that these other programs exist. The actual problem in the code is quite apparent. Inside recipient.c we find the following: char nbuf[MAXNAME + 1]; ... buildfname(pw->pw_gecos, pw->pw_name, nbuf); The problem is that nbuf[MAXNAME + 1] is a fixed length buffer and as we will soon see, buildfname() does not honor this. from util.c: void buildfname(gecos, login, buf) register char *gecos; char *login; char *buf; { register char *p; register char *bp = buf; int l; ... /* now fill in buf */ for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) { if (*p == '&') { (void) strcpy(bp, login); *bp = toupper(*bp); while (*bp != '\0') bp++; } else *bp++ = *p; } *bp = '\0'; } Here we see that buildfname() happily copies whatever size we can hand it into nbuf[MAXNAME +1]. The function is even nice enough to append a null to the string in case we wanted to put our machine opcodes and operands inside the gecos field. Though this is one way of doing it, we opted for another method that enabled us more freedom with the various methods of altering ones gecos field. Solution: This particular problem has been fixed in Sendmail 8.8 beta. A temporary fix is to remove the ability for users on a local system to change their gecos (commonly referred to as 'real-name') field. mudge@l0pht.com From owner-linux-security@tarsier.cv.nrao.edu Thu Sep 12 20:07:51 1996 Return-Path: Delivered-To: route@infonexus.com Received: (qmail-queue invoked from smtpd); 12 Sep 1996 20:07:49 -0000 Received: from mail6.netcom.com (root@192.100.81.142) by onyx.infonexus.com with SMTP; 12 Sep 1996 20:07:48 -0000 Received: from marmoset.cv.nrao.edu (root@marmoset.cv.nrao.edu [192.33.115.176]) by mail6.netcom.com (8.6.13/Netcom) id NAA28057; Thu, 12 Sep 1996 13:03:07 -0700 Received: from tarsier.cv.nrao.edu (majdom@tarsier.cv.nrao.edu [192.33.115.50]) by marmoset.cv.nrao.edu (8.6.12/$Revision: 3.22 $) with ESMTP id PAA15654; Thu, 12 Sep 1996 15:27:05 -0400 Received: (from majdom@localhost) by tarsier.cv.nrao.edu (8.6.13/$Revision: 2.10 $) id PAA18906; Thu, 12 Sep 1996 15:27:02 -0400 To: linux-security@tarsier.cv.nrao.edu Path: news.dhp.com!not-for-mail From: panzer@dhp.com (Matt) Newsgroups: mail.linux.security Subject: Re: [linux-security] Re: sendmail-8.7.5 Date: 12 Sep 1996 13:08:03 -0400 Organization: DataHaven Project +1 412 421 4516 (DHP.COM) Lines: 80 Message-ID: <519g1j$2i4@dhp.com> References: <199609121556.RAA14593@riemann.iam.uni-bonn.de> X-Newsreader: TIN [version 1.2 PL2+color] Sender: owner-linux-security@tarsier.cv.nrao.edu Precedence: list Status: RO Patches for Sendmail-8.7.5 to incorporate the buildfname buflen check from sendmail-8.8-beta2. Tossed together when I should have been at work on 12 Sep 1996. -Matt (panzer@dhp.com) http://www.dhp.com/ -------------------------------SNIP----------------------------------- diff -u --recursive ../../sendmail-8.7.5/src/envelope.c ./envelope.c --- ../../sendmail-8.7.5/src/envelope.c Sat Nov 11 14:07:50 1995 +++ ./envelope.c Thu Sep 12 12:12:05 1996 @@ -777,7 +777,7 @@ strcmp(pw->pw_name, e->e_from.q_user) == 0 && !internal) { - buildfname(pw->pw_gecos, e->e_from.q_user, buf); + buildfname(pw->pw_gecos, e->e_from.q_user, buf, sizeof buf); if (buf[0] != '\0') FullName = newstr(buf); } diff -u --recursive ../../sendmail-8.7.5/src/recipient.c ./recipient.c --- ../../sendmail-8.7.5/src/recipient.c Mon Oct 30 15:44:17 1995 +++ ./recipient.c Thu Sep 12 12:11:11 1996 @@ -535,7 +535,7 @@ a->q_gid = pw->pw_gid; a->q_ruser = newstr(pw->pw_name); a->q_flags |= QGOODUID; - buildfname(pw->pw_gecos, pw->pw_name, nbuf); + buildfname(pw->pw_gecos, pw->pw_name, nbuf, sizeof nbuf); if (nbuf[0] != '\0') a->q_fullname = newstr(nbuf); if (!usershellok(pw->pw_name, pw->pw_shell)) @@ -743,7 +743,7 @@ } # endif - buildfname(pw->pw_gecos, pw->pw_name, buf); + buildfname(pw->pw_gecos, pw->pw_name, buf, sizeof buf); if (strchr(buf, ' ') != NULL && !strcasecmp(buf, name)) { if (tTd(29, 4)) diff -u --recursive ../../sendmail-8.7.5/src/util.c ./util.c --- ../../sendmail-8.7.5/src/util.c Mon Mar 4 12:13:21 1996 +++ ./util.c Thu Sep 12 12:23:12 1996 @@ -383,10 +383,11 @@ */ void -buildfname(gecos, login, buf) +buildfname(gecos, login, buf,buflen) register char *gecos; char *login; char *buf; + int buflen; { register char *p; register char *bp = buf; @@ -404,7 +405,22 @@ else l++; } - + if (l > buflen - 1) + { + /* not a good sign */ + if (strlen(gecos) > (SIZE_T) buflen - 1) + { + /* even worse */ + strncpy(buf, gecos, buflen - 1); + buf[buflen - 1] = '\0'; + } + else + { + strcpy(buf, gecos); + } + return; + } + /* now fill in buf */ for (p = gecos; *p != '\0' && *p != ',' && *p != ';' && *p != '%'; p++) { -- -Matt (panzer@dhp.com) -- DataHaven Project - http://www.dhp.com/ "That which can never be enforced should not be prohibited."