ashishsaud2025/pcap-insight

GitHub: ashishsaud2025/pcap-insight

一个基于Python的命令行PCAP分析工具,用于将抓包文件转换为可读的安全与流量统计报告。

Stars: 0 | Forks: 0

# PCAP ANALYZER CLI 一个命令行 PCAP 分析器,可将 `.pcap` / `.pcapng` 捕获文件转换为 可读的安全与流量报告: - **摘要**:数据包数量、捕获时长、总字节数、平均数据包大小 - **协议分布**:TCP/UDP/ICMP/ARP/DNS/TLS/HTTP 的数量和百分比 - **活跃主机(Top talkers)**:按数据包数量*和*字节量统计的前 10 个源到目标的 IP 对 - **高频端口(Top ports)**:最常用的目标端口及尽力而为的服务名称匹配 - **ASN/组织信息补充**:活跃主机行会标注其所属的组织/ASN(通过 MaxMind 免费的 GeoLite2-ASN 数据库进行离线查询;使用 `--no-enrich` 可禁用) - **可疑模式**(仅作为标记,不进行拦截): - 通过 HTTP 传输的明文凭据 - 大量未响应的 SYN 突发(可能是 SYN 扫描) - 高熵/超长的 DNS 子域名(可能是隧道传输或 C2 信标) - 在 ARP 回复中,同一个 IP 被多个 MAC 地址声明(可能是 ARP 欺骗) - **`--export json`**:生成机器可读的输出,便于通过管道传递给其他工具 - **`--filter`**:BPF 风格的过滤器,用于将分析范围缩小到特定流量 它使用 [Scapy](https://scapy.net/) 来解析捕获文件, 使用 [Rich](https://github.com/Textualize/rich) 来渲染表格,并使用 [geoip2](https://geoip2.readthedocs.io/) 结合 MaxMind 免费的 GeoLite2-ASN 数据库进行可选的离线组织/ASN 归属查询。其余功能均由 标准库 Python(argparse、`socket.getservbyport`、`ipaddress` 等)实现。 ## 安装说明 要求 **Python 3.10+**。 ### 1. 克隆仓库 ``` git clone https://github.com/ashishsaud2025/pcap-insight.git cd pcap-insight ``` ### 2. 创建并激活虚拟环境 虚拟环境可以将此项目的依赖项与您的系统 Python 和其他项目隔离开来。 **Windows (PowerShell):** ``` python -m venv venv .\venv\Scripts\Activate.ps1 ``` **Windows (cmd.exe):** ``` python -m venv venv venv\Scripts\activate.bat ``` **macOS / Linux:** ``` python3 -m venv venv source venv/bin/activate ``` 激活后,您的命令行提示符将显示 `(venv)` 前缀。下面每一次 `pip install` 以及 `pcap-insight` 的运行都将在这个隔离的环境中进行。 ### 3. 安装依赖项 您有两个等效的选择: **选项 A:通过 `requirements.txt` 安装:** ``` pip install -r requirements.txt ``` **选项 B:直接安装该包(推荐):** ``` python -m pip install -e . ``` 此操作将安装 `pcap-insight` 命令行入口,以及 `pyproject.toml` 中声明的 `scapy`、`rich` 和 `geoip2`。`-e`(可编辑)标志意味着 任何本地代码的更改都会立即生效,无需重新安装。 用于开发(为测试套件添加 `pytest`): ``` python -m pip install -e ".[dev]" ``` ### 4. 验证安装 ``` pcap-insight --version pcap-insight --demo ``` 如果这两个命令都能正常运行,说明您已正确设置。只要*激活了此虚拟环境*,`pcap-insight` 现在就可以 在任意目录下使用——每次打开新的终端会话时,请使用 上面的 `Activate.ps1` / `activate.bat` / `source ... activate` 命令重新激活它。 ### 可选:组织/ASN 信息补充 (GeoLite2-ASN) 活跃主机表将为每个 IP 标注所属的组织/ASN。 该查询是**完全离线**的,并使用 MaxMind 免费的 **GeoLite2-ASN** 数据库,即在分析时不需要 API 密钥和网络访问。 要为公网 IP 启用真实的组织名称(而不是显示 `Unknown`): 1. 在 注册并下载 **GeoLite2-ASN** 数据库(`GeoLite2-ASN.mmdb`)。 2. 将其放置在以下任一位置(按顺序检查): - `/GeoLite2-ASN.mmdb` - `~/.pcap-insight/GeoLite2-ASN.mmdb` - `~/.local/share/GeoLite2-ASN.mmdb` - 或者将 `PCAP_INSIGHT_ASN_DB` 环境变量设置为其路径 私有/保留地址(RFC1918、loopback、link-local、multicast 等)会被 标记为 `Private`,并且永远不会去查询数据库。缺失或无法读取的 数据库,或未知的 IP,将被标记为 `Unknown`。结果将按 IP 缓存,有效 期为进程的生命周期,因此活跃主机信息补充只会为每个唯一的公网 IP 执行一次数据库读取。使用 `pcap-insight capture.pcap --no-enrich` 可以完全 跳过查询(适用于完全离线的环境或不需要此功能的脚本)。 程序显式处理了一种边缘情况:IPv4 映射的 IPv6 地址 (`::ffff:a.b.c.d`)在进行私有地址检查之前会被解码回其内嵌的 IPv4 地址,因为即使内嵌的 地址是公网地址,Python 也会将映射形式标记为 `reserved=True`。如果不进行解码,`::ffff:8.8.8.8` 将被 (错误地)视为私有地址,从而永远不会去查询数据库。6to4(`2002::/16`) 和 Teredo(`2001::/32`)范围会被标记为 `Private`,这是根据 Python 的标准库 分类,尽管它们可以内嵌公网 IPv4 地址——这是一个被默认接受的 标准库特性(参见 `pcap_insight/enrichment.py` 中的 `is_private()`)。 如果启用了信息补充但找不到或无法读取数据库,CLI 会向 **stderr** 打印一条警告(这样 JSON/管道输出将保持整洁),解释 公网 IP 将显示为 `Unknown`,并附带指向此部分的提示。 `--no-enrich` 会同时禁用查询和该警告。 ### Windows / Npcap 注意事项 只有在您想要*嗅探*实时流量时,Scapy 才需要 **Npcap** 驱动程序。 `pcap-insight` 仅*读取捕获文件*,因此不需要管理员权限或安装 Npcap。 ## 用法 ``` usage: pcap-insight [-h] [--demo] [--export {json}] [--filter FILTER] [--no-enrich] [--version] [capture] Analyze a .pcap/.pcapng capture: summary stats, protocol breakdown, top talkers/ports, and heuristic suspicious-pattern flags (credentials in plaintext HTTP, SYN scans, DNS tunneling candidates, ARP spoofing candidates). positional arguments: capture path to a .pcap or .pcapng file (omit with --demo) options: -h, --help show this help message and exit --demo write a synthetic demo capture to './demo.pcap' and analyze it --export {json} emit a structured JSON document instead of tables --filter FILTER BPF-style capture filter, e.g. 'tcp port 443' or 'host 10.0.0.5' --no-enrich disable ASN/organization enrichment for top-talker tables (default: on, using the GeoLite2-ASN database if present) --version show program's version number and exit ``` ### 快速演示(无需真实数据包) `--demo` 标志会生成一个小巧、完全合成的捕获文件(不产生互联网 流量),它会演练每一个分析部分,包括所有四个可疑 模式,并对其进行分析: ``` pcap-insight --demo ``` ### 分析您自己的捕获文件 ``` # 完整报告 pcap-insight capture.pcap # 缩小到一个 host pcap-insight capture.pcap --filter 'host 10.0.0.5' # 缩小到 HTTPS 并为 jq dump JSON pcap-insight capture.pcap --filter 'tcp port 443' --export json | jq .summary # 跳过 org/ASN 查询(离线环境、脚本、更快的运行) pcap-insight capture.pcap --no-enrich ``` ### 示例输出 `pcap-insight --demo` 会生成(检测到 Rich,因此如果使用非 Rich 终端,输出为纯文本;此处显示的列已截断): ``` Summary Metric Value Total packets 27 Capture duration 13.00 s Total bytes 1.2 KB Average packet size 45 B First packet (UTC) 2023-11-14 22:13:20.000000 UTC Last packet (UTC) 2023-11-14 22:13:33.000000 UTC Protocol breakdown Protocol Packets Percent TCP 18 66.7% ARP 3 11.1% DNS 2 7.4% TLS 2 7.4% HTTP 1 3.7% ICMP 1 3.7% Top talkers by packet count Source Source Org Destination Dest Org Packets 10.0.0.50 Private 10.0.0.1 Private 15 10.0.0.2 Private 93.184.216.34 Unknown 2 10.0.0.2 Private 8.8.8.8 Unknown 2 10.0.0.60 Private 10.0.0.61 Private 2 93.184.216.34 Unknown 10.0.0.2 Private 1 10.0.0.61 Private 10.0.0.60 Private 1 10.0.0.2 Private 10.0.0.99 Private 1 Top talkers by byte volume Source Source Org Destination Dest Org Bytes 10.0.0.50 Private 10.0.0.1 Private 600 B 10.0.0.2 Private 93.184.216.34 Unknown 262 B 10.0.0.2 Private 8.8.8.8 Unknown 143 B 10.0.0.60 Private 10.0.0.61 Private 80 B 93.184.216.34 Unknown 10.0.0.2 Private 63 B 10.0.0.61 Private 10.0.0.60 Private 40 B 10.0.0.2 Private 10.0.0.99 Private 28 B Top destination ports Port Service Packets 80 http 3 53 domain 2 443 https 1 50001 unknown 1 1024 unknown 1 1025 unknown 1 1026 unknown 1 1027 unknown 1 1028 unknown 1 1029 unknown 1 Suspicious patterns (heuristics, not ground truth) Type Severity Summary plaintext-credentials high 1 plaintext credential exposure(s) in HTTP traffic syn-scan medium 1 source(s) with many unanswered SYN packets (possible port scan) dns-tunneling-candidate medium 1 DNS quer(ies) with high-entropy or long subdomains (threshold entropy>3.5 & len>=18) arp-spoofing-candidate medium 1 IP(s) mapped to multiple MAC addresses in ARP replies - [packet #1] 10.0.0.2 -> 93.184.216.34: HTTP Basic Authorization header (POST /login HTTP/1.1) - 10.0.0.50: 15 SYN(s) sent, only 0 SYN-ACK(s) observed in return - a1b2c3d4e5f6a7b8c9d0e1f2.example.com (subdomain 'a1b2c3d4e5f6a7b8c9d0e1f2', len=24, entropy=3.92, packet #3) - 192.168.1.1 claimed by MACs: aa:bb:cc:dd:ee:01, aa:bb:cc:dd:ee:ff ``` ### JSON 导出 ``` pcap-insight capture.pcap --export json > report.json ``` ``` { "summary": { "total_packets": 27, "duration_seconds": 13.0, "total_bytes": 1216, "avg_packet_size": 45.04, "start_time": 1700000000.0, "end_time": 1700000013.0, "start_time_utc": "2023-11-14 22:13:20.000000+00:00", "end_time_utc": "2023-11-14 22:13:33.000000+00:00" }, "protocols": [ {"protocol": "TCP", "count": 18, "percent": 66.67}, {"protocol": "ARP", "count": 3, "percent": 11.11}, {"protocol": "DNS", "count": 2, "percent": 7.41}, {"protocol": "TLS", "count": 2, "percent": 7.41}, {"protocol": "HTTP", "count": 1, "percent": 3.7}, {"protocol": "ICMP", "count": 1, "percent": 3.7} ], "top_talkers_by_packets": [ {"src": "10.0.0.50", "dst": "10.0.0.1", "src_org": "Private", "dst_org": "Private", "packets": 15} ], "top_talkers_by_bytes": [ {"src": "10.0.0.50", "dst": "10.0.0.1", "src_org": "Private", "dst_org": "Private", "bytes": 600} ], "top_ports": [ {"port": 80, "count": 3, "service": "http"} ], "suspicious_findings": [ { "type": "plaintext-credentials", "severity": "high", "summary": "1 plaintext credential exposure(s) in HTTP traffic", "details": ["[packet #1] 10.0.0.2 -> 93.184.216.34: HTTP Basic Authorization header (POST /login HTTP/1.1)"] } ] } ``` ### BPF 过滤器子集 `--filter` 接受一个实用的 tcpdump 子集,应用于我们规范化后的 数据包记录,**无需 libpcap/Npcap**: | 原语 | 示例 | |---|---| | 协议 | `tcp`, `udp`, `icmp`, `arp`, `ip` | | 主机 | `host 10.0.0.5`, `src host 10.0.0.5`, `dst host 10.0.0.5` | | 网络 | `net 192.168.0.0/16`, `src net 10.0.0.0/8`, `dst net 172.16.0.0/12` | | 端口 | `port 443`, `src port 53`, `dst port 22` | | 端口范围 | `portrange 8000-8080`, `dst portrange 1024-2048` | | 组合符 | `and`, `or`, `not`, `(`, `)` | 示例: ``` pcap-insight capture.pcap --filter 'tcp port 443' pcap-insight capture.pcap --filter 'udp port 53 and not src host 8.8.8.8' pcap-insight capture.pcap --filter 'src net 10.0.0.0/8 and dst portrange 1-1024' ``` 不支持(会显式报错):IPv6 地址、以太网原语 (`ether host`、`ether proto`、VLAN)以及完整的 libpcap 语法。请注意, 我们的协议标签是具有传输层感知能力的:`tcp` 也会匹配标记为 HTTP 或 TLS 的数据包,因为它们承载于 TCP 之中。 ## 可疑模式启发式算法的工作原理(及其误报情况) 这四个检测器是经过精心设计的、简单且具有确定性的规则。它们 旨在作为**标记启发式规则,而非绝对事实**。每个检测器都 在 `tests/` 中的合成捕获文件上进行了单元测试。 ### 1. 通过 HTTP 传输的明文凭据 **规则。** 对于每个其 payload 解析为 HTTP 请求的数据包 (`METHOD SP path SP HTTP/x.y`),如果满足以下条件则将其标记: - headers 包含以 `Basic `(base64 凭据)开头的 `Authorization:` 请求头,或 - 请求体包含匹配 `pass|pwd|password|passwd|...=` (不区分大小写)的表单字段。 **为何容易产生误报 / 假阳性。** - `pass` 会匹配 body 字段名中的诸如 `passphrase`、`passcode`、`bypass`、`compass` 等子串。 - 检测器无法判断 `https://` 流量是否在范围内,页面是否 为蜜罐,或者字段是否经过了客户端加密。 - 仅检查*出站请求*;检测器不解析分块传输(chunked) 的 body、gzip 或 HTTP/2(它们不是明文 HTTP/1.1 请求行)。 - 捕获工具可能会记录属于产品演示或 故意公开表单的登录表单(例如测试环境中的 `username=admin&password=admin`)。 ### 2. 未响应的 SYN 突发(可能的 SYN 扫描) **规则。** 按源 IP 统计: - 每个设置了 `SYN` 且清除了 `ACK` 的 TCP 数据包(这是握手*或* 探测的第一步),以及 - 同一 IP 接收到的 `SYN+ACK` 回复数量。 将符合以下情况的重点源 IP 标记:SYN 数量 ≥ 10 且其中收到回复的比例不足一半。 **误报 / 注意事项。** - 对合法但不可达的连接进行的 TCP 重传将显示为 重复的未响应 SYN,并可能触发此规则。 - 激进的负载均衡器或健康检查器一次性发起大量连接 (例如攻击者*自己的*具有短暂 `connect` 超时的 NAT 出口),如果没有响应流,其表现将与之 完全相同。 - 非对称捕获(SPAN 仅在一侧进行)会看到 SYN 但看不到 回复,从而产生虚假的“扫描”。 - 阈值(10 个 SYN,回答率 <50%)是任意的;请通过 `pcap_insight/analyzers.py` 中的 `SYN_SCAN_MIN_SYNS` 常量进行调整。 ### 3. DNS 隧道传输 / C2 信标 **规则。** 对于每个带有 qname 的 DNS 查询,去除可注册域名(使用 小型的内部公共后缀列表,见注意事项),并计算子域名的 **Shannon 熵**(以位为单位)。在以下任一情况发生时标记该查询: - 子域名熵 > **3.5 位** *且* 子域名长度 ≥ 18 个字符,或 - 子域名长度超过 18 + 20 = 38 个字符(即使是低熵也很长, 例如重复的 `aaaa...`)。 反向 IP 字面值名称(`4.4.8.8.in-addr.arpa`,`abcd.ef01.example.com` 十六进制字面值风格)被排除在外,因为它们属于常规的基础设施记录。 受管的云区域也被归入“可注册”侧:对于 AWS、 CloudFront、Azure、Google APIs、Fastly 和 Microsoft 端点,提供商区域正上方的标签是由提供商控制的 (`codewhisperer.us-east-1.amazonaws.com`,`d123abc456.cloudfront.net`, `mobile.events.data.microsoft.com`),因此它们被视为已注册的 主机名,而不是随机的子域名。受管区域*之上*的随机标签(例如 `..amazonaws.com`)仍会被标记。 对同一 qname 的重复查询只会报告**一次**。重试和缓存 未命中是正常现象,标记每一次重试会增加噪音。此发现会统计 唯一的 qname,而不是查询数据包。 **误报 / 注意事项。** - 熵阈值是近似值。合法的看似随机的标签,例如 CDN 主机名、跟踪查询子域名、唯一的缓存清除标识符, 以及 `crypto`/`uuid` 风格的 API 主机名经常会超过 3.5 位。 - 我们的公共后缀列表**不是**完整的 [Public Suffix List](https://publicsuffix.org/)(该非常庞大且经常 变动),因此像 `foo.example.co.uk` 这样的域名可能会被拆分为 `co.uk` 的可注册域名,从而将 `foo.example` 留作“子域名”,如果那里有一个短小的随机标签,可能会产生误报。 - 受管区域列表是一个简短的白名单。不在列表中的区域(其他 CDN、 云提供商,或您使用的云托管 SaaS)对于其看似随机但合法的 主机名仍会产生误报。请针对您的环境扩展 `pcap_insight/analyzers.py` 中的 `_MANAGED_ZONES`。 - 长的 base64/十六进制数据块是典型的隧道/C2 特征,但相同的特征 也会出现在合法的基于 DNS 的 CDN 注册以及 DoH/DoT 时代的基础设施中。 - 此检测器针对单个查询触发;真正的隧道检测还会使用 基于域名的查询量、查询大小分布和查询时间规律, 而本工具**并未**实现这些功能。 ### 4. ARP 回复:一个 IP 被多个 MAC 声明 **规则。** 收集在 **ARP 回复数据包**(`op=2`)中为每个发送方 IP 声明的发送方 MAC 地址集合。标记在捕获文件中被多个不同 MAC 声明的任何 IP。 **误报 / 注意事项。** - **合法的多 MAC 场景是最常见的误报:** - 具有多个别名/VLAN 的服务器网卡,从 不同的物理网卡宣告相同的 IP(端口聚合、主备模式的负载均衡器); - 脚本化的故障转移,在过渡期间新旧 MAC 地址都会 作出响应; - 捕获文件合并:来自不同网段的两个捕获文件 自然会有共享的 IP,但具有不同的 MAC。 - ARP 请求(`op=1`)被刻意忽略:对 `who-has X` 的请求*并不* 意味着发送方声明了 `X`。 - 检测器需要在*同一个*捕获文件中包含这两个回复;如果您的捕获窗口 恰好跨越了合法的故障转移,则两个 MAC 都会出现。 ## 检测器阈值一览 | 检测器 | 主要阈值(在 `analyzers.py` 中的常量) | |---|---| | 明文凭据 | `Basic` 认证请求头或 body 正则表达式 `(pass|pwd|password|passwd|user_pass|client_secret)=` | | SYN 扫描 | ≥ `SYN_SCAN_MIN_SYNS` = 10 个 SYN;回答率 < 50% | | DNS 隧道 | 子域名熵 > `DNS_ENTROPY_THRESHOLD` = 3.5 且长度 ≥ 18;或长度 > `SUBNAME_PADDING` + 18 = 38 | | ARP 欺骗 | 在 ARP 回复中,有 ≥ 2 个不同的发送方 MAC 声明了同一个发送方 IP | 这些数值只是起点,并非经过研究支持的调优结果。请在 `pcap_insight/analyzers.py` 中调整它们并重新运行测试套件。 ## 开发指南 假设您已经创建并激活了虚拟环境(参见上方的 [安装说明](#installation))。 ``` python -m pip install -e ".[dev]" python -m pytest -v ``` 该测试套件(78 个测试)涵盖: - 对照参考公式和已知字符串的 Shannon 熵正确性 - 协议计数 / 百分比 / 排序顺序 - 活跃主机和高频端口聚合、服务名回退 - 每个可疑模式检测器:命中情况、正常情况和边界情况 - BPF 过滤引擎(解析、限定符、组合符、无效过滤器) - 端到端的 CLI 表格、JSON 导出、JSON + 过滤器以及 `--demo` - 信息补充行为(私有 IP 短路、缓存、失败处理) - 合成的 `tests/` 固定捕获文件的解析(在会话 fixture 中由 Scapy 生成;无外部 pcap 文件) ### 项目结构 ``` pcap-insight/ pcap_insight/ __init__.py # package metadata / version parser.py # Scapy reading -> PacketRecord, plus the BPF-subset engine analyzers.py # stats + four heuristic detectors (pure, testable) cli.py # argparse, rich rendering, JSON export enrichment.py # offline GeoLite2-ASN org lookup (cache + private detection) testing.py # synthetic capture builder (used by tests and --demo) tests/ conftest.py # session fixtures (creates the synthetic capture) test_analyzers.py test_filter.py test_cli.py test_enrichment.py README.md requirements.txt pyproject.toml # pip-installable, console script: pcap-insight ``` ## 环境依赖 - Python 3.10+ - `scapy` ≥ 2.5 - `rich` ≥ 13 - `geoip2` ≥ 4(用于可选的组织/ASN 信息补充) - `pytest` ≥ 8(仅限开发使用) 有关锁定的最低版本,请参见 `requirements.txt`。
标签:IP 地址批量处理, PCAP分析, Python, Scapy, 无后门, 网络流量分析, 逆向工具, 防御绕过