/* * ARPTool v0.1, (c) Cristiano Lincoln Mattos, 1999 - * * - Compiled and tested on Linux 2.0.33, 2.0.35, 2.0.36, libc5 & glibc. * Will port to Solaris 2.5.1 as soon as i have time. * - For usage, run it without arguments. * - If you dont know what this is for, or what you can do with it, * read yuri volobuev's excellent bugtraq post about ARP spoofing * (available from the bugtraq archives). * - The netmap results depend on the network latency.. try adjusting the * usleep() delay, if you think it's too small/big. * - The latest version will be always at * http://www.hotlink.com.br/users/lincoln/arptool * - Some code borrowed from neped (apostols.org), thanks. * * #include * * CHANGELOG: * 09/12/98 - General code cleanup. * 07/12/98 - Removed the option for hiding in the process list, and * double mode: didn't work as expected, stupid oversight. * 29/12/98 - Better display of MAC's with more than one IP (proxy * arp or virtual interfaces). * 28/12/98 - Added check for arp reply being to source ip (netmap). */ #include #include #include #include #include #include #include #include #define ARP_ETHER 1 #define ARP_REQUEST 1 #define ARP_REPLY 2 /* Structures */ struct pkt_struct { unsigned char eth_dst[6]; unsigned char eth_src[6]; unsigned short eth_proto; unsigned short int arp_hw_type; unsigned short int arp_proto; unsigned char arp_hw_len; unsigned char arp_proto_len; // proto is IP. unsigned short arp_oper; unsigned char arp_hw_src[6]; unsigned char arp_ip_src[4]; unsigned char arp_hw_dst[6]; unsigned char arp_ip_dst[4]; }; struct spoof_struct { unsigned char hw_src[6]; unsigned char hw_dst[6]; unsigned long int ip_src; unsigned long int ip_dst; unsigned short op; }; /* List structures */ struct iplist_struct { unsigned long int ip; struct iplist_struct * next; }; struct list_struct { unsigned char hw[ETH_ALEN]; struct iplist_struct * iplist; struct iplist_struct * lastip; struct list_struct * next; } * head = NULL, * tail = NULL; /* Functions */ char * hwaddr_to_str (unsigned char * str); unsigned char * str_to_hwaddr (char * str); unsigned int hexstr_to_int (char *cptr); void netmap (int fd, unsigned long int start_ip); void usage (char * av, int mode); void add_to_list (unsigned long int ip, unsigned char * hw); void show_list (); /* Global variables */ unsigned long netmask, broadcast; /* struct in_addr */ unsigned char hwaddr[ETH_ALEN]; struct sockaddr sock; int verbose = 0; void sendarp (int fd, unsigned char * h_source, unsigned char * h_dest, \ unsigned char * arp_src, unsigned char * arp_dst, \ unsigned long int ip_source, unsigned long int ip_dest, unsigned char op) { struct pkt_struct pkt; // Ethernet header. memcpy(&pkt.eth_dst,h_dest,ETH_ALEN); memcpy(&pkt.eth_src,h_source,ETH_ALEN); pkt.eth_proto = htons(ETH_P_ARP); // ARP header. pkt.arp_hw_type = htons(ARP_ETHER); pkt.arp_proto = htons(ETH_P_IP); pkt.arp_hw_len = ETH_ALEN; pkt.arp_proto_len = 4; pkt.arp_oper = htons(op); if (arp_src==0) bzero(&pkt.arp_hw_src,ETH_ALEN); else memcpy(&pkt.arp_hw_src,arp_src,ETH_ALEN); if (arp_dst==0) bzero(&pkt.arp_hw_dst,ETH_ALEN); else memcpy(&pkt.arp_hw_dst,arp_dst,ETH_ALEN); memcpy(&pkt.arp_ip_src,&ip_source,4); memcpy(&pkt.arp_ip_dst,&ip_dest,4); if ( (sendto(fd,&pkt,sizeof(pkt),0,&sock,sizeof(sock))) < 0) perror("Error sending ARP"); if (verbose) { char ips[16], hws[18]; strncpy(ips,inet_ntoa(ip_source),16); strncpy(hws,hwaddr_to_str(pkt.eth_src),18); printf(" - Sending packet: Ether src: %s - Ether dst: %s \n",hws,hwaddr_to_str(pkt.eth_dst)); strncpy(hws,hwaddr_to_str(pkt.arp_hw_src),18); printf(" ARP hw src: %s - ARP hw dst: %s\n",hws,hwaddr_to_str(pkt.arp_hw_dst)); printf(" ARP ip src: %s - ARP ip dst: %s - ARP op: ",ips,inet_ntoa(ip_dest)); if (op==1) printf("%s\n","Request"); else printf("%s\n","Reply"); } } void netmap (int fd, unsigned long int start_ip) { unsigned long int ip, ip_s; struct pkt_struct * pkt; int i; ip_s = start_ip; ip = ip_s & netmask; i = fcntl(fd,F_GETFL); if ((fcntl(fd,F_SETFL, i | O_NONBLOCK))<0) { perror("FCNTL"); exit (1); } pkt = (struct pkt_struct *) malloc(sizeof(struct pkt_struct)); bzero(pkt,sizeof(struct pkt_struct)); printf(" - Mapping network... \n"); while (ip < broadcast) { unsigned long int iptmp; unsigned char hwa[ETH_ALEN]; ip = ntohl(ip); ip = htonl(++ip); sendarp(fd,hwaddr,str_to_hwaddr("FF:FF:FF:FF:FF:FF"),hwaddr,0,ip_s,ip,ARP_REQUEST); usleep(1000); i = sizeof(sock); bzero(pkt,sizeof(struct pkt_struct)); if ((recvfrom(fd,pkt,sizeof(struct pkt_struct),0,&sock,&i)) < 0) continue; memcpy(&iptmp,pkt->arp_ip_dst,4); if ((iptmp!=ip_s) || (ntohs(pkt->arp_oper)!=ARP_REPLY)) continue; memcpy(&iptmp,pkt->arp_ip_src,4); add_to_list(iptmp,pkt->eth_src); } show_list(); free (pkt); } void main (int argc, char ** argv) { struct ifreq ifr; struct sockaddr_in sin; struct spoof_struct sp; unsigned long int ip; int fd, ret; int i = 0, map = 0, spoof = 0, interval = 0; char * dev; // Parsing the arguments. if (argc < 2) { usage(argv[0],0); exit(1); } usage(argv[0],1); dev = (char *) malloc(6); strncpy(dev,"eth0",5); while ((i = getopt(argc, argv, "dc:vmi:s:")) != EOF) { switch (i) { case 'm': map = 1; continue; case 'v': verbose = 1; continue; case 'i': dev = optarg; continue; case 'c': interval = atoi(optarg); continue; case 's': spoof = optind-1; continue; case '?': exit(1); default: usage(argv[0],0); exit; } } if ((map) && (spoof)) { printf(" Error: cannot run in map mode (-m) and spoof mode (-s) simultaneously.\n"); exit(1); } if ((!map) && (!spoof)) { printf(" Error: map mode (-m) or spoof mode (-s) must be specified.\n"); exit(1); } if (spoof) { unsigned long int ips; int origspoof = spoof; spoof = optind; if ((!argv[origspoof]) || (!argv[spoof]) || (!argv[spoof+1]) || (!argv[spoof+2]) || (!argv[spoof+3])) { printf(" Error: spoof (-s) requires five arguments: \n"); exit(1); } ips = atoi(argv[spoof+3]); if ( (ips!=1) && (ips!=2) ) { printf(" Erro: wrong arp operation. Must be 1 for request or 2 for reply. \n"); exit(1); } memcpy(&sp.hw_src,str_to_hwaddr(argv[origspoof]),ETH_ALEN); memcpy(&sp.hw_dst,str_to_hwaddr(argv[spoof++]),ETH_ALEN); ips= inet_addr(argv[spoof++]); memcpy(&sp.ip_src,&ips,4); ips = inet_addr(argv[spoof++]); memcpy(&sp.ip_dst,&ips,4); ips = atoi(argv[spoof]); memcpy(&sp.op,&ips,1); } // Setting up the sockets, interface, and getting data. strcpy(sock.sa_data,dev); sock.sa_family = AF_INET; fd = socket(AF_INET, SOCK_PACKET, htons(ETH_P_ARP)); if (fd==-1) { perror("Socket: "); exit (1); } // HW Addr. strcpy(ifr.ifr_name,dev); ret = ioctl(fd,SIOCGIFHWADDR,&ifr); if (ret==-1) { perror("Error getting HW Address"); exit (1); } memcpy(hwaddr,ifr.ifr_hwaddr.sa_data,ETH_ALEN); // IP. ret = ioctl(fd,SIOCGIFADDR,&ifr); if (ret==-1) { perror("Error getting IP Address"); exit (1); } memcpy(&sin,&ifr.ifr_addr,sizeof(struct sockaddr_in)); ip = sin.sin_addr.s_addr; // Netmask. ret = ioctl(fd,SIOCGIFNETMASK,&ifr); if (ret==-1) { perror("Error getting netmask"); exit (1); } memcpy(&sin,&ifr.ifr_netmask,sizeof(struct sockaddr_in)); netmask = sin.sin_addr.s_addr; // netmask = 16777215; // 24 bit Netmask // Broadcast. ret = ioctl(fd,SIOCGIFBRDADDR,&ifr); if (ret==-1) { perror("Error getting broadcast"); exit (1); } memcpy(&sin,&ifr.ifr_broadaddr,sizeof(struct sockaddr_in)); broadcast = sin.sin_addr.s_addr; printf(" - Hardware addr : %s\n",hwaddr_to_str(hwaddr)); printf(" - Interface IP: %s (%s)\n",inet_ntoa(ip),dev); printf(" - Netmask: %s\n",inet_ntoa(netmask)); printf(" - Brodcast: %s\n",inet_ntoa(broadcast)); while (1) { if (map) netmap (fd,ip); if (spoof) { sendarp(fd,sp.hw_src,sp.hw_dst,sp.hw_src,sp.hw_dst,sp.ip_src,sp.ip_dst,sp.op); } if (interval) sleep(interval); else break; } } char * hwaddr_to_str (unsigned char * str) { static char tmp[20]; sprintf(tmp,"%02X:%02X:%02X:%02X:%02X:%02X",str[0],str[1],str[2],str[3],str[4],str[5]); return tmp; } unsigned int hexstr_to_int(char *cptr) { unsigned int i, j = 0; while (cptr && *cptr && isxdigit(*cptr)) { i = *cptr++ - '0'; if (9 < i) i -= 7; j <<= 4; j |= (i & 0x0f); } return(j); } unsigned char * str_to_hwaddr (char * str) { unsigned char tmp[2], strbuf[17], t[2]; static unsigned char * buf, * tt; int e, i; buf = (unsigned char *) malloc(6); bzero(t,2); bzero(tmp,2); bzero(strbuf,17); bzero(buf,6); strncpy(strbuf,str,17); strbuf[17]='\0'; tt = buf; e = 0; for (i=0; i < strlen(strbuf); i++) { if ((strbuf[i]==':') && (e==0)) continue; tmp[e] = strbuf[i]; e++; if (e==2) { unsigned int a; a = hexstr_to_int(tmp); memcpy(tt,&a,1); tt++; bzero(tmp,2); e = 0; } } return buf; } void usage (char * av, int mode) { printf(" ARPTool v0.1, (c) Cristiano Lincoln Mattos, 1999. \n"); if (!mode) { printf(" Sintax: %s [-i interface] [-m] [-c] [-s hwsrc hwdest ipsrc ipdst op]\n",av); printf(" -i interface: use this interface. If ommited, default to eth0\n"); printf(" -m: network map mode. Will identify all hosts on the same \n cable segment. \n"); printf(" -s src_hwaddress dst_hwaddress src_ipaddress dst_ipaddress operation:\n"); printf(" send arbitrary ARP packets. The hardware address must be \n specified in the usual form, i.e. 00:00:FD:FF:1E:C1.\n Operation is 1 for ARP request, 2 for ARP reply. \n"); printf(" -c interval: continuous mode. Will keep sending the specified \n packets every interval seconds (requires -s or -m).\n"); exit(1); } } void show_list () { struct list_struct * tmp, * tmp2; tmp = head; while (tmp!=NULL) { struct iplist_struct * iptmp; iptmp = tmp->iplist; printf(" -- HW Address: %s",hwaddr_to_str(tmp->hw)); if (iptmp->next) printf(" - Several IP's: probably router with proxy arp, or virtual interfaces.\n"); while (iptmp!=NULL) { printf(" IP: %s\n",inet_ntoa(iptmp->ip)); iptmp = iptmp->next; } free(iptmp); tmp2 = tmp->next; free(tmp); tmp = tmp2; } return; } void add_to_list (unsigned long int ip, unsigned char * hw) { struct list_struct * tmp; struct iplist_struct * iptmp; tmp = head; while (tmp) { if ((hw[0]==tmp->hw[0]) && (hw[1]==tmp->hw[1]) && (hw[2]==tmp->hw[2]) && (hw[3]==tmp->hw[3]) &&\ (hw[4]==tmp->hw[4]) && (hw[5]==tmp->hw[5])) break; tmp = tmp->next; } if (!tmp) { // If it's the first HW entry, or did not find HW in list, create if ((tmp = (struct list_struct *) malloc(sizeof(struct list_struct))) == NULL) { printf("\n malloc error. \n"); exit (1); } if ((iptmp = (struct iplist_struct *) malloc(sizeof(struct iplist_struct))) == NULL) { printf("\n malloc error. \n"); exit (1); } iptmp->ip = ip; iptmp->next = NULL; tmp->iplist = iptmp; tmp->lastip = iptmp; tmp->next = NULL; memcpy(tmp->hw,hw,ETH_ALEN); if (tail) { tail->next = tmp; tail = tmp; } } else { // Found the HW entry in the list, just add the IP. if ((iptmp = (struct iplist_struct *) malloc(sizeof(struct iplist_struct))) == NULL) { printf("\n malloc error. \n"); exit (1); } iptmp->ip = ip; iptmp->next = NULL; tmp->lastip->next = iptmp; tmp->lastip = iptmp; } if (!head) head = tail = tmp; }