4、Python与Scapy:Scapy库安装、构造与发送数据包、嗅探与解析数据包
各位好,我是老张。今天咱们聊聊Scapy这个工具。说实话,我入行头三年,抓包分析全靠Wireshark,点来点去虽然直观,但遇到批量处理或者自动化场景,就有点力不从心了。后来接触了Scapy,才发现原来用Python也能这么灵活地玩转网络包。说白了,Scapy就是一个让你用代码“捏”数据包、发出去、再抓回来的瑞士军刀。
核心观点:Scapy不是简单的抓包工具,它是一个数据包工厂。你可以像搭积木一样,从零构造一个TCP包、DNS查询包,甚至伪造一个ARP响应。我个人习惯把它当作网络协议的“乐高套装”。
4.1 Scapy库的安装
安装Scapy其实很简单。我建议直接用pip,干净利落。不过要注意,Scapy依赖一些底层库,比如libpcap(Linux/macOS)或者Npcap(Windows)。
# 基础安装
pip install scapy
# 如果需要图形化界面(比如查看包结构),可以装完整版
pip install scapy[complete]
小提示:Windows用户记得先装Npcap,不然抓包功能用不了。我曾经在这上面栽过跟头,装完Scapy发现嗅探没反应,折腾了半天才发现是Npcap没装。
验证安装是否成功,打开Python交互环境,输入:
from scapy.all import *
print(ls()) # 列出所有支持的协议
如果能看到一长串协议列表,比如IP、TCP、UDP、Ethernet等等,那就说明装好了。嗯,这里要注意,第一次导入可能会慢一点,因为Scapy要加载所有协议模块。
4.2 构造与发送数据包
Scapy最爽的地方,就是构造数据包像写诗一样自由。每个协议层用/符号拼接,从物理层到应用层,一层一层叠上去。
4.2.1 构造一个简单的ICMP Ping包
from scapy.all import *
# 构造一个IP层 + ICMP层
packet = IP(dst="8.8.8.8") / ICMP()
# 发送并等待响应
reply = sr1(packet, timeout=2)
if reply:
reply.show() # 显示响应包的详细信息
你看,就这么几行代码,一个Ping包就发出去了。我刚开始用的时候,觉得这比系统自带的ping命令灵活多了——你可以随意修改TTL、标识位,甚至伪造源IP。
避坑指南:我曾经在测试环境中,不小心把源IP改成了网关的IP,结果导致网络环路,整个办公室断网了5分钟。所以,伪造源IP这种事,玩玩可以,生产环境千万别乱来。
4.2.2 构造TCP SYN包(端口扫描基础)
做网络安全的朋友,肯定对SYN扫描不陌生。用Scapy实现起来,简直不要太简单:
# 构造SYN包
syn_packet = IP(dst="192.168.1.1") / TCP(dport=80, flags="S")
# 发送并等待SYN-ACK响应
response = sr1(syn_packet, timeout=1)
if response and response.haslayer(TCP):
if response.getlayer(TCP).flags == 0x12: # SYN-ACK标志
print("端口 80 开放")
elif response.getlayer(TCP).flags == 0x14: # RST标志
print("端口 80 关闭")
这里flags="S"表示设置SYN标志位。收到SYN-ACK说明端口开放,收到RST说明关闭。说白了,这就是半连接扫描的原理。我当年做渗透测试时,经常用这个脚本批量扫C段,比nmap还轻量。
4.2.3 发送方式的区别
| 函数 | 作用 | 适用场景 |
|---|---|---|
send() |
只发送,不等待响应 | 广播包、无状态攻击 |
sr() |
发送并接收所有响应 | 需要匹配请求-响应的场景 |
sr1() |
发送并只接收第一个响应 | Ping、单次查询 |
sendp() |
在二层(数据链路层)发送 | 构造自定义以太网帧 |
我个人习惯,如果只是测试连通性,用sr1()就够了。但如果你在做ARP欺骗或者DHCP饿攻击,需要持续监听响应,那就得用sr()配合超时参数。
4.3 嗅探与解析数据包
光会发包不算本事,能抓到包、读懂包,才是真功夫。Scapy的嗅探功能,说白了就是让你用Python写一个迷你版Wireshark。
4.3.1 基础嗅探
# 抓取10个包,不存储
pkts = sniff(count=10)
# 查看抓到的包
pkts.summary()
运行后,你会看到类似这样的输出:
Ether / IP / TCP 192.168.1.100:54321 > 142.250.80.46:443
Ether / IP / UDP 192.168.1.100:5353 > 224.0.0.251:5353
...
每一行就是一个包的概要。你想想看,如果配合过滤条件,比如只抓HTTP流量,那分析起来就高效多了。
4.3.2 使用过滤条件
Scapy支持BPF(Berkeley Packet Filter)语法,和tcpdump一模一样:
# 只抓取HTTP请求(80端口)
pkts = sniff(filter="tcp port 80", count=20)
# 只抓取特定IP的流量
pkts = sniff(filter="host 192.168.1.1", count=10)
# 抓取DNS查询
pkts = sniff(filter="udp port 53", count=5)
经验之谈:我在排查网络延迟问题时,经常用filter="icmp"只抓Ping包,然后分析RTT(往返时间)。有一次发现某个服务器Ping值忽高忽低,最后定位到是网卡驱动问题。如果没有过滤,在成千上万个包里找ICMP包,那真是大海捞针。
4.3.3 解析数据包内容
抓到的包怎么读?Scapy提供了多种方式:
# 显示包的详细信息(类似Wireshark的Packet Details)
pkts[0].show()
# 访问特定字段
pkts[0][IP].src # 源IP
pkts[0][IP].dst # 目的IP
pkts[0][TCP].sport # 源端口
pkts[0][TCP].dport # 目的端口
pkts[0][TCP].payload # 应用层数据
举个例子,假设你想提取HTTP请求中的URL:
def extract_http_url(pkt):
if pkt.haslayer(TCP) and pkt.haslayer(Raw):
payload = pkt[Raw].load.decode(errors='ignore')
if 'GET' in payload or 'POST' in payload:
lines = payload.split('\r\n')
print(lines[0]) # 第一行就是请求行,比如 GET /index.html HTTP/1.1
# 实时嗅探并解析
sniff(filter="tcp port 80", prn=extract_http_url, count=10)
这里prn参数指定了回调函数,每抓到一个包就自动调用。说白了,这就是实时分析。我写过一个脚本,用这个方式监控公司内网的异常HTTP请求,发现过几次挖矿病毒的通信流量。
4.4 知识体系总览
为了让你更直观地理解本章内容,我画了一张图,把Scapy的核心功能串起来:
这张图把本章的知识点串成了三条线:左边是构造与发送,右边是嗅探与解析,底部是应用场景。你想想看,掌握了这三块,基本上就能用Scapy解决大部分网络数据包的问题了。
4.5 实战小技巧
最后,分享几个我平时常用的技巧:
- 保存抓包结果:
wrpcap("output.pcap", pkts),这样就能用Wireshark打开分析了。 - 读取pcap文件:
pkts = rdpcap("input.pcap"),离线分析必备。 - 查看包长度:
len(pkt),快速判断是不是大包。 - 合并多个包:
pkts1 + pkts2,Scapy的包列表支持加法操作。
注意:在Windows上使用Scapy嗅探时,需要以管理员权限运行Python。我曾经忘了这茬,脚本跑起来一点反应都没有,还以为是代码写错了。
好了,关于Scapy的安装、构造、发送、嗅探和解析,就聊到这儿。说白了,这东西就是个网络包的“乐高”,你只要理解了协议栈的分层思想,剩下的就是拼积木的事。多动手试试,你会发现网络世界其实没那么神秘。