Linux tftpd vulnerability

Summary
Description:Linux tftpd doesn't check corectly for requests beginning with ../
Author:Alex Belits (abelits@phobos.illtel.denver.co.us)
Compromise:Access directories beyond permissions REMOTELY
Vulnerable Systems:Idiots on Linux running tftpd
Date:23 March 1997
Details

Exploit:

From abelits@phobos.illtel.denver.co.us Fri Mar 28 23:25:17 1997
Date: Sun, 23 Mar 1997 09:11:34 -0800 (PST)
From: Alex Belits 
To: linux-security@redhat.com
Cc: linux-alert@redhat.com
Subject: [linux-alert] Re: [linux-security] tftpd bug (was: "Secure" tftpd source for Linux?)
Resent-Date: 23 Mar 1997 18:57:43 -0000
Resent-From: linux-alert@redhat.com
Resent-cc: "recipient.list.not.shown":;



[Mod: David Holland's message added to the back, linux-alert added to the
list of addresses -- alex]

On Sat, 22 Mar 1997, Ben Cantrick wrote:

>   It's a cute little hack, and it seems to work. But I am convinced that
> someone must have seen the need and done this before. My extended forays
> into the web via several search engines have failed to turn up anything
> relevant. So I'm curious if anyone on the list knows of (or better, has)
> freely distributable source for a "secure" tftpd.

  tftpd in FreeBSD distribution uses chroot() and sets its uid to nobody.
I don't think, it does anything reasonable with groups.

But... I've 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.

--
Alex

P.S. how such umm... not obviously secure code got into tftpd in the first
place after that many revisions that definitely were done to increase
security? After all, changes between NetKit revisions _do_ make sense.

Return-Path: dholland@hcs.harvard.edu

 > [tftpd source mapped to /dev/null]
 >
 > Finally, it prevents ".." and "." in filename to be used to go up:

He's right; it doesn't block leading ".." in the case where the
filename doesn't begin with "/". 

Someone already caught this and the fix is going to be in the next
release; in the meantime here's a patch.

 > > P.S. how such umm... not obviously secure code got into tftpd in the first
 > > place after that many revisions that definitely were done to increase
 > > security? After all, changes between NetKit revisions _do_ make sense.

It needs an intensive rewrite. Don't hold your breath... :(


*** tftpd.c	1996/12/29 18:42:40	1.8
--- tftpd.c	1997/03/08 11:31:00
***************
*** 40,44 ****
   */
  char rcsid[] = 
!   "$Id: linux.tftpd.dotdotbug.html 30060 2022-03-05 20:19:24Z dmiller $";
  
  /*
--- 40,44 ----
   */
  char rcsid[] = 
!   "$Id: linux.tftpd.dotdotbug.html 30060 2022-03-05 20:19:24Z dmiller $";
  
  /*
***************
*** 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)


-- 
   - David A. Holland          | Number of words in the English language that
     dholland@eecs.harvard.edu | exist because of typos or misreadings: 381


More Exploits!

The master index of all exploits is available here (Very large file)
Or you can pick your favorite operating system:
All OS's Linux Solaris/SunOS Micro$oft
*BSD Macintosh AIX IRIX
ULTRIX/Digital UNIX HP/UX SCO Remote exploits

This page is part of Fyodor's exploit world. For a free program to automate scanning your network for vulnerable hosts and services, check out my network mapping tool, nmap. Or try these Insecure.Org resources: