[16876] in bugtraq

home help back first fref pref prev next nref lref last post

Correction to sendmail attachment filter

daemon@ATHENA.MIT.EDU (Bennett Samowich)
Fri Sep 22 13:02:08 2000

Mime-Version: 1.0
Content-Type: multipart/mixed; boundary="=====================_7739719==_"
Message-Id:  <4.2.0.58.20000921235818.009ed700@localhost>
Date:         Fri, 22 Sep 2000 00:15:18 -0400
Reply-To: Bennett Samowich <brs@BEN-TECH.COM>
From: Bennett Samowich <brs@BEN-TECH.COM>
To: BUGTRAQ@SECURITYFOCUS.COM

--=====================_7739719==_
Content-Type: text/plain; charset="us-ascii"; format=flowed

Greetings,

I have attached yet another copy of the sendmail filter with the
corrections as recommended by Brett and Jason (thanks).     During my tests
it did block messages that used mixed case MIME tags for filenames.  (e.g.
Name="...", NAME="...", etc)

These filters are not my forte', but I had been toying with them when this
one came about.  Thanks to those who caught the shortcomings.

- Bennett


Here is what was found:

1) An attacker could create a special message that contained mixed case
MIME tags when specifying the attached file names.

Example:
Content-Type: TEXT/PLAIN; charset=US-ASCII; NaMe="filename.dll"

Solution:
added the following code to mlfi_body():

       /* convert to lowercase */
       q = p;
       while (*q) {
          *q = tolower(*q);
          q++;
       }

2) There was a flaw in the logic of bad_extension() that caused valid files
to be incorrectly blocked.

Example:
.xls files were rejected as if they were .vbs file because they had a
common character (the 's').

Solution:
Changed
       if ( x != y )
          n++;
    }

    if (n == len)
       return (0);

To
       if ( x == y )
          n++;
    }

    if (n != len)
       return (0);

--=====================_7739719==_
Content-Type: text/plain; charset="us-ascii"
Content-Disposition: attachment; filename="noattach.c"

/*
 * noattach.c - libmilter filter to reject incoming messages with
 *              specific attachments.
 *
 * Currently rejects VBS, SHS, and DLL attachments.
 *
 * Adapted from filter code written by Al Smith <Al.Smith@aeschi.ch.eu.org>
 *
 * Catches mixed case MIME filename labels.  Identified by:
 *   Brett Glass  <brett@lariat.org> and
 *   Jason Storm  <jms@negation.net>
 */
#include <string.h>
#include "libmilter/mfapi.h"

static int bad_extension(SMFICTX *ctx, const char *s1, const char *s2, int len) {
   int n;
   const char *p, *q;
   char x, y;
   char m[1024];

   sprintf (m, "Sorry, I can't accept messages with .%s attachments.", s2);

   n = 0;
   for (p=s1, q=s2; *p && *q && n < len; p++, q++) {
      x = (isalpha((int)*p)) ? tolower(*p) : *p;
      y = (isalpha((int)*q)) ? tolower(*q) : *q;

      if ( x == y )
         n++;
   }

   if (n != len)
      return (0);

   smfi_setreply(ctx, "554", "5.6.1", m);
   return (1);
}

sfsistat mlfi_body(SMFICTX *ctx, u_char *bodyp, size_t bodylen) {
   u_char *p, *q, *r;

   /* check body block for vbs data */
   for(p = bodyp; p && (p = strstr(p, "Content-Type:")); p++) {
      /* convert to lowercase */
      q = p;
      while (*q) {
         *q = tolower(*q);
         q++;
      }
      if ((q = strstr(p, "name=\""))) {
         for(r=q+6; *r != '\n' && *r != '\0' && *r != '"'; r++);
            if (*r == '"') {
               /* Filter for bad extensions */
               if (bad_extension(ctx, r-3, "vbs", 3))  return SMFIS_REJECT;
               if (bad_extension(ctx, r-3, "shs", 3))  return SMFIS_REJECT;
               if (bad_extension(ctx, r-3, "dll", 3))  return SMFIS_REJECT;
            }
      }
   }

   /* continue processing */
   return SMFIS_CONTINUE;
}

struct smfiDesc smfilter = {
   "VBFilter", 		/* filter name */
   SMFI_VERSION, 	/* version code -- do not change */
   0,  			/* flags */
   NULL,  		/* connection info filter */
   NULL,  		/* SMTP HELO command filter */
   NULL,  		/* envelope sender filter */
   NULL,  		/* envelope recipient filter */
   NULL,  		/* header filter */
   NULL,  		/* end of header */
   mlfi_body, 		/* body block filter */
   NULL,  		/* end of message */
   NULL,  		/* message aborted */
   NULL  		/* connection cleanup */
};


int main(int argc, char *argv[]) {
   char c;
   const char *args = "p:";

   /* Process command line options */
   while ((c = getopt(argc, argv, args)) != -1) {
      switch (c) {
         case 'p':
            if (optarg == NULL || *optarg == '\0') {
               (void) fprintf(stderr, "Illegal conn: %s\n", optarg);
               exit(EX_USAGE);
            }
            (void) smfi_setconn(optarg);
            break;

      }
   }

   if (smfi_register(smfilter) == MI_FAILURE) {
      fprintf(stderr, "smfi_register failed\n");
      exit(EX_UNAVAILABLE);
   }
   return smfi_main();
}

--=====================_7739719==_--

home help back first fref pref prev next nref lref last post