Scapy 详细安装教程、功能介绍与快速上手
Scapy 网络数据包处理工具的安装方法(Windows/Ubuntu)、核心调试函数(rdpcap/show/ls/lsc/help)及主要功能。涵盖报文结构查看、数据包构造(以太/IP/ICMP 层)、发送函数(send/sendp/sr/sr1/srp)区别及高速发包(sendpfast)示例,并演示了基于 Wireshark 抓包的组包流程与 ICMP 报文嗅探实战。

Scapy 网络数据包处理工具的安装方法(Windows/Ubuntu)、核心调试函数(rdpcap/show/ls/lsc/help)及主要功能。涵盖报文结构查看、数据包构造(以太/IP/ICMP 层)、发送函数(send/sendp/sr/sr1/srp)区别及高速发包(sendpfast)示例,并演示了基于 Wireshark 抓包的组包流程与 ICMP 报文嗅探实战。

Scapy 是一个基于 Python 的交互式数据包操纵工具,能够发送、嗅探、解析和伪造网络数据包,其核心能力包括网络探测、扫描和协议分析。作为多功能工具,在吞吐量和性能要求不高的情况下,可代替测试仪构建和组装想要的报文内容,实现抓包和发包的功能。
Scapy 是一个强大的 Python 网络数据包操作工具,其核心优势在于灵活性和协议支持广度,但也存在一定局限性。
A、协议支持全面:支持 IPv4/IPv6、TCP/UDP、ARP、ICMP 等超过 800 种协议,可构造复杂数据包并进行发送、捕获及解析主流协议,以及 802.11 无线协议。
B、交互式操作与脚本化:通过 Python 脚本灵活构造数据包,支持实时交互调试,适用于渗透测试和教育演示。
C、跨平台兼容性:支持 Linux/Windows/macOS,并集成 Wireshark 解析引擎提升分析效率。
A、性能局限:基于 Python 实现,处理高并发流量时性能低于 C/C++ 工具(如 Nmap),通常不会超过 1000pps。
B、学习曲线较陡:需深入理解网络协议才能有效使用,对新手不够友好。
C、无线功能依赖硬件:802.11 功能需特定网卡支持(如支持 monitor 模式的无线网卡)。
Scapy 的安装需确保 Python 环境已正确配置(建议 3.7+ 版本),并通过 pip 直接安装或离线部署。
以管理员权限打开 Windows 的 cmd 窗口,使用命令 pip install scapy 安装 scapy 包,可以使用 pip list 检查 scapy 是否安装成功,在 python 已设置全局变量的情况下可执行 scapy 来进入 shell 界面。
pip install scapy
pip list

Ubuntu 使用 root 权限安装 scapy。
apt install python3-scapy
# 或者
apt install scapy
使用 pip list | grep scapy 查看 scapy 是否安装版本。

当我们在组包时,不清楚报文需要封装哪些头和 data 时,可以使用 rdpcap 读取 wireshark 抓取的真实报文,打印出来,然后按照输出的报文结构进行组包。其中 [0] 是报文索引,表示第一个报文。
from scapy.all import *
pkt = rdpcap("icmp.pcap")[0]
print(pkt)
ICMP 报文由以太头、IP 头、ICMP 协议层、data 构成,上文以作说明,这里不再重复赘述。
// 打印如下 Ether / IP / ICMP 192.168.0.103 > 192.168.0.1 echo-request 0 / Raw
当我们需要构建精准报文时,不清楚需要填写哪些字段和内容时,可以使用 show() 函数打印真实报文,再模仿构造。
from scapy.all import *
pkt = rdpcap("icmp.pcap")[0]
pkt.show()
// 打印如下 ###[ Ethernet ]### dst = 18:f2:2c:c8:90:11 src = d8:b3:2f:80:2d:11 type = IPv4 ###[ IP ]### version = 4 ihl = 5 tos = 0x0 len = 60 id = 36773 flags = frag = 0 ttl = 128 proto = icmp chksum = 0x2963 src = 192.168.0.103 dst = 192.168.0.1 \
options \
###[ ICMP ]### type = echo-request code = 0 chksum = 0x4d48 id = 0x1 seq = 0x13 unused = b'' ###[ Raw ]### load = b'abcdefghijklmnopqrstuvwabcdefghi'
ls() 函数可查看 scapy 支持的所有协议、头部字段及默认值罗列等。
from scapy.all import *
from scapy.layers.inet import TCP, IP
ls() # 列出所有支持的协议
ls(IP) # 显示 IP 头部字段及默认值
列出 Scapy 所有内置函数(如发包/嗅探/ARP 欺骗等)。
from scapy.all import *
lsc()
// 打印如下 IPID_count : Identify IP id values classes in a list of packets arp_mitm : ARP MitM: poison 2 target's ARP cache ...
查看函数/类的详细使用说明(如参数含义、返回值)。
from scapy.all import *
help(sendp)
// 打印如下 Help on function sendp in module scapy.sendrecv: sendp(x, iface=None, iface_hint=None, socket=None, **kargs) Send packets at layer 2 ...
scapy 官方文档介绍:https://scapy.readthedocs.io/en/latest/
当我们想要组一个 scapy 报文时,就先要了解该报文的结构,scapy 官方文档提供了部分的 API,可能不够全面,或者很难查询到我们想要的报文结构。此时,我们可以通过 wireshark 把想要的报文抓下来,再通过 scapy 去解析,然后重新组包发送,或者修改现有报文再重放。以下举一个 icmp request 组包举例:

