Sendmail 8.8.x/8.9.x bugware

From: Gregory Neil Shapiro (sendmail+gshapiroat_private)
Date: Wed Jan 20 1999 - 21:56:57 PST

  • Next message: Wolfgang Gassner: "Nobo and Netbuster Dos"

    -----BEGIN PGP SIGNED MESSAGE-----
    
    Michal> 1. Redirection attack
    
    Michal> Due to strange address parsing policy [briefly: if address ends
    Michal> with local hostname, trim it and parse as any other (even if after
    Michal> this operation address isn't 'local' anymore], specific message
    Michal> routing (eg. through internal, protected or external networks) can
    Michal> be forced, giving an occasion to perform anonymous scanning (or
    Michal> fakemailing). You could call it 'feature' instead of 'bug', but it
    Michal> seems to be Sendmail-specific ;>
    
    Working with Michal, I believe we have concluded that this is not bug in
    8.9.2 but rather a policy decision made by some sites running 8.9.2.
    Specifically, sendmail includes a method for tuning the anti-relaying
    rulesets via an access database or other features.  Sites can also
    completely turn off the anti-relaying checks and leave themselves wide open
    to attacks.
    
    Sendmail users should be sure to update their sendmail.cf when upgrading
    their sendmail binary.  The sendmail 8.9.2 binary alone will not stop
    relaying.  The rulesets provide the hooks for stopping relaying.
    Instructions on building a new sendmail.cf are available in cf/README in
    the sendmail distribution.
    
    Michal> 2. 'Headers prescan' DoS
    
    Michal> There are possible DoS attacks due to ineffective headers prescan
    Michal> algorithm. Two or three medium-size (200 kb) mail messages may
    Michal> render system unusable for quite long period of time (as headers
    Michal> are parsed at least twice, on message collection and in
    Michal> queue). Exploit sold separately :-)
    
    While studying the denial of service attack found by Michal Zalewski, we
    found another related area which Michal's patch did not catch.  The patch
    below extends Michal's patch by limiting both the number of header lines
    as well as the size of each individual header line.  The patch will enforce
    reasonable limits on these lengths and adds a new configuration item.  The
    new option syntax is similar to that of the MaxMimeHeaderLength option:
    
    O MaxHeaderLines=####/####
    
    where the first number is the number of lines that sendmail will accept and
    the second number is the length of each line.  The default is 1000/990.
    This option can be set in a .mc file (after applying the patch) with:
    
    define(confMAX_HEADER_LINES, `1000/990')
    
    Also note that the count is per line where before concatenating
    continuation lines.  For example, the following will be counted as 2 lines
    (even though it is a single header):
    
    To: gshapiro,
            eric
    
    The patch is for sendmail 8.9.2.  To apply the patch, expand the sendmail
    distribution (available from ftp://ftp.sendmail.org/pub/sendmail/) and
    follow these steps:
    
    cd sendmail-8.9.2
    patch -p0 < patchfile
    
    Note that the patch program which ships with Solaris has had problems with
    patches in the past.  Please use GNU patch (ftp://ftp.gnu.org/pub/gnu/) if
    you are on a Solaris system.
    
    To enable the new MaxHeaderLines option, you will need to recompile with
    '-D_FFR_MAX_HEADER_LINES'.  To accomplish this, add the following line to
    sendmail-8.9.2/BuildTools/Site/site.config.m4:
    
    APPENDDEF(`confENVDEF', `-D_FFR_MAX_HEADER_LINES=1')
    
    Then recompile with './Build -c' in the src directory:
    
    cd sendmail-8.9.2/src
    ./Build -c
    
    Finally, install the new binary and restart your sendmail daemon.
    
    sendmail 8.9.3, currently under test, will include this patch.
    
    Questions can be mailed to sendmail-questionsat_private  Bugs should be
    mailed to sendmail-bugsat_private
    
    Since this message has been PGP signed, some of the lines below will be
    encapsulated by prepending "- " to lines starting with "-" as specified by
    RFC 934.  Modern versions of patch will properly deal with this
    encapsulation.  If you are using a patch that does not handle this, you may
    need to hand edit the patch after saving it.
    
    *** -   Wed Dec 31 16:00:00 1969
    - --- src/conf.h        Mon Jan 18 15:16:14 1999
    ***************
    *** 65,70 ****
    - --- 65,76 ----
      # else
      #  define MAXMACNAMELEN       20              /* max macro name length */
      # endif
    + # ifndef MAXHDRLINES
    + #  define MAXHDRLINES 1000            /* max lines in a message header */
    + # endif
    + # ifndef MAXHDRLINELEN
    + #  define MAXHDRLINELEN       SMTPLINELIM     /* max length of a header line */
    + # endif
    
      /**********************************************************************
      **  Compilation options.
    
    *** -   Wed Dec 31 16:00:00 1969
    - --- src/collect.c     Tue Jan 19 20:27:20 1999
    ***************
    *** 53,58 ****
    - --- 53,59 ----
      #define MS_UFROM      0       /* reading Unix from line */
      #define MS_HEADER     1       /* reading message header */
      #define MS_BODY               2       /* reading message body */
    + #define MS_DISCARD    3       /* discarding rest of message */
    
      void
      collect(fp, smtpmode, hdrp, e)
    ***************
    *** 73,78 ****
    - --- 74,81 ----
            volatile int istate;
            volatile int mstate;
            u_char *volatile pbp;
    +       int nhdrlines = 0;
    +       int hdrlinelen = 0;
            u_char peekbuf[8];
            char dfname[MAXQFNAME];
            char bufbuf[MAXLINE];
    ***************
    *** 194,199 ****
    - --- 197,203 ----
                            switch (istate)
                            {
                              case IS_BOL:
    +                               hdrlinelen = 0;
                                    if (c == '.')
                                    {
                                            istate = IS_DOT;
    ***************
    *** 258,269 ****
      bufferchar:
                            if (!headeronly)
                                    e->e_msgsize++;
    !                       if (mstate == MS_BODY)
                            {
                                    /* just put the character out */
                                    if (MaxMessageSize <= 0 ||
                                        e->e_msgsize <= MaxMessageSize)
                                            putc(c, tf);
                                    continue;
                            }
    
    - --- 262,278 ----
      bufferchar:
                            if (!headeronly)
                                    e->e_msgsize++;
    !                       switch (mstate)
                            {
    +                         case MS_BODY:
                                    /* just put the character out */
                                    if (MaxMessageSize <= 0 ||
                                        e->e_msgsize <= MaxMessageSize)
                                            putc(c, tf);
    +
    +                               /* fall through */
    +
    +                         case MS_DISCARD:
                                    continue;
                            }
    
    ***************
    *** 294,300 ****
    - --- 303,325 ----
      #endif
                            }
                            else if (c != '\0')
    +                       {
                                    *bp++ = c;
    +                               if (MaxHeaderLineLength > 0 &&
    +                                   ++hdrlinelen > MaxHeaderLineLength)
    +                               {
    +                                       sm_syslog(LOG_NOTICE, e->e_id,
    +                                                 "header line too long (%d max) from %s during message collect",
    +                                                 MaxHeaderLineLength,
    +                                                 CurHostName != NULL ? CurHostName : "localhost");
    +                                       errno = 0;
    +                                       e->e_flags |= EF_CLRQUEUE;
    +                                       e->e_status = "5.6.0";
    +                                       usrerr("552 Header line too long (%d max)",
    +                                               MaxHeaderLineLength);
    +                                       mstate = MS_DISCARD;
    +                               }
    +                       }
                            if (istate == IS_BOL)
                                    break;
                    }
    ***************
    *** 327,332 ****
    - --- 352,373 ----
                                    goto nextstate;
                            }
    
    +                       if (MaxHeaderLines > 0 &&
    +                           ++nhdrlines > MaxHeaderLines)
    +                       {
    +                               sm_syslog(LOG_NOTICE, e->e_id,
    +                                         "too many header lines (%d max) from %s during message collect",
    +                                         MaxHeaderLines,
    +                                         CurHostName != NULL ? CurHostName : "localhost");
    +                               errno = 0;
    +                               e->e_flags |= EF_CLRQUEUE;
    +                               e->e_status = "5.6.0";
    +                               usrerr("552 Too many header lines (%d max)",
    +                                       MaxHeaderLines);
    +                               mstate = MS_DISCARD;
    +                               break;
    +                       }
    +
                            /* check for possible continuation line */
                            do
                            {
    ***************
    *** 346,351 ****
    - --- 387,393 ----
                            if (*--bp != '\n' || *--bp != '\r')
                                    bp++;
                            *bp = '\0';
    +
                            if (bitset(H_EOH, chompheader(buf, FALSE, hdrp, e)))
                            {
                                    mstate = MS_BODY;
    
    *** -   Wed Dec 31 16:00:00 1969
    - --- src/sendmail.h    Mon Jan 18 16:41:12 1999
    ***************
    *** 1254,1259 ****
    - --- 1254,1261 ----
      EXTERN int    MaxRcptPerMsg;  /* max recipients per SMTP message */
      EXTERN bool   DoQueueRun;     /* non-interrupt time queue run needed */
      EXTERN u_long ConnectOnlyTo;  /* override connection address (for testing) */
    + EXTERN int    MaxHeaderLines; /* max lines of headers per message */
    + EXTERN int    MaxHeaderLineLength;    /* max length of a header line */
      #if _FFR_DSN_RRT_OPTION
      EXTERN bool   RrtImpliesDsn;  /* turn Return-Receipt-To: into DSN */
      #endif
    
    *** -   Wed Dec 31 16:00:00 1969
    - --- src/readcf.c      Mon Jan 18 19:15:10 1999
    ***************
    *** 1523,1528 ****
    - --- 1523,1532 ----
      #define O_CONTROLSOCKET       0xa9
            { "ControlSocketName",          O_CONTROLSOCKET,        FALSE   },
      #endif
    + #if _FFR_MAX_HEADER_LINES
    + #define O_MAXHDRLINES 0xaa
    +       { "MaxHeaderLines",             O_MAXHDRLINES,  FALSE   },
    + #endif
            { NULL,                         '\0',           FALSE   }
      };
    
    ***************
    *** 2459,2464 ****
    - --- 2463,2487 ----
                    if (ControlSocketName != NULL)
                            free(ControlSocketName);
                    ControlSocketName = newstr(val);
    +               break;
    + #endif
    +
    + #if _FFR_MAX_HEADER_LINES
    +         case O_MAXHDRLINES:
    +               p = strchr(val, '/');
    +               if (p != NULL)
    +                       *p++ = '\0';
    +               MaxHeaderLines = atoi(val);
    +               if (p != NULL && *p != '\0')
    +                       MaxHeaderLineLength = atoi(p);
    +
    +               if (MaxHeaderLines > 0 &&
    +                   MaxHeaderLines < 50)
    +                       printf("Warning: MaxHeaderLines: header line limit set lower than 50\n");
    +
    +               if (MaxHeaderLineLength > 0 &&
    +                   MaxHeaderLineLength < MAXHDRLINELEN)
    +                       printf("Warning: MaxHeaderLines: header line length limit set lower than %d\n", MAXHDRLINELEN);
                    break;
      #endif
    
    
    *** -   Wed Dec 31 16:00:00 1969
    - --- src/conf.c        Mon Jan 18 15:27:30 1999
    ***************
    *** 280,285 ****
    - --- 280,287 ----
            ColonOkInAddr = TRUE;
            DontLockReadFiles = TRUE;
            DoubleBounceAddr = "postmaster";
    +       MaxHeaderLines = MAXHDRLINES;
    +       MaxHeaderLineLength = MAXHDRLINELEN;
            snprintf(buf, sizeof buf, "%s%sdead.letter",
                    _PATH_VARTMP,
                    _PATH_VARTMP[sizeof _PATH_VARTMP - 2] == '/' ? "" : "/");
    
    *** -   Wed Dec 31 16:00:00 1969
    - --- cf/m4/proto.m4    Mon Jan 18 19:28:07 1999
    ***************
    *** 474,479 ****
    - --- 474,483 ----
      `# Maximum MIME header length to protect MUAs
      O MaxMimeHeaderLength=confMAX_MIME_HEADER_LENGTH
      ')
    + ifdef(`confMAX_HEADER_LINES',
    + `# Maximum number of header lines and header line length limit
    + O MaxHeaderLines=confMAX_HEADER_LINES
    + ')
    
      ###########################
      #   Message precedences   #
    
    
    -----BEGIN PGP SIGNATURE-----
    Version: 2.6.3a
    Charset: noconv
    
    iQCVAwUBNqa7aXxLZ22gDhVjAQHSMwP+KFbI5hxzkeTdV2gptoqHiAf49AT2KqO+
    Mu9cIa/OMuYQSnxoBBJZoZqV6e7BR92x9NJOpeVqemzV7iVZNwYrjgzt/5+K5I6V
    9J+g43uXk7Es7r6Y50YktLa+yXXD9qGEQf/VgevYTwT+vqo/VYu1cAPFO5kwy7Er
    MS4FMoX6SuY=
    =Yj/b
    -----END PGP SIGNATURE-----
    



    This archive was generated by hypermail 2b30 : Fri Apr 13 2001 - 14:29:33 PDT