以前学网络用的谢希仁的《计算机网络原理》,一是网开始学不太懂网络二是ARP协议是没有数据包格式的(如果没记错应该是没有)。学完只记得老师说:ARP很简单的,就是一个问谁有x.x.x.x这个地址告诉y.y.y.y,一个答x.x.x.x在z:z:z:z:z:z。自己就一直在想这怎么简单法嘛,数据包到底长什么样嘛,把"Who has x.x.x.x? Tell y.y.y.y"用ASCII编码发出去吗。当时Wireshark也不会就不了了之了,所以其实就数据包来说我一直也不懂ARP长什么样,昨天分析了一天产品用到的各种协议,今天突然想到似乎需要看一下ARP长什么样了。
如果对wireshark不太熟悉,可参考"wireshark捕获/显示过滤器表达式书写规律说明"。
网络传输我们一般说是通过IP地址传输的,但更专业的说法应该是MAC地址实现同子网主机的通信、在此基础上IP地址实现远程主机到远程主机的通信、在此基础上端口实现进程到进程之前的通信。换言之一个数据包必要必先要有Eth头,然后才是IP头、TCP头,单纯只有IP+端口是无法完成网络通信的。Eth最重要的就是MAC地址,而MAC地址的获取或者叫学习就是使用ARP协议。
ARP是一种同子网内以IP地址找MAC地址的协议。(另外有一种叫RARP的协议,是一种同子网内通过MAC地址找IP的协议,但MAC地址怎么知道是不是同子网?不太懂)
我们这里一直强调“同子网”这个定语,因为不同子网内的地址一是你学不到(终端主机不会向不同子网发送ARP方播包)二是不同子网的MAC地下学来没有意义(MAC地址要且只要能且只能完成同子网内的通信,这也是终端主机不会向不同子网发送ARP方播包的原因)。
我们现在考滤这样一个场景:x.x.x.x要向y.y.y.y的http服务发起访问,ip地址和端口都是很明确的所以ip头和tcp头构造没有问题,那如何获取Mac地址构造Eth头呢?整个流程是这样:x.x.x.x主机先看y.y.y.y是否是同子网ip,不同子网则查找本地MAC地址表中是否有网关ip对应的MAC地址,有则直接使用没有则对网关ip发起ARP;同子网则查找本地MAC地址表中是否有y.y.y.y对应的MAC地址,有则直接使用没有则对y.y.y.y发起ARP。ARP查看本地MAC地址表中是否有给定的ip对应的mac地址,有则向该MAC地址发送ARP查询包,没有则向ff:ff:ff:ff:ff:ff广播ARP查询包。
可能有人会觉查在上面的描述中有个问题:主机分明是在mac地址表中找不到ip对应mac地址后发起的ARP,为什么ARP还要自己再去查询mac地址表中是否有ip对应mac地址,这不是多此一举吗?这是因为MAC地址表除了建立之外还有维护的工作,即针对MAC地址表中已有条目ARP每隔一段时间(几秒?)就会针对每个条目发送一个ARP查询包确认该条目是否还是正确的。因为ARP身兼维护工作,所以他就不只是做为通信时刻的一个附属而是一个独立的程序;而从重用性角度建立和维护应该是使统一的代码,所以ARP自己要去确认MAC地址表中是否有ip对应的mac地址。
主机关机、更换IP、更换网卡这些都是常有的事,所以维护是必要的。当然你可以说不管建立和维护我都直接发广播包不就完事了?从道理上是可以的,但是广播包是很消耗带宽的,而主机没有关机、没有更换IP、没有更换网卡是概率更大的事,向原来MAC地址发送ARP查询包是命中率很高的事(对于交换机要向每个端口都发送一份而对每个终端主机都要接收一个数据包),这样能节省的资源还是可观的。
MAC地址表就是一个“IP地址-MAC地址”的对照表,但我们一直说没看到长什么样总是让人觉得水够直观。其实很简单打开命令行使用arp -a进行查看即可。
arp -a
ARP数据包当然不会真把"Who has x.x.x.x? Tell y.y.y.y"之类的人类语句经ASCII编码而成,凡协议就是由各字段组成的结构(struct),各字段的含义是收发两端协定好的不会加上文字描述其用途。
ARP只有三类数据包但他们共用一个数据包格式:指向性查询包,广播性查询包和响应包。指向性查询包与方播性查询包的区别是指向性查询包Target hardware address(THA)字段是原来记录的Mac地址,而广播性查询包是00:00:00:00:00:00;查询包与响应包的区别是查询包Operation字段值为1响应包中Operation字段值为2。
前面我们说有ARP指向应查询包和ARP广播查询包但这两者的区别在Eth头的dst mac上和ARP头无关;另外还要注意不管是指向应查询还是广播查询,响应包都是指向性的而不是广播的(所以使用wireshark你可以截获各个地址发出的广播查询包但只能截获自己地址的响应包)。
列坐格是相对头部的偏移量(单位字节),横坐标表示两个字节长度。next 2 bytes等表示该区域同属上一字段。
Hardware type(HTYPE)----网卡类型,以太网(Ethernet)是1。我们常见的网络都是以太网,但这并不意味着只有以太网。
Protocol type(PTYPE)----查询中提供的网络地址的类型,IPv4是0x0800。
Harware lenght(HLEN)----网卡地址长度,以太网网卡是6字节。
Protocol lengt(PLEN)----查询中提供的网络地址的的长度,IPv4是4字节。
Operation----查询包值为1,响应包值为2。
Sender hardware address(SHA)----发送者的Mac地址。
Sender protocol address(SPA)----发送者的IP地址。
Target hardware address(THA)----接收者的Mac地址,指向性查询包是MAC地址表中记录的mac,广播性查询包是00:00:00:00:00:00。(注意区分ARP头和Eth头,指向性查询包Eth头的dst mac是MAC地址表中记录的mac,而广播性查询包是ff:ff:ff:ff:ff:ff)。
Target protocol address(TPA)----要查询mac地址的ip。
注意arp是数据链路层协议还不是网络层协议,即没有ip头所以不能用ip头过滤而只能用eth头过滤;可使用ipconfig /all查看自己网卡mac地址。
指向性查询数据包:
广播性查询数据包:
响应数据包:
第一步,arp攻击程序先向待攻击目标IP发出广播性查询数据包,获取其mac地址。
第二步,arp攻击程序向待攻击目标IP发送响应数据包,告诉该主机攻击程序欲伪造的IP对应的mac地址是攻击程序主机的mac地址。
经以上两步会造成以下影响:
该存活主机本应发往受伪造主机的数据包会发往攻击程序所在主机;特别地,当受伪造主机是网关那所有原本发往网关的数据都会被发送。造成信息泄漏,这也是最常说的arp攻击。
如果攻击程序不回应数据包,那就进一步造成该存活主机网络通信异常。
如果攻击程序回复针对性构造的数据包,那可造成中间人攻击。
光说不练假把式,我们直接上一下最简单的ARP欺骗的代码:
from scapy.all import *
# 要欺骗的机器的IP
fake_taget = "10.10.6.94"
# 要伪造的机器IP
faked_ip = "10.10.6.95"
# 要伪造的机器的MAC
faked_mac = "11:22:33:44:55:66"
# 总的意思就是:不断告诉pdst,psrc的mac地址是hwsrc
srloop(ARP(psrc=faked_ip,hwsrc=faked_mac,pdst=fake_taget,op=2))
原先94的arp记录如下:
欺骗后,94的arp记录如下,可以看到10.10.6.95的mac地址记录已被欺骗:
20190830补充说明:
理论上来说由于此时94上的95的MAC地址不对,所以94应当是ping不通95的,但实际测试发现当使用“11:22:33:44:55:66”这种比较“假”的MAC地址时,在多次接收不到响应后会触发ping程序的防欺骗机制ping程序会将MAC替换成一种广播地址,95接收到广播消息后应会回应,这样就导致从观察上看还是能ping通的。处理办法就是使用形如“18:31:BF:CA:1D:34”这样比较“真”的MAC地址。
另外,不同子网是不用记录MAC的,所以比如你想伪造百度的MAC让目标机器ping不通百度,那你本质上应当伪造的是网关的MAC地址。
从《华为交换机学习指南》整理出两条看起来比较实用的arp防范方法:
一是只从自己发送的ARP请求报文的应答报文中学习。不过因为似乎只有应答报文中的“Sender Mac address”和“Sender IP address”可以标识,所以如果这两项也伪造那还是可以欺骗。
二是启用send-ack方式。即当收到一个修改mac地址表的arp响应报文时,先向被修改项发送一个指向应查询数据包如果无响应或有响应但返回结果有改变,那就允许mac地址表修改反之不予处理。