---
name: traffic-analysis
description: CTF 流量分析与网络取证（pcap / network forensics）：pcap 分诊、DNS/ICMP/TCP 隐信道与隧道重组（covert channel / tunneling）、USB HID 键鼠抓包还原、WPA/TLS 解密、文件与凭据提取。触发：流量/pcap/抓包/Wireshark/tshark/网络取证/流量包/隐蔽信道/隧道。不做二进制逆向——那是 ghidra-static 系；提取出的文件需逆向时回 re-triage。
whenToUse: 拿到 pcap/pcapng 要分析时；DNS 隧道、ICMP/时序/TCP flag 隐信道、USB HID 键盘鼠标抓包、802.11 eapol/WPA 解密、TLS keylog 解密、--export-objects 文件提取、明文凭据收割
---

# Traffic Analysis（场景 6：流量里找信号）

前置：拿到 pcap/pcapng（题目附件，或别的主线提取出的文件）／后继：提取出的二进制 → `~/.dsh/skills/re-triage` 重新分诊；文本/flag 类结论直接交付

> **内容看不懂时，信号在元数据里**：包长、TTL、IPID、时延、TCP flags 的 per-packet 分布画直方图，值落在可打印 ASCII 区间的分布就是信号（TokyoWesterns 2018 方法论，细节 references/tunnels.md §通用检测）。同一路径失败 2 次换工具，单方向 ≤15 分钟（铁律 6，全文见 ghidra-core §1）。

## 路径约定

```bash
TA="$HOME/.dsh/skills/traffic-analysis/scripts"   # 本 skill 脚本（全零依赖，Python 3 stdlib）
# Windows:
TS="$HOME/Desktop/src/tools/wireshark/tshark.exe" # tshark 4.6.8（7z 免安装解包；未加 PATH，用全路径）
EC="$HOME/Desktop/src/tools/wireshark/editcap.exe" # editcap（pcapng→pcap 转换）
# WSL/Linux（apt 安装，PATH 直达）:
# TS="$(command -v tshark)"; EC="$(command -v editcap)"
```

本 skill 不依赖 tshark——`pcap_triage.py` / `conflict_oracle.py` / `decode_engine.py` 自研解析器保底（全 stdlib）；tshark/editcap/scapy/aircrack-ng/hashcat 是否可用以 `python "$SK/doctor.py"` 的 toolchain 节为准（SK 路径见 ghidra-core），缺失按 hint 装或绕。ghidra-core 的 unreferenced_data.py / ledger.py 仅为路由引用，非本 skill 脚本的运行依赖。

## 流程

### 1. 打不开先修

`xxd cap.pcap | head -1` 对 magic bytes（d4c3b2a1/a1b2c3d4=pcap，0a0d0d0a=pcapng）→ 修头/pcapfix/格式转换，配方见 `references/pcap-triage.md` §修复。

### 2. 开局三连（每条 30 秒内）

```bash
python "$TA/pcap_triage.py" cap.pcap      # 零依赖：包数/时间跨度/协议分布/包长直方图/top 会话 + 路由 hint
"$TS" -r cap.pcap -q -z io,phs            # 有 tshark 时交叉验证：协议分层统计
"$TS" -r cap.pcap -q -z conv,ip           # 会话/端点
```

- `pcap_triage.py` **exit 2 = 某协议占比 >60%**，直接跟它打印的路由 hint 走；报告末尾的**每流字段一致性矩阵**打出 ⚠ 重复键冲突时，走 `conflict_oracle.py`（见 §2.5 异常即约束）
- **大 pcap（百万包级）**：信号载体往往藏在包数最少的协议/会话里，按包数倒序找（EHAX 2026 经验）
- pcapng 会被 pcap_triage 拒收：`"$EC" -F pcap in.pcapng out.pcap` 转换后再来

### 2.5 解码阶梯：轴必须交叉，且先算预算

```
明文候选 = OP(字段₁..字段₃) × 顺序(下标/seq/TS/外部置换表) × 打包(半字节 hi|lo, 位序) × 后变换
- OP 至少覆盖 1~3 元 XOR / ADD / SUB → scripts/decode_engine.py 强制全交叉
- 顺序源包含"附件二进制里零引用的置换表"（ghidra-core scripts/unreferenced_data.py）
- 硬门 1（预算）：先算候选总数；算得出却仍剪轴 ⇒ 必须写明理由（铁律 13）
- 硬门 2（覆盖）：任一轴恒为 identity/常量 ⇒ 记为未覆盖，禁止计入"试过"
- 硬门 3（oracle）：无校验手段（hash 常量/重复项一致性/格式校验位）不许全交叉开跑
- 尺寸对齐：载体位数与目标长度严丝合缝 = 信道判对的强证据（非禁令——尺寸巧合可作诱饵）
```

**异常即约束**：

```
同一逻辑键（同 seq / 同下标 / 重传）上字段取值冲突
  ⇒ 该字段大概率不是明文；明文可能是 ≥2 字段的复合函数（xor/add/sub）
  ⇒ 正确函数必须让重复项一致 → 免费过滤器：scripts/conflict_oracle.py
  ⇒ 注意真实抓包重传载荷可合法不同——冲突是假设生成器，不是排除器
  ⇒ 未解决前用 ghidra-core ledger.py anomaly --consequence 落账，禁止当噪声枚举
```

