Läsa nästa text. 5034514 2000-04-24 23:20 /101 rader/ Postmaster Mottagare: Bugtraq (import) <10602> Ärende: unsafe fgets() in sendmail's mail.local ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: bugtraq@securityfocus.com X-Priority: 3 (Normal) Mime-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <2694.000424@SECURITY.NNOV.RU> Date: Mon, 24 Apr 2000 16:40:32 +0400 Reply-To: 3APA3A <3APA3A@SECURITY.NNOV.RU> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: 3APA3A <3APA3A@SECURITY.NNOV.RU> Organization: http://www.security.nnov.ru X-To: bugtraq@security.nnov.ru, bugtraq@securityfocus.com X-cc: security-officer@freebsd.org To: BUGTRAQ@SECURITYFOCUS.COM Topic: unsafe fgets() in sendmail's mail.local Description: There are 4 problems: 1. Possibility to insert LMTP commands into e-mail message 2. Possibility of deadlock between sendmail and mail.local 3. Possibility to corrupt user's mailbox 4. Possibility to change e-mail headers of the message in user's mailbox Vulnerable software: Problems 1 and 2: sendmail before 8.10.0 (8.9.3 tested), all platforms Problems 3 and 4: sendmail 8.10.0 and 8.10.1 (8.10.1 tested) under Solaris only Status: vendor contacted, problems 1 and 2 are patched in sendmail 8.10.0 Long description: Problem 1: While in LMTP mode mail.local checks input for ".\n" string to find the end of the message. Sendmail will not allow this string to pass through, but using of fgets() with buffersize 2048 allows to emulate end of the message with a string "(2047 chars).\n" The rest of the message will be treated as LMTP commands. This allows to send messages to multiple mailboxes (including private and closed ones) with any spoofed information bypassing sendmail and without any filtering, checking, logging etc. Problem 2: In the conditions of the problem 1, mail.local will return LMTP answers to sendmail. Because sendmail doesn't expects any output from mail.local at this point, replies will not be taken from I/O buffer. If extreamaly large number of LMTP commands is used in the text, or the rest of the message is just a collection of text strings (in this case mail.local will reply with a error for every string) sendmail and mail.local will be deadlocked then the buffer will be filled. This deadlock problem regardless to LMTP command execution was reported to sendmail team by Peter Jeremy and patched in 8.10.0 release. Problem 3: sendmail 8.10.0 introduces support for "Content-Length: " header for Solaris in mail.local. This header stores the size of the message and is used by mail retrieving software (f.e. qpopper) to calculate message boundary in the mailbox. If this header already exists in message it will be stripped, but because fgets() is used for parsing message it's possible to add "Content-Length: 99999999" header and comment out real "Content-Length: " causing mailbox corruption using strings "(2047 chars)\n" "Content-Length: 99999999\n" in the end of message header. Problem 4: If message body is empty and last string of the message header is "(2047 chars)Content-Length: \n" the headers of this message will be glued to the next message in mailbox, because '\n' character will be lost while stripping Content-Length. http://www.security.nnov.ru /\_/\ { . . } |\ +--oQQo->{ ^ }<-----+ \ | 3APA3A U 3APA3A } +-------------o66o--+ / |/ You know my name - look up my number (The Beatles) (5034514) ------------------------------------------ 5038233 2000-04-26 05:27 /149 rader/ Postmaster Mottagare: Bugtraq (import) <10620> Ärende: Re: unsafe fgets() in sendmail's mail.local ------------------------------------------------------------ Approved-By: aleph1@SECURITYFOCUS.COM Delivered-To: bugtraq@lists.securityfocus.com Delivered-To: BUGTRAQ@SECURITYFOCUS.COM Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="vkogqOf2sHV7VnPd" Message-ID: <20000425091054.A30214@zardoc.endmail.org> Date: Tue, 25 Apr 2000 09:10:54 -0700 Reply-To: Claus Assmann <ca+bugtraq@ZARDOC.ENDMAIL.ORG> Sender: Bugtraq List <BUGTRAQ@SECURITYFOCUS.COM> From: Claus Assmann <ca+bugtraq@ZARDOC.ENDMAIL.ORG> X-To: BUGTRAQ@SECURITYFOCUS.COM To: BUGTRAQ@SECURITYFOCUS.COM In-Reply-To: <2694.000424@SECURITY.NNOV.RU>; from 3APA3A@SECURITY.NNOV.RU o Mon, Apr 24, 2000 at 04:40:32PM +0400 --vkogqOf2sHV7VnPd Content-Type: text/plain; charset=us-ascii On Mon, Apr 24, 2000, 3APA3A wrote: > Topic: > unsafe fgets() in sendmail's mail.local > 1. Possibility to insert LMTP commands into e-mail message > 2. Possibility of deadlock between sendmail and mail.local > 3. Possibility to corrupt user's mailbox > 4. Possibility to change e-mail headers of the message in user's > mailbox > Vulnerable software: > Problems 1 and 2: sendmail before 8.10.0 (8.9.3 tested), all > platforms > Problems 3 and 4: sendmail 8.10.0 and 8.10.1 (8.10.1 tested) > under Solaris only Thanks for the notification and your help to create a patch. The attached patch will be in the next release of sendmail. PS: Content-Length: shouldn't be used anyway :-) --vkogqOf2sHV7VnPd Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="p.m.c" Index: mail.local.c =================================================================== RCS file: /cvs/mail.local/mail.local.c,v retrieving revision 8.145 retrieving revision 8.146 diff -u -r8.145 -r8.146 --- mail.local.c 2000/04/25 15:27:08 8.145 +++ mail.local.c 2000/04/25 15:48:32 8.146 @@ -746,7 +746,8 @@ FILE *fp = NULL; time_t tval; bool eline; - bool fullline = TRUE; + bool fullline = TRUE; /* current line is terminated */ + bool prevfl; /* previous line was terminated */ char line[2048]; int fd; char tmpbuf[sizeof _PATH_LOCTMP + 1]; @@ -783,16 +784,19 @@ #endif /* CONTENTLENGTH */ line[0] = '\0'; - for (eline = TRUE; fgets(line, sizeof(line), stdin); ) + eline = TRUE; + while (fgets(line, sizeof(line), stdin) != (char *)NULL) { size_t line_len = 0; int peek; + + prevfl = fullline; /* preserve state of previous line */ while (line[line_len] != '\n' && line_len < sizeof(line) - 2) line_len++; line_len++; /* Check for dot-stuffing */ - if (fullline && lmtprcpts && line[0] == '.') + if (prevfl && lmtprcpts && line[0] == '.') { if (line[1] == '\n' || (line[1] == '\r' && line[2] == '\n')) @@ -801,7 +805,7 @@ line_len--; } - /* Check to see if we have the full line from the fgets() */ + /* Check to see if we have the full line from fgets() */ fullline = FALSE; if (line_len > 0) { @@ -809,12 +813,11 @@ { if (line_len >= 2 && line[line_len - 2] == '\r') - { - (void) strlcpy(line + line_len - 2, - "\n", sizeof line - - line_len + 2); + { + line[line_len - 2] = '\n'; + line[line_len - 1] = '\0'; line_len--; - } + } fullline = TRUE; } else if (line[line_len - 1] == '\r') @@ -834,7 +837,7 @@ fullline = TRUE; #ifdef CONTENTLENGTH - if (line[0] == '\n' && HeaderLength == 0) + if (prevfl && line[0] == '\n' && HeaderLength == 0) { eline = FALSE; HeaderLength = ftell(fp); @@ -849,7 +852,7 @@ } } #else /* CONTENTLENGTH */ - if (line[0] == '\n') + if (prevfl && line[0] == '\n') eline = TRUE; #endif /* CONTENTLENGTH */ else @@ -860,10 +863,17 @@ eline = FALSE; #ifdef CONTENTLENGTH /* discard existing "Content-Length:" headers */ - if (HeaderLength == 0 && + if (prevfl && HeaderLength == 0 && (line[0] == 'C' || line[0] == 'c') && strncasecmp(line, ContentHdr, 15) == 0) - continue; + { + /* + ** be paranoid: clear the line + ** so no "wrong matches" may occur later + */ + line[0] = '\0'; + continue; + } #endif /* CONTENTLENGTH */ } --vkogqOf2sHV7VnPd-- (5038233) ------------------------------------------