讲师中心 微信公众号
AI工具推荐 视频效率加速

pcap-analysis

Polar Sponsor
爱发电 赞助
.NET 9.0

提供使用 Python 分析网络抓包文件(PCAP)并计算网络统计量的指导,包含经过测试的工具函数。

PCAP 网络分析指南

功能概述

PCAP 网络分析指南是一项面向实际任务的技能,主要用于此技能为分析网络包抓取( PCAP 文件) 和使用 Python 计算网络统计提供了指导;QQ 快速启动: 使用 Helper 模块。

核心要点

  • 它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
  • 使用时应结合输入条件选择合适的执行方式,核对必要参数、依赖环境与输出内容,并按原始要求处理异常情况。
  • 该技能适合需要稳定复用相关能力的场景,可作为自动化工作流的一部分,也便于后续检查、调整和扩展。

使用与执行

从功能定位来看,该技能强调把分散的操作要求整理成清晰、可复用的处理流程,使用户能够围绕既定目标快速准备输入、选择执行方式并获得结构化结果。实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;

结果检查与注意事项

若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。

PCAP 网络分析指南

本技能提供对网络数据包捕获文件(PCAP 文件)进行分析及使用 Python 计算网络统计指标的指导。

快速入门:使用辅助模块

本目录下提供一个工具模块(pcap_utils.py),其中包含经过**充分测试、逻辑正确**的常用分析函数实现。该模块提供若干实用函数,用于统计中间结果,帮助你更快得出关键结论。请直接调用这些函数,而非自行重新实现相同逻辑——因其已正确处理各类边界情况。

# 推荐做法:导入并直接使用辅助函数
import sys
sys.path.insert(0, '/root/skills/pcap-analysis')  # 将技能目录加入 Python 路径
from pcap_utils import (
    load_packets, split_by_protocol, graph_metrics,
    detect_port_scan, detect_dos_pattern, detect_beaconing,
    port_counters, ip_counters, iat_stats, flow_metrics,
    packets_per_minute_stats, producer_consumer_counts, shannon_entropy
)

packets = load_packets('/root/packets.pcap')
parts = split_by_protocol(packets)

# 图论/拓扑指标(入度/出度统计的是 UNIQUE IP 数量,而非数据包数量!)
g = graph_metrics(parts['ip'])
print(g['max_indegree'], g['max_outdegree'])

# 检测函数采用严格阈值,所有条件必须同时满足才返回 True
print(detect_port_scan(parts['tcp']))      # 返回 True/False
print(detect_dos_pattern(ppm_avg, ppm_max)) # 返回 True/False
print(detect_beaconing(iat_cv))             # 返回 True/False

辅助函数使用特定的检测阈值(详见下文说明),这些阈值经过校准以确保结果准确。若自行实现逻辑并采用不同阈值,极可能导致错误结论。

概述

网络流量分析涉及读取数据包捕获文件,并计算各类统计指标:

  • 基础计数(数据包数量、字节数、协议分布)
  • 分布分析(熵值)
  • 图论/拓扑结构指标
  • 时间序列模式
  • 流级别分析

使用 Scapy 读取 PCAP 文件

Scapy 是 Python 中标准的数据包操作库:

from scapy.all import rdpcap, IP, TCP, UDP, ICMP, ARP

# 加载全部数据包
packets = rdpcap('packets.pcap')

# 按协议过滤
ip_packets = [p for p in packets if IP in p]
tcp_packets = [p for p in packets if TCP in p]
udp_packets = [p for p in packets if UDP in p]

基础统计指标

数据包与字节数统计

total_packets = len(packets)
total_bytes = sum(len(p) for p in packets)
avg_packet_size = total_bytes / total_packets

协议分布统计

tcp_count = len([p for p in packets if TCP in p])
udp_count = len([p for p in packets if UDP in p])
icmp_count = len([p for p in packets if ICMP in p])
arp_count = len([p for p in packets if ARP in p])

熵值计算

香农熵(Shannon entropy)用于衡量分布的“随机性”:

import math
from collections import Counter

def shannon_entropy(counter):
    """
    计算香农熵:H(X) = -Σ p(x) log₂(p(x))

    低熵值:流量集中在少数目标上(正常行为)
    高熵值:流量分散在大量目标上(扫描行为)
    """
    total = sum(counter.values())
    if total == 0:
        return 0.0

    entropy = 0.0
    for count in counter.values():
        if count > 0:
            p = count / total
            entropy -= p * math.log2(p)
    return entropy