**表先看跨度**：附件有二进制时，32 字节零引用表 → 先查 +0x40/+0x80 是否构成 64/128 项置换，相邻表可能是同一置换的两半或倒序（ghidra-core unreferenced_data.py）。

### 3. 路由表（按分诊发现选路）

| 分诊发现 | 去哪 |
|---|---|
| DNS 占比高 / 查询名 >40 字节 / TXT 记录异常 | `references/tunnels.md` §DNS + `scripts/dnscat2_reassemble.py` |
| ICMP 异常（payload 非标准/长度可疑/时延双峰） | `references/tunnels.md` §ICMP + `scripts/timing_decode.py` |
| TCP flag 组合混乱（FIN+SYN 同现）、同端口包数 %4==0 | `references/tunnels.md` §TCP flags |
| 包内容雷同、间隔只有两档 | `references/tunnels.md` §时序 + `timing_decode.py --mode interval` |
| USB linktype（189/220/288） | `references/usb-hid.md` + `hid_keyboard.py` / `mouse_render.py` |
| 802.11/radiotap、eapol 四次握手 | `references/wifi-tls.md` §WPA |
| TLS 密文 + 附件有 keylog/私钥/coredump | `references/wifi-tls.md` §TLS |
| HTTP/SMB/FTP 明文传文件 | `references/pcap-triage.md` §文件提取 |
| FTP/Telnet/HTTP Basic/NTLM 认证流量 | `references/pcap-triage.md` §凭据 |
| 协议分布全正常、内容全噪声 | 元数据直方图：`timing_decode.py --mode len` / `--mode byte --offset N`（TTL=IP+8，TOS=IP+1；**IPID 是 16 位大端，`--offset` 只读 1 字节 → 高字节 IP+4 恒为 0、低字节 IP+5**），方法论 `references/tunnels.md` §通用检测 |
| 附件 = pcap + 二进制 | 先用 ghidra-core `unreferenced_data.py` 提取零引用材料清单（置换/替换/密钥表），再解 pcap |
| 字段取值在重传/重复键上冲突 | 复合算子分支：`conflict_oracle.py`（不是噪声分支）→ 命中组合交 `decode_engine.py` + oracle 验证 |

### 4. 证据落账（强制）

每个观察/结论走 ghidra-core `scripts/ledger.py`（`observe`/`conclude`，key 用 pcap 文件名），机制见 ghidra-core `references/evidence-ledger.md`。**提取出的文件先正向验证**（魔数/file 命令/能打开）才算证据；自建解码脚本在支撑结论前用已知答案自检（铁律 10 ②）。

### 5. 时间盒与换路

同一路径失败 2 次 → 换工具（如 hid 手工解析不行就回 tshark 换字段导）；单方向 ≤15 分钟无产出 → 回 §3 路由表选下一行；彻底卡住 `ledger.py stuck` 留痕并问用户。

## 脚本速查

| 脚本 | 一句话 |
|---|---|
| `scripts/pcap_triage.py` | 开局分诊（零依赖）；某协议占比 >60% exit 2 并给路由 hint；报告末尾附 top TCP 流字段一致性矩阵，重复键冲突打 ⚠ |
| `scripts/conflict_oracle.py` | 重复逻辑键上字段冲突报告 + 消除冲突的 1~3 元 xor/add/sub 组合排名（假设生成器，非排除器） |
| `scripts/decode_engine.py` | 字段×算子×顺序×打包多轴全交叉解码；无 --oracle（sha256/前缀/可打印）exit 2 拒绝开跑，超 --max-candidates 同样 exit 2 |
| `scripts/hid_keyboard.py` | usbhid.data hex 行 → 还原文本（内置完整 HID 键码表+Shift 映射，--lines 跟踪方向键分行） |
| `scripts/mouse_render.py` | HID 鼠标/数位板位移 → 累加轨迹 → PGM 图（纯 stdlib；输出是 `<out>_mode<N>.pgm` 不是 `<out>.pgm`；`--png` 需 PIL——**venv 里没有 PIL、PATH 上的 python 3.10 才有**，缺了自动降级只出 PGM） |
| `scripts/dnscat2_reassemble.py` | DNS 查询名列表 → 去 9 字节头/去重传 → 重组 payload（缺省只自动猜 **2 级**隧道域名；3 级以上必须显式 `--domain`，否则静默猜错成 `example.com`） |
| `scripts/timing_decode.py` | 时序分档/包长/单字节字段 → bit/字节 → ASCII 渲染 |

## References

| 文件 | 何时读 |
|---|---|
| `references/pcap-triage.md` | pcap 修头/pcapfix、`--export-objects` 文件提取、流重组、明文凭据与 NTLMv2、strings 碰运气 |
| `references/tunnels.md` | DNS（dnscat2/尾部字节/TXT/oracle）、ICMP、TCP flags、时序隐信道配方 + 通用元数据直方图方法论 + pcap+二进制复合题载体判定 tells |
| `references/usb-hid.md` | USB 键盘 8 字节报告、鼠标/数位板画图还原、LED Morse、蓝牙 RFCOMM 重组 |
| `references/wifi-tls.md` | WPA eapol 破解+airdecap 二次分析、TLS 解密三途径、SMB3.1.1 会话密钥推导 |
