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 核心功能 构造数据包 IP/TCP/UDP/ICMP send() / sr() / sr1() 二层发送 sendp() 嗅探数据包 sniff(count=N) BPF过滤(filter="") 回调函数 prn=func 应用场景:网络诊断 / 安全测试 / 流量分析

这张图把本章的知识点串成了三条线:左边是构造与发送,右边是嗅探与解析,底部是应用场景。你想想看,掌握了这三块,基本上就能用Scapy解决大部分网络数据包的问题了。

4.5 实战小技巧

最后,分享几个我平时常用的技巧:

  • 保存抓包结果:wrpcap("output.pcap", pkts),这样就能用Wireshark打开分析了。
  • 读取pcap文件:pkts = rdpcap("input.pcap"),离线分析必备。
  • 查看包长度:len(pkt),快速判断是不是大包。
  • 合并多个包:pkts1 + pkts2,Scapy的包列表支持加法操作。

注意:在Windows上使用Scapy嗅探时,需要以管理员权限运行Python。我曾经忘了这茬,脚本跑起来一点反应都没有,还以为是代码写错了。

好了,关于Scapy的安装、构造、发送、嗅探和解析,就聊到这儿。说白了,这东西就是个网络包的“乐高”,你只要理解了协议栈的分层思想,剩下的就是拼积木的事。多动手试试,你会发现网络世界其实没那么神秘。

专注资料整理