COMMAND

    tftp

SYSTEMS AFFECTED

    Linux & FreeBSD

PROBLEM

    Text used to describe this  vulnerability is mix of messages  from
    linux-alert mailing list (Ben Cantrick, David Holland's, Alex).

    David  have  looked  at  both  Linux  (NetKit  0.09)  and  FreeBSD
    (2.2-ALPHA) tftpd and found  rather strange code in  Linux tftpd's
    validate_access() function:

    ---8<---
	syslog(LOG_ERR, "tftpd: trying to get file: %s\n", filename);

	if (*filename != '/') {
		syslog(LOG_ERR, "tftpd: serving file from %s\n", dirs[0]);
		chdir(dirs[0]);
	} else {
		for (dirp = dirs; *dirp; dirp++)
			if (strncmp(filename, *dirp, strlen(*dirp)) == 0)
				break;
		if (*dirp==0 && dirp!=dirs)
			return (EACCESS);
	}
	/*
	 * prevent tricksters from getting around the directory restrictions
	 */
	for (cp = filename + 1; *cp; cp++)
		if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0)
			return(EACCESS);
    --->8---

    ...it checks _only_ for "/../" and start _always_ from the  second
    character in the filename (in  other words, if filename is  empty,
    it will "analyze"  the memory after  it where other  piece of code
    places mode, so  at least it  won't do anything  destructive). But
    it  also  assumes  all  not  starting  from  '/'  filenames  to be
    relative to some directory, and  never checks them for "../"  that
    FreeBSD one  does. So  (see code  above for  locations of calls to
    syslog()):

    ---8<---
    Mar 23 06:55:08 phobos in.tftpd[9799]: connect from phobos.illtel.denver.co.us
    Mar 23 06:55:08 phobos tftpd[9800]: tftpd: trying to get file: ../etc/passwd
    Mar 23 06:55:08 phobos tftpd[9800]: tftpd: serving file from /tftpboot
    --->8---

    ...and obviously it was /tftpboot/../etc/passwd aka /etc/passwd

    Not that it  does any damage  by itself, but  it definitely wasn't
    supposed to do that. FreeBSD tftpd disallows such things.

    According to copyright notices,  both tftpd are derived  from some
    old  (1983)  Berkeley  code,  and  Linux  one  has  some   general
    clumsiness  all  over  its  code  (and default /tftpboot directory
    didn't  exist  until  0.09,  0.08  seems  to  require  the list of
    directories, or it will just SIGSEGV on NULL pointer).

    FreeBSD tftpd compiles with command line:

	gcc -O -DLOG_FTP=LOG_DAEMON -o tftpd  tftpd.c tftpsubs.c

    and  works  fine  if  -ls  /tftpboot  is  added  as options to its
    command line.  Otherwise  it only checks file  permissions without
    even  trying  to   become  "nobody"  and   thus  opens  hole   for
    non-executable directories  (even if  directory is  non-executable
    for anyone but  root, files in  it will be  accessible). Also it's
    necessary  to  hardlink  /dev/log  under  chroot directory to keep
    logging functional.

SOLUTION

    David A. Holland gave possible soulution.

    *** tftpd.c     1996/12/29 18:42:40     1.8
    --- tftpd.c     1997/03/08 11:31:00
    ***************
    *** 40,44 ****
	*/
       char rcsid[] =
    !   "$Id: tftpd.c,v 1.8 1996/12/29 18:42:40 dholland Exp $";

       /*
    --- 40,44 ----
	*/
       char rcsid[] =
    !   "$Id: tftpd.c,v 1.9 1997/03/08 11:30:30 dholland Exp $";

       /*
    ***************
    *** 298,301 ****
    --- 298,303 ----
	      * prevent tricksters from getting around the directory restrictions
	      */
    +       if (!strncmp(filename, "../", 3))
    +               return EACCESS;
	     for (cp = filename + 1; *cp; cp++)
		     if(*cp == '.' && strncmp(cp-1, "/../", 4) == 0)