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)