# 示例:目的端口熵值
dst_ports = Counter()
for pkt in tcp_packets:
    dst_ports[pkt[TCP].dport] += 1
for pkt in udp_packets:
    if IP in pkt:
        dst_ports[pkt[UDP].dport] += 1

port_entropy = shannon_entropy(dst_ports)

图论/拓扑结构指标

重要提示:务必使用 pcap_utils.py 中的 graph_metrics() 函数获取正确结果!

将网络建模为有向图,节点为 IP 地址,边为通信关系对(src → dst)。

关键要点:度(degree)指与之通信的 UNIQUE IP 数量,而非数据包总数!

  • max_indegree = 任一目的地址所接收数据包的唯一源 IP 数量的最大值
  • max_outdegree = 任一源地址所发送数据包的唯一目的 IP 数量的最大值

常见错误:统计数据包总数而非唯一 IP 数量。对于含 38 个节点的网络,max_indegree 最大值应为 37,而非数千!

# 推荐做法:使用辅助函数
from pcap_utils import graph_metrics
g = graph_metrics(ip_packets)
print(g['max_indegree'])   # 唯一 IP 数量,通常 < 50
print(g['max_outdegree'])  # 唯一 IP 数量,通常 < 50

# 或手动实现时:
from collections import defaultdict

# 构建图:节点 = IP,边 = (src, dst) 对
edges = set()
indegree = defaultdict(set)   # dst -> 向该 dst 发送数据包的源 IP 集合
outdegree = defaultdict(set)  # src -> src 所发送数据包的目的 IP 集合

for pkt in ip_packets:
    src, dst = pkt[IP].src, pkt[IP].dst
    edges.add((src, dst))
    indegree[dst].add(src)      # dst 收到来自 src 的数据包
    outdegree[src].add(dst)     # src 向 dst 发送数据包

all_nodes = set(indegree.keys()) | set(outdegree.keys())
num_nodes = len(all_nodes)
num_edges = len(edges)

# 网络密度 = 实际边数 / 可能边数
# 有向图中可能边数 = n × (n−1)
network_density = num_edges / (num_nodes * (num_nodes - 1))

# 度中心性 —— 统计 UNIQUE IP 数量,非数据包数量!
# 使用 len(set) 获取唯一 IP 数量
max_indegree = max(len(v) for v in indegree.values())    # len(set) = 唯一 IP 数量
max_outdegree = max(len(v) for v in outdegree.values())  # len(set) = 唯一 IP 数量

时间维度指标

数据包到达间隔时间(IAT)

# 获取按时间戳排序的列表
timestamps = sorted(float(p.time) for p in packets)

# 计算到达间隔时间
iats = [timestamps[i+1] - timestamps[i] for i in range(len(timestamps)-1)]

iat_mean = sum(iats) / len(iats)
iat_variance = sum((x - iat_mean)**2 for x in iats) / len(iats)
iat_std = math.sqrt(iat_variance)

# 变异系数 CV = std / mean
# CV 较低(<0.5):规律性强/机器人式流量(可疑)
# CV 较高(>1.0):突发性/人类操作流量(正常)
iat_cv = iat_std / iat_mean if iat_mean > 0 else 0

生产者/消费者比(PCR)

# PCR = (bytes_sent - bytes_recv) / (bytes_sent + bytes_recv)
# 正值:生产者/服务器;负值:消费者/客户端
bytes_sent = defaultdict(int)
bytes_recv = defaultdict(int)

for pkt in ip_packets:
    size = len(pkt)
    bytes_sent[pkt[IP].src] += size
    bytes_recv[pkt[IP].dst] += size

num_producers = 0
num_consumers = 0
for ip in all_nodes:
    sent = bytes_sent.get(ip, 0)
    recv = bytes_recv.get(ip, 0)
    total = sent + recv
    if total > 0:
        pcr = (sent - recv) / total
        if pcr > 0.2:
            num_producers += 1
        elif pcr < -0.2:
            num_consumers += 1

流分析

一条流定义为五元组:(src_ip, dst_ip, src_port, dst_port, protocol)

重要提示:仅统计同时包含 IP 层和传输层的数据包所构成的流!

# 收集唯一流
flows = set()
for pkt in tcp_packets:
    if IP in pkt:  # 必须检查 IP 层存在
        flow = (pkt[IP].src, pkt[IP].dst, pkt[TCP].sport, pkt[TCP].dport, "TCP")
        flows.add(flow)

for pkt in udp_packets:
    if IP in pkt:  # 必须检查 IP 层存在
        flow = (pkt[IP].src, pkt[IP].dst, pkt[UDP].sport, pkt[UDP].dport, "UDP")
        flows.add(flow)

unique_flows = len(flows)
tcp_flows = len([f for f in flows if f[4] == "TCP"])
udp_flows = len([f for f in flows if f[4] == "UDP"])

# 双向流:统计正向与反向均存在的流对数量
# 即存在 A→B 且 B→A(端口相同)的流对
bidirectional_count = 0
for flow in flows:
    src_ip, dst_ip, src_port, dst_port, proto = flow
    reverse = (dst_ip, src_ip, dst_port, src_port, proto)
    if reverse in flows:
        bidirectional_count += 1

# 每个双向流对被统计两次(A→B 和 B→A),故需除以 2
bidirectional_flows = bidirectional_count // 2

时间序列分析

按时间区间对数据包分桶:

from collections import defaultdict

timestamps = [float(p.time) for p in packets]
start_time = min(timestamps)

# 按分钟分桶
minute_buckets = defaultdict(int)
for ts in timestamps:
    minute = int((ts - start_time) / 60)
    minute_buckets[minute] += 1

duration_seconds = max(timestamps) - start_time
packets_per_min = list(minute_buckets.values())
ppm_avg = sum(packets_per_min) / len(packets_per_min)
ppm_max = max(packets_per_min)
ppm_min = min(packets_per_min)

写入 CSV 结果文件

import csv

results = {
    "total_packets": total_packets,
    "protocol_tcp": tcp_count,
    # ... 其他指标
}

# 读取模板并填充数值
with open('network_stats.csv', 'r') as f:
    reader = csv.DictReader(f)
    rows = list(reader)

with open('network_stats.csv', 'w', newline='') as f:
    writer = csv.DictWriter(f, fieldnames=['metric', 'value'])
    writer.writeheader()
    for row in rows:
        metric = row['metric']
        if metric.startswith('#'):
            writer.writerow(row)  # 保留注释行
        elif metric in results:
            writer.writerow({'metric': metric, 'value': results[metric]})

流量分析问题

完成各项指标计算后,你可能需要回答有关该流量的具体分析问题。

主导协议识别

找出数据包数量最多的协议:

protocol_counts = {
    "tcp": tcp_count,
    "udp": udp_count,
    "icmp": icmp_count,
    "arp": arp_count,
}
dominant_protocol = max(protocol_counts, key=protocol_counts.get)

端口扫描检测(鲁棒方法)

重要提示:请使用 pcap_utils.py 中的 detect_port_scan() 函数以获得准确结果!

基于简单阈值的检测方法不具备鲁棒性。原因如下:

  • 合法用户可能在较长时间内访问大量端口(时间不敏感)
  • 分布式扫描由多个源发起,每个源仅探测少量端口
  • 半开放扫描(仅发送 SYN)可能未完成三次握手

鲁棒检测要求同时满足以下三项信号:

  1. 端口熵值 > 6.0:扫描器均匀访问大量端口(高熵值)。正常流量反复访问相同端口(低熵值,约 4–5 bits)。
  2. 仅 SYN 包比例 > 0.7:半开放扫描仅发送 SYN 而不完成握手(占比 >70%)
  3. 唯一端口数 > 100:必须具备足够多的唯一端口才构成有意义的扫描行为

若任意一项条件未满足,则判定为无端口扫描行为!

# 推荐做法:使用辅助函数
from pcap_utils import detect_port_scan
has_port_scan = detect_port_scan(tcp_packets)  # 返回 True/False

# 或手动实现时,必须同时满足全部三项条件:
from collections import Counter, defaultdict

src_port_counts = defaultdict(Counter)  # src -> 目的端口计数器
src_syn_only = defaultdict(int)         # src -> 仅 SYN 数据包计数
src_total_tcp = defaultdict(int)        # src -> TCP 数据包总数