from scapy.all import *
# 使用 show() 函数,把抓取的 icmp 报文结构读出来
icmp_req = rdpcap("icmp.pcap")[0]
icmp_req.show()
// 打印如下: ###[ Ethernet ]### dst = 18:f2:2c:c8:90:11 src = d8:b3:2f:80:2d:11 type = IPv4 ###[ IP ]### version = 4 ihl = 5 tos = 0x0 len = 60 id = 36773 flags = frag = 0 ttl = 128 proto = icmp chksum = 0x2963 src = 192.168.0.103 dst = 192.168.0.1 \
options \
###[ ICMP ]### type = echo-request code = 0 chksum = 0x4d48 id = 0x1 seq = 0x13 unused = b'' ###[ Raw ]### load = b'abcdefghijklmnopqrstuvwabcdefghi'
根据 TCP/IP 标准模型,从上文可查看 icmp 总共有以太层、IP 层、ICMP 协议层、data;可按照以上格式进行组包:
# 步骤一:分别查看以太层、IP 层、ICMP 协议层、Raw 下参数名称和类型,以 Eher 为例
ls(Ether)
# 打印如下 dst : DestMACField =('None') src : SourceMACField =('None')type: XShortEnumField =('36864')
# 步骤二:组包。数据通信对报文正确性、完整性有严格的校验,包括 chksum 等,以下只做教学举例,列举了部分关键字段。
from scapy.all import *
from scapy.layers.inet import ICMP, IP
from scapy.layers.l2 import Ether
eth = Ether(dst="18:f2:2c:c8:90:11", src="d8:b3:2f:80:2d:11",type="IPv4")
ip = IP(proto="icmp", src="192.168.0.103", dst="192.168.0.1")
icmp = ICMP(type="echo-request")
data = Raw(load=b'abc')
icmp_req_pkt = eth / ip / icmp / data
# 步骤三:查看已经组好的报文
icmp_req_pkt.show()
// 打印如下 ###[ Ethernet ]### dst = 18:f2:2c:c8:90:11 src = d8:b3:2f:80:2d:11 type = IPv4 ###[ IP ]### version = 4 ihl = None tos = 0x0 len = None id = 1 flags = frag = 0 ttl = 64 proto = icmp chksum = None src = 192.168.0.103 dst = 192.168.0.1 \
options \
###[ ICMP ]### type = echo-request code = 0 chksum = None id = 0x0 seq = 0x0 unused = b'' ###[ Raw ]### load = b'abc'
以下是 Scapy 中 send()、sendp()、sr()、sr1() 和 srp() 系列函数的区别总结。
send(IP(dst="1.2.3.4")/ICMP()) 发送 ICMP 请求sendp(Ether()/IP(dst="1.2.3.4"), iface="eth0") 发送以太网帧sr(IP(dst="192.168.1.1")/TCP(dport=80)) 扫描端口sr1(IP(dst="192.168.1.1")/ICMP()) 探测主机存活srp(Ether()/ARP(), timeout=2) 发送 ARP 请求send()、sendp()、sr()、sr1() 和 srp() 系列函数关键区别对比
| 函数 | 工作层级 | 是否接收响应 | 返回内容 | 典型用途 |
|---|---|---|---|---|
| send() | L3 | 否 | 无 | 快速发送单次数据包 |
| sendp() | L2 | 否 | 无 | 循环发送或指定网卡 |
| sr() | L3 | 是 | 所有响应和未应答包 | 端口扫描、统计响应 |
| sr1() | L3 | 是 | 仅第一个响应包 | 探测主机、快速验证 |
| srp() | L2 | 是 | 二层协议响应 | ARP 交互、二层攻击 |
注意:
Scapy 中的 sendpfast() 是一个专为高速发送二层数据包设计的函数,其核心特点如下:
sendpfast() 参数说明
sendpfast( pkt,# 要发送的数据包对象(需包含 L2 头)
pps=None,# 每秒发包数(如 pps=1000)
mbps=None,# 带宽限制(如 mbps=10)
loop=0,# 循环次数(0 为单次,1 为无限循环)
iface=None# 指定网卡(如 iface="eth0")
)
sendfast() 使用示例
from scapy.all import *
# 构造 ARP 请求包
pkt = Ether(dst="ff:ff:ff:ff:ff:ff"]/ARP(pdst="192.168.1.0/24")
# 以 1000pps 速率发送
sendpfast(pkt, pps=1000, iface="eth0")
在上文中,我们已组装好了一个 icmp 报文,方便后续讲解 sniff() 函数,接下来我们将使用 scapy 的 sendp() 函数进行举例,接收并解析响应报文。
# sendp() 举例说明
from scapy.all import *
from scapy.layers.inet import ICMP, IP
from scapy.layers.l2 import Ether
eth = Ether(dst="18:f2:2c:c8:90:11", src="d8:b3:2f:80:2d:11",type="IPv4")
ip = IP(proto="icmp", src="192.168.0.103", dst="192.168.0.1")
icmp = ICMP(type="echo-request")
data = Raw(load=b'abc')
icmp_req_pkt = eth / ip / icmp / data
sendp(icmp_req_pkt, count=1, iface="WLAN")
# sr1 举例说明,可直接获取 icmp reply 报文
from scapy.all import *
from scapy.layers.inet import ICMP, IP
from scapy.layers.l2 import Ether
ip = IP(proto="icmp", src="192.168.0.103", dst="192.168.0.1")
icmp = ICMP(type="echo-request")
data = Raw(load=b'abc')
icmp_req_pkt = ip / icmp / data
sr1(icmp_req_pkt, timeout=3, iface="WLAN")
使用 wireshark 抓取 "WLAN" 接口的报文,过滤报文类型为 icmp,可查看收到 icmp reply。

当使用测试 PC 发送 icmp 报文进行 Ping 网关时,报文交互如下:
PC -> 网关 icmp request -> 网关 icmp reply -> PC
from scapy.all import *
from scapy.layers.inet import ICMP, IP
from scapy.layers.l2 import Ether
eth = Ether(dst="18:f2:2c:c8:90:11", src="d8:b3:2f:80:2d:11",type="IPv4")
ip = IP(proto="icmp", src="192.168.0.103", dst="192.168.0.1")
icmp = ICMP(type="echo-request")
data = Raw(load=b'abc')
icmp_req_pkt = eth / ip / icmp / data
sendp(icmp_req_pkt, count=1, iface="WLAN")
reply = sniff(filter=f"icmp[icmptype]==0 and src host 192.168.0.1",count=1,timeout=5)
if reply:
print("[success] 捕获到 ICMP 响应:")
reply[0].show()
else:
print("[fail] 未捕获到响应")
// 打印如下 . Sent 1 packets.
[success] 捕获到 ICMP 响应:
###[ Ethernet ]### dst = d8:b3:2f:80:2d:11 src = 18:f2:2c:c8:90:11 type = IPv4
###[ IP ]### version = 4 ihl = 5 tos = 0x0 len = 31 id = 29959 flags = frag = 0 ttl = 64 proto = icmp chksum = 0x841e src = 192.168.0.1 dst = 192.168.0.103 \
options \
###[ ICMP ]### type = echo-reply code = 0 chksum = 0x3b9d id = 0x0 seq = 0x0 unused = b''
###[ Raw ]### load = b'abc'
备注:filter 过滤规则介绍
filter="icmp[icmptype]==8" # 只捕获 ICMP 请求(type=8)filter="icmp[icmptype]==0" # 只捕获 ICMP 响应(type=0)filter="icmp and host 192.168.1.1" # 捕获与指定主机的所有 ICMP 通信filter="icmp and src host 192.168.1.1" # 只捕获来自该主机的 ICMPfilter="icmp and dst host 192.168.1.1" # 只捕获发往该主机的 ICMP
微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
解析常见 curl 参数并生成 fetch、axios、PHP curl 或 Python requests 示例代码。 在线工具,curl 转代码在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML 转 Markdown 互为补充。 在线工具,Markdown 转 HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML 转 Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online