4、网络流量捕获基础:使用Scapy捕获网络包、解析IP和MAC地址、过滤IoT设备流量

做IoT安全,第一件事是什么?

我个人觉得,不是急着写规则,也不是调算法。你得先能“看见”流量。看不见攻击者,你怎么防?

这一章,我们就来搞定这件事。用Scapy这个Python库,把网络包抓下来,看懂它,然后专门挑出IoT设备的流量。

4.1 为什么选Scapy?

市面上抓包工具不少,Wireshark、tcpdump都很强。但做自动化防御,你不能每次都打开图形界面点鼠标。你需要一个能嵌入到Python脚本里的工具。

Scapy就是干这个的。它不仅能抓包,还能解析、构造、发送网络包。说白了,它就是网络世界的瑞士军刀。

我在项目中遇到过好几次,现场只有命令行,没有图形界面。这时候Scapy就是救命稻草。写个脚本,跑起来,流量数据直接进数据库,省事得很。

核心优势: Scapy 让你用 Python 直接操作网络包,从捕获到分析,一条龙搞定。

4.2 安装与基础环境

安装很简单,一行命令的事:

pip install scapy

但要注意,在Linux系统上,抓包需要root权限。Windows下也需要管理员权限。否则你只能看到自己的包,看不到别人的。

权限警告: 抓包必须用 root 或管理员权限运行脚本。否则 Scapy 会报错,或者抓不到任何流量。

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地址)说话。

小技巧: 我曾经调试一个智能灯泡,发现它总是向一个奇怪的IP发数据。用Scapy一查,发现MAC地址是某个厂商的,但IP归属地不对。后来确认是被植入了后门。所以,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 本章知识体系

下面这张图,帮你理清本章的核心逻辑:

网络流量捕获与IoT过滤核心流程 1. 捕获原始包 2. 解析IP与MAC 3. 过滤IoT流量 4. 保存为pcap文件 关键点 • 使用 sniff() 捕获 • packet['IP'].src 获取IP • packet['Ether'].src 获取MAC • filter参数支持BPF语法 • wrpcap() 保存文件 • 注意权限问题 • 设置抓包上限防内存溢出 常用过滤方式 1. 按MAC过滤 ether host MAC 2. 按端口过滤 port 1883 3. 按协议过滤 udp / tcp 4. 组合过滤 and / or 连接

4.8 避坑指南

做流量捕获,有几个坑我踩过,分享给你:

  • 网卡混杂模式: 默认情况下,网卡只收发给自己的包。要抓别人的包,得开启混杂模式。Scapy的 sniff() 默认会帮你开,但有些虚拟网卡不支持。
  • 性能问题: 流量大的时候,回调函数里别做复杂计算。我曾经在回调里写数据库,结果丢包严重。后来改成先存内存,再批量写入。
  • 编码问题: 有些IoT设备发送的数据不是标准ASCII。解析payload时,记得用 .hex() 或 .raw() 查看原始字节,别直接转字符串。
我的经验: 刚开始做流量分析,别想着一步到位。先抓10个包,看看结构。再抓100个,找找规律。慢慢来,比一次性写个大脚本靠谱得多。

好了,这一章的内容就到这里。你现在应该能自己写脚本,捕获网络包,解析出IP和MAC,并且只过滤出IoT设备的流量了。这是后续所有限速策略的基础。数据在手,心里不慌。