4、网络流量捕获基础:使用Scapy捕获网络包、解析IP和MAC地址、过滤IoT设备流量
做IoT安全,第一件事是什么?
我个人觉得,不是急着写规则,也不是调算法。你得先能“看见”流量。看不见攻击者,你怎么防?
这一章,我们就来搞定这件事。用Scapy这个Python库,把网络包抓下来,看懂它,然后专门挑出IoT设备的流量。
4.1 为什么选Scapy?
市面上抓包工具不少,Wireshark、tcpdump都很强。但做自动化防御,你不能每次都打开图形界面点鼠标。你需要一个能嵌入到Python脚本里的工具。
Scapy就是干这个的。它不仅能抓包,还能解析、构造、发送网络包。说白了,它就是网络世界的瑞士军刀。
我在项目中遇到过好几次,现场只有命令行,没有图形界面。这时候Scapy就是救命稻草。写个脚本,跑起来,流量数据直接进数据库,省事得很。
4.2 安装与基础环境
安装很简单,一行命令的事:
pip install scapy
但要注意,在Linux系统上,抓包需要root权限。Windows下也需要管理员权限。否则你只能看到自己的包,看不到别人的。
4.3 第一个抓包脚本
我们先写一个最简单的,抓几个包看看:
from scapy.all import sniff
# 抓取5个包,不存储内容,只打印摘要
packets = sniff(count=5)
packets.summary()
运行后,你会看到类似这样的输出:
Ether / IP / TCP 192.168.1.100:54321 > 8.8.8.8:80
Ether / IP / UDP 192.168.1.50:12345 > 239.255.255.250:1900
...
每一行就是一个网络包。从左到右,依次是:链路层(Ether)、网络层(IP)、传输层(TCP/UDP),然后是源地址和目标地址。
嗯,这里要注意,默认抓包会抓所有接口。如果你只想抓某个网卡,可以指定 iface 参数:
packets = sniff(iface="eth0", count=5)
4.4 解析IP和MAC地址
光看摘要不够。我们需要深入到包的内部,把IP和MAC地址抠出来。
Scapy的包结构是分层的。每个包就像一个洋葱,你可以一层层剥开:
from scapy.all import sniff
def packet_callback(packet):
# 检查是否有IP层
if packet.haslayer('IP'):
src_ip = packet['IP'].src
dst_ip = packet['IP'].dst
print(f"IP: {src_ip} -> {dst_ip}")
# 检查是否有Ether层(链路层)
if packet.haslayer('Ether'):
src_mac = packet['Ether'].src
dst_mac = packet['Ether'].dst
print(f"MAC: {src_mac} -> {dst_mac}")
# 抓包,每抓到1个就调用回调函数
sniff(prn=packet_callback, count=10)
运行后,你会看到类似:
MAC: 00:1a:2b:3c:4d:5e -> ff:ff:ff:ff:ff:ff
IP: 192.168.1.100 -> 192.168.1.1
MAC: 00:1a:2b:3c:4d:5f -> 00:1a:2b:3c:4d:5e
IP: 192.168.1.50 -> 8.8.8.8
你想想看,有了这些信息,你就能知道:哪个设备(MAC地址)在和谁(IP地址)说话。
4.5 过滤IoT设备流量
现实网络里,流量很杂。有电脑的、手机的、服务器的。我们只关心IoT设备。
怎么过滤?有两种思路:
- 按MAC地址过滤: IoT设备的MAC地址通常是固定的。你可以先收集设备MAC,然后只抓这些MAC的包。
- 按协议特征过滤: 很多IoT设备使用MQTT、CoAP、UPnP等协议。你可以根据端口或协议类型来过滤。
Scapy支持BPF(Berkeley Packet Filter)语法,和tcpdump一样。比如:
# 只抓MAC地址为 00:1a:2b:3c:4d:5e 的设备的流量
packets = sniff(filter="ether host 00:1a:2b:3c:4d:5e", count=10)
# 只抓MQTT协议(默认端口1883)的流量
packets = sniff(filter="port 1883", count=10)
# 组合过滤:抓某个设备发往MQTT服务器的流量
packets = sniff(filter="ether host 00:1a:2b:3c:4d:5e and port 1883", count=10)
我个人习惯,先不加过滤抓一小段时间,看看网络里都有什么设备。然后根据观察结果,再写精确的过滤规则。
4.6 实战:捕获并识别IoT设备
我们来写一个完整的脚本。它会持续抓包,自动识别出IoT设备,并把流量保存下来:
from scapy.all import sniff, wrpcap
from collections import defaultdict
# 已知的IoT设备MAC地址列表
iot_macs = [
"00:1a:2b:3c:4d:5e", # 智能灯泡
"00:1a:2b:3c:4d:5f", # 智能插座
"00:1a:2b:3c:4d:60", # 摄像头
]
# 用于存储捕获的包
iot_packets = []
def is_iot_device(mac):
"""判断MAC地址是否属于IoT设备"""
return mac.upper() in [m.upper() for m in iot_macs]
def packet_handler(packet):
"""处理每个捕获的包"""
if packet.haslayer('Ether'):
src_mac = packet['Ether'].src
dst_mac = packet['Ether'].dst
# 如果源或目标是IoT设备,就保存这个包
if is_iot_device(src_mac) or is_iot_device(dst_mac):
iot_packets.append(packet)
print(f"捕获到IoT流量: {src_mac} -> {dst_mac}")
# 如果抓够了,就停止
if len(iot_packets) >= 100:
return True # 返回True会停止sniff
# 开始抓包,直到抓到100个IoT包
sniff(prn=packet_handler, store=False)
# 保存到文件
wrpcap("iot_traffic.pcap", iot_packets)
print(f"已保存 {len(iot_packets)} 个IoT数据包到 iot_traffic.pcap")
这个脚本会一直运行,直到抓到100个IoT设备的包。然后自动保存成pcap文件。你可以用Wireshark打开这个文件,慢慢分析。
4.7 本章知识体系
下面这张图,帮你理清本章的核心逻辑:
4.8 避坑指南
做流量捕获,有几个坑我踩过,分享给你:
- 网卡混杂模式: 默认情况下,网卡只收发给自己的包。要抓别人的包,得开启混杂模式。Scapy的
sniff()默认会帮你开,但有些虚拟网卡不支持。 - 性能问题: 流量大的时候,回调函数里别做复杂计算。我曾经在回调里写数据库,结果丢包严重。后来改成先存内存,再批量写入。
- 编码问题: 有些IoT设备发送的数据不是标准ASCII。解析payload时,记得用
.hex()或.raw()查看原始字节,别直接转字符串。
好了,这一章的内容就到这里。你现在应该能自己写脚本,捕获网络包,解析出IP和MAC,并且只过滤出IoT设备的流量了。这是后续所有限速策略的基础。数据在手,心里不慌。