for pkt in tcp_packets:
    if IP in pkt and TCP in pkt:
        src = pkt[IP].src
        dst_port = pkt[TCP].dport
        flags = pkt[TCP].flags

        src_port_counts[src][dst_port] += 1
        src_total_tcp[src] += 1

        # 仅 SYN:SYN 标志位(0x02)置位,且 ACK 标志位(0x10)未置位
        if flags & 0x02 and not (flags & 0x10):
            src_syn_only[src] += 1

def calc_port_entropy(port_counter):
    """计算端口分布的香农熵值。"""
    total = sum(port_counter.values())
    if total == 0:
        return 0.0
    entropy = 0.0
    for count in port_counter.values():
        if count > 0:
            p = count / total
            entropy -= p * math.log2(p)
    return entropy

has_port_scan = False
for src in src_port_counts:
    total_pkts = src_total_tcp[src]
    if total_pkts < 50:  # 忽略低流量源
        continue

    port_entropy = calc_port_entropy(src_port_counts[src])
    syn_only_ratio = src_syn_only[src] / total_pkts
    unique_ports = len(src_port_counts[src])

    # 扫描特征:必须同时满足以下三项条件!
    # - 高熵值(端口分布均匀,非重复访问固定端口)
    # - 高仅 SYN 比例(半开放连接,未完成握手)
    # - 大量唯一端口(实际探测多种服务)
    if port_entropy > 6.0 and syn_only_ratio > 0.7 and unique_ports > 100:
        has_port_scan = True
        break

DoS 模式检测

重要提示:请使用 pcap_utils.py 中的 detect_dos_pattern() 函数以获得准确结果!

DoS 攻击会导致极端的流量激增。判定阈值为>20 倍于平均速率。

最大/平均比值必须严格大于 20 才可判定为 DoS。5 倍、10 倍甚至 15 倍均为正常流量波动,不可视为 DoS!

# 推荐做法:使用辅助函数
from pcap_utils import detect_dos_pattern
has_dos = detect_dos_pattern(packets_per_minute_avg, packets_per_minute_max)

# 或手动实现时:
ppm_ratio = packets_per_minute_max / packets_per_minute_avg
# 仅当比值 > 20 时才表示 DoS!较低比值属于正常流量波动。
has_dos_pattern = ppm_ratio > 20

C2 信标行为检测

命令与控制(C2)信标行为表现为规律、周期性的通信模式。 可通过低到达间隔时间变异系数(CV < 0.5)进行检测:

# CV = std / mean
# CV 较低(<0.5):规律性强/机器人式流量(可疑信标行为)
# CV 较高(>1.0):突发性/人类操作流量(正常)
has_beaconing = iat_cv < 0.5

良性流量评估

当且仅当以下全部条件为假时,流量才可判定为良性:

  • 未检测到端口扫描(使用 detect_port_scan())
  • 未检测到 DoS 模式(使用 detect_dos_pattern())
  • 未检测到信标行为(使用 detect_beaconing())

重要提示:请使用具备正确阈值的检测辅助函数。若自行实现检测逻辑并采用错误阈值,将导致错误结论!

# 推荐做法:使用辅助函数进行检测
from pcap_utils import detect_port_scan, detect_dos_pattern, detect_beaconing

has_port_scan = detect_port_scan(tcp_packets)
has_dos_pattern = detect_dos_pattern(ppm_avg, ppm_max)
has_beaconing = detect_beaconing(iat_cv)

# 仅当全部检测结果均为 False 时,流量才为良性
is_benign = (
    not has_port_scan and
    not has_dos_pattern and
    not has_beaconing
)

常见问题

大型 PCAP 文件的内存占用

对于大型捕获文件,建议分块处理或应用具体过滤条件:

from scapy.all import PcapReader

# 流式读取大型文件
with PcapReader('large.pcap') as pcap:
    for pkt in pcap:
        # 逐个处理数据包
        pass

非 IP 数据包

部分数据包(如 ARP 等)不含 IP 层。务必始终检查:

for pkt in packets:
    if IP in pkt:
        src = pkt[IP].src
        # ... 处理逻辑

无 IP 层的 UDP 数据包

链路层协议可能存在不含 IP 层的 UDP 数据包:

for pkt in udp_packets:
    if IP in pkt:  # 安全检查
        # ... 处理逻辑
目录

热门AI工具

更多
DeepSeek

DeepSeek是一款面向对话、写作、编程和推理场景的AI大模型工具。

超级麦吉

一款通过数字员工协作完成调研、数据分析与文档制作的AI办公平台。

豆包大模型

豆包大模型是一款由字节跳动推出的企业级大语言模型服务平台。

音述AI
音述AI Hot

一款AI音频处理工具,主要用于音述AI是一个以“用声音述说故事”为核心的 AI 音乐创作与声音分享社区,适合需要提升相关任务效率的用户。

AionClaw
AionClaw Hot

AionClaw是一款面向办公、创作和编程任务的AI桌面智能体。

咔片AIPPT

一款在线AI演示文稿制作工具,可根据主题和内容需求辅助生成PPT结构与页面,提高演示材料制作效率。

WorkBuddy

一款AI办公效率工具,主要用于腾讯云推出的AI原生桌面智能体工作台,适合需要提升相关任务效率的用户。

创客贴AI

创客贴AI是一款AI图像与设计工具,AI辅助的智能在线设计工具。

Lovart
Lovart Hot

一款面向视觉设计创作的AI设计平台,可通过智能体和画布工作流辅助制作海报、Logo、网页、PPT及其他视觉内容。

相关专题

更多
Vite 项目如何打包和部署
Vite 项目如何打包和部署

Vite项目打包部署专题汇集生产构建、产物预览、输出目录、资源路径、Nginx与GitHub Pages部署及常见白屏和路由404问题的已审核文章,帮助读者完成上线流程。

0

2026.10.28

Vite 如何搭配 Vue.js
Vite 如何搭配 Vue.js

Vite搭配Vue.js专题汇集创建Vue 3项目、配置开发环境、路径别名、Vue插件、代理、多环境构建与调试的已审核文章,帮助读者完成从初始化到日常开发的配置。

0

2026.10.28

Vite 项目目录怎么看
Vite 项目目录怎么看

Vite项目目录专题汇集入口文件、src源码、public静态资源、路径别名、项目根目录和构建输出目录相关的已审核文章,帮助读者理解各文件夹的用途与引用方式。

0

2026.10.28

Gradle插件开发入门教程
Gradle插件开发入门教程

本专题介绍Gradle插件开发的基本流程,涵盖插件类编写、自定义任务注册、扩展参数设计和插件应用方法,帮助你理解插件如何组织构建逻辑,减少多个项目之间的重复配置。

0

2026.10.22

Gradle Wrapper配置教程
Gradle Wrapper配置教程

本专题介绍Gradle Wrapper的基本作用,涵盖文件组成、生成方法、版本配置和任务调用,帮助你理解项目如何使用指定的Gradle版本,减少不同开发环境带来的构建差异。

0

2026.10.22

Golangci-lint检查器使用教程
Golangci-lint检查器使用教程

本专题整理Golangci-lint常用Linters的用途与配置方法,覆盖错误处理、无效代码、安全、复杂度、命名和依赖检查,帮助项目合理选规则。

0

2026.10.22

Gradle怎么构建Java项目
Gradle怎么构建Java项目

本专题介绍Gradle Java项目构建方法,涵盖Java插件配置、依赖声明、源码编译、测试执行和打包检查,帮助你理解各阶段的任务关系,逐步完成项目构建。

0

2026.10.22

PHP时间戳漏洞修复教程
PHP时间戳漏洞修复教程

本专题汇总PHP常见时间戳漏洞,包括2038年溢出、时区漂移、时间戳伪造、重放攻击、时间盲注与日志审计失效等,并给出升级64位环境、使用 DateTimeImmutable、统一UTC、严格超时校验、预处理绑定、hash_equals 比对等修复方案,帮助开发者快速排查和加固时间相关代码。

0

2026.10.22

Golangci-lint配置文件与规则设置
Golangci-lint配置文件与规则设置

本专题聚焦Golangci-lint YAML配置文件,讲清运行参数、规则启停、目录排除、问题过滤及严重级别设置,便于团队统一检查标准。

0

2026.10.22

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
热门推荐
/
最新课程
关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn