Scapy 是一个非常实用的交互式数据包处理工具,适合用于构造、发送、捕获、解析和匹配各种网络协议数据包。它既能完成常见的网络测试任务,也能胜任一些传统工具不太方便处理的场景,例如协议探测、路由跟踪、扫描、单元测试以及网络发现等。
在很多情况下,Scapy 可以覆盖多种网络工具的部分能力。它的优势在于灵活、可编程,并且适合快速验证网络通信过程中的各种细节。对于学习网络协议、分析报文结构和进行实验性测试来说,它是一个非常高效的选择。
安装 Scapy
如果使用的是 Python 3 环境,通常直接通过 pip 安装即可:
pip3 install scapy
进入 Scapy 交互环境
安装完成后,可以在终端中输入 scapy 进入交互式 Shell。在这个环境里,可以直接构造和操作数据包。
常用查看命令包括:
ls():查看支持的协议,或查看某个协议包含的字段参数。lsc():查看可用的内置函数。
发送与接收数据包
send()
send() 用于在第 3 层发送数据包,由 Scapy 自动补齐第 2 层头部,不负责接收返回数据。
常见参数:
count:指定发送次数。loop:循环发送,直到手动中断。inter:设置每次发送之间的间隔时间。
示例:
send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'))
send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'), count=10)
send(IP(dst='8.8.8.8')/TCP(dport=53, flags='S'), loop=1)
sendp()
sendp() 与 send() 类似,但工作在第 2 层,因此需要显式提供链路层头部。它适合在指定网卡上直接发送以太网帧。
示例:
sendp(Ether()/IP(dst='1.2.3.4', ttl=(1,4)), iface='eth0')
sendp("I'm travelling on Ethernet", iface='eth0', loop=1, inter=0.2)
sendp(rdpcap('/tmp/pcapfile'))
sr()
sr() 用于发送数据包并接收响应,返回两个结果集:一个是已收到响应的数据包,另一个是没有收到响应的数据包。
示例:
sr(IP(dst='60.205.177.168')/TCP(dport=[21,22,23]))
通常可以这样获取结果:
ans, unans = sr(IP(dst='60.205.177.168')/TCP(dport=[21,22,23]))
unans.summary()
sr1()
sr1() 会发送数据包,并只返回接收到的第一个响应结果。适合只关心单个回复的场景。
示例:
p = sr1(IP(dst='www.baidu.com')/ICMP()/"asdqwe")
srloop()
srloop() 用于循环发送数据包,并持续显示收到的响应。这个函数适合观察目标主机在连续请求下的回应情况。
示例:
packet = IP(dst='60.205.177.168')/ICMP()
srloop(packet)
使用 Scapy 创建数据包
Scapy 的数据包构造方式遵循网络协议分层思想。每一层都是一个独立对象,完整的数据包则通过把这些层依次叠加形成。
它会根据 TCP/IP 各层协议头的定义来组织报文,因此既适合快速构造简单数据包,也适合做更精细的字段控制。
一行构造数据包
可以直接使用一行语句完成多层封装:
packet = Ether()/IP(dst='8.8.8.8')/TCP(dport=53, flags='S')
分层构造后再组合
也可以先分别创建各层,再通过 / 运算符进行堆叠:
l2 = Ether()
l3 = IP(dst='8.8.8.8/30')
l4 = TCP(dport=53, flags='S')
packet = l2/l3/l4
Scapy 支持的 IP 写法
Scapy 对目标地址的写法支持比较灵活,既可以使用普通 IP,也可以使用 CIDR 表示法,甚至可以直接使用主机名。
示例:
packet = IP(dst='8.8.8.8')
packet = IP(dst='scanme.nmap.org')
packet = IP(dst='8.8.8.8/30')
packet = IP(dst='egadz.metasploit.com/30')
这意味着它不仅能描述单个目标,还能生成一个地址集合,方便用于批量测试。
创建一组数据包
Scapy 可以通过字段取值范围或列表,自动生成一组数据包。这样在做扫描或参数组合测试时会非常方便。
例如:
pkts = IP(ttl=[1,3,5,(7,10)])/TCP()
packet = IP(dst='192.168.*.1-10')/TCP(dport=(0,100))
通过这种方式,可以一次性生成多个不同 TTL、目标地址或端口的数据包,减少重复编写代码的工作量。
检查数据包结构
在构造好数据包后,可以用 ls() 查看其字段详情以及对应的数据类型。这对于理解报文结构和调试字段设置非常有帮助。
示例:
packet = IP()/TCP()
ls(packet)
执行后会显示该数据包中各字段的名称、类型及默认值,例如 IP 头中的 version、ihl、tos、len 等。
总结
Scapy 的核心价值在于“可编程的数据包处理”。它既可以作为学习网络协议的实验工具,也可以作为实际测试中的灵活组件。掌握安装、交互环境、收发函数以及分层构造报文的方法后,就可以逐步开展更深入的网络分析与自动化测试工作。
