gecsemax/Oneida-Network-Steganography-Detector-
GitHub: gecsemax/Oneida-Network-Steganography-Detector-
一款基于 12 通道统计的高性能网络隐写术检测器,用于被动识别隐蔽通信并触发告警。
Stars: 1 | Forks: 0
```
# Oneida v4.2 – 网络隐写术检测器
> A high-performance, 12-channel network covert channel detector written in C.
> Designed for live traffic analysis and PCAP replay on Linux and macOS.
---
## 目录
- [Overview](#overview)
- [How It Works](#how-it-works)
- [Detection Channels](#detection-channels)
- [Architecture](#architecture)
- [Requirements](#requirements)
- [Build](#build)
- [Usage](#usage)
- [Output Formats](#output-formats)
- [Configuration Reference](#configuration-reference)
- [Signals](#signals)
- [Performance Tuning](#performance-tuning)
- [Version History](#version-history)
- [License](#license)
---
## 概述
**Oneida** passively monitors network traffic and scores every TCP, UDP, and ICMP flow across 12 independent statistical channels. When the weighted composite score of a flow exceeds a configurable threshold, an alert is emitted — either as human-readable text or as a JSON record suitable for SIEM ingestion.
Oneida detects:
- **Timing-based covert channels** — inter-packet delay modulation
- **Size-based covert channels** — fixed or patterned packet lengths
- **Header covert channels** — TCP flag abuse, TTL manipulation, IP-ID modulation
- **DNS tunnels** — iodine, dnscat2, dns2tcp (label encoding + query rate + record type)
- **Payload covert channels** — high-entropy payloads hidden inside normal-looking flows
- **Burst-pattern channels** — timer-driven injectors with regular IPD spacing
- **Directional covert channels** — extreme traffic asymmetry
---
## 工作原理
```
网络接口/PCAP文件
│
▼
┌─────────────┐ memcpy ┌──────────────────────┐
│ pcap_loop │ ──────────► │ 无锁环形缓冲区 │ 65 536 个槽位
│ (捕获 │ │ (SPSC, 原子头/尾) │ 64 MB 内核环形缓冲区
│ 线程) │ │ │
└─────────────┘ └──────────┬───────────┘
│ sem_post (上限)
▼
┌──────────────────────┐
│ 工作线程 │
│ process_one() │
│ ├─ parse_packet() │
│ ├─ 流查找/分配 │ 每个桶的读写锁
│ ├─ 重传检查 │ O(1) 序列号哈希集合
│ ├─ DNS 解码 │
│ ├─ 窗口槽位写入 │ 256 个槽位的循环缓冲区
│ ├─ 计算分数 │ 脏标志 / N=64
│ └─ 发出告警 │
└──────────────────────┘
│
┌──────────▼───────────┐
│ 清理线程 │ 每 30 秒
│ 过期空闲流 │ 安全锁顺序
└──────────────────────┘
```
Each flow is tracked using a bidirectional canonical key (`min(src,dst)` always first), so `A→B` and `B→A` packets update the same flow record. A pre-allocated slab pool of 32 768 flow structs avoids dynamic allocation on the hot path.
---
## 检测通道
| Ch | Name | What it measures | Suspicious pattern |
|----|------|------------------|--------------------|
| 0 | **IPD CoV** | Inter-packet delay Coefficient of Variation | CoV < 0.10 → timer-driven (score 0.85) |
| 1 | **Length Std Dev** | Standard deviation of packet lengths | Std < 2.0 → fixed-size encoding (score 0.85) |
| 2 | **Protocol Entropy** | Shannon entropy of L4 protocol field | Unexpected protocol diversity |
| 3 | **TCP Flag Entropy** | Entropy of observed TCP flag combinations | Unusual flag patterns / covert flag abuse |
| 4 | **SEQ Variance** | Variance of TCP sequence numbers | Low variance = suspiciously predictable SEQ |
| 5 | **IP-ID Delta** | Delta between consecutive IP Identification fields | Static or tiny-range modulation = covert channel |
| 6 | **Window Variance** | TCP receive window size variance | Constant window = possible encoding |
| 7 | **TTL Variance** | Variance of IP Time-To-Live values | High variance = TTL manipulation |
| 8 | **Payload Entropy + DNS** | Shannon entropy of payload bytes; DNS tunnel heuristics | High entropy = encrypted carrier; DNS rate/charset/type |
| 9 | **Directional Asymmetry** | `|bytes_fwd/total − 0.5| × 2` | > 0.85 → one-way-only flow |
| 10 | **Burst Regularity** | CoV of inter-packet delays (burst view) | CoV < 0.10 → equal-spacing = timer injector |
| 11 | **Retransmit Rate** | Retransmissions / total packets | Unusually high retransmit rate |
### 加权综合评分
```text
score = Σ(channel_score[i] × weight[i]) / Σ(weight[i])
```
默认权重:时机×2,长度×2,标志×1.5,负载×2,突发×2,不对称×1.5,IP-ID×1.5,其余×1。
当 `score > threshold`(默认 **0.45**)且至少经过 30 个数据包后触发告警,每个流有冷却时间(默认 **5 秒**)。
### DNS 隧道检测(第 8 章子计分器)
Oneida 从 UDP 端口 53 流量解码 DNS 查询名称,并应用四种独立启发式方法:
| 启发式方法 | 分数贡献 | 目标 |
|------------|----------|------|
| 查询速率 > 10/10 秒 | +0.40 | 所有隧道 |
| TXT 或 NULL 记录类型 | +0.30 | iodine、dnscat2 |
| 标签中使用 Base32/Base64 字符集 | +0.35 | iodine、dns2tcp |
| 标签长度 > 40 字符 | +0.25 | 所有隧道 |
DNS 分数在更高时替代负载熵分数。
### IP-ID 隐蔽信道(第 5 章)
| Delta 模式 | 分数 | 解释 |
|------------|------|------|
| 标准差 < 1.0(静态) | 0.55 | ID 冻结 — 故意隐藏 |
| 标准差 < 8,平均值 < 8 | 0.60 | 小范围调制 |
| 标准差 < 3,平均值 0.5–5 | 0.10 | 正常内核计数器 |
| 其他情况 | 0.05 | 随机化(现代操作系统) |
## 架构
### 线程模型
| 线程 | 角色 | CPU 绑定标志 |
|------|------|-------------|
| 主线程 / pcap | `pcap_loop`、`capture_callback` |(默认) |
| 工作线程 | 从环形缓冲区出队,运行评分管道 | `-W <核心>` |
| 清理线程 | 每 30 秒清理过期/旧流 | `-C <核心>` |
### 流表
- **8192 个哈希桶**,每个桶包含一个 `pthread_rwlock_t`
- 查找(热路径)仅对一个桶获取**读锁**
- 写入插入时进行双重检查(无 TOCTOU 竞争)
- 每个流使用 `pthread_mutex_t` 进行槽位写入和评分
- **安全清理:** 在获取每个流的互斥锁之前先释放桶的写锁,以避免死锁
### 内存
- **预分配 slab 池**,包含 32768 个 `flow_t` 结构体
- 启动后无动态分配
- 池使用 `uint32_t` 空闲列表计数器(适合长时间运行)
### 环形缓冲区
- **65536 个槽位**,单生产者/单消费者
- 使用原子操作实现无锁头/尾
- `sem_post` 有**上限**(通过 `sem_getvalue`)——高 PPS 下不会失控
- 通过 `pcap_set_buffer_size` 提供 64 MB 内核环形缓冲区
## 需求
| 依赖项 | 版本 | 说明 |
|--------|------|------|
| `libpcap` | ≥ 1.5 | `libpcap-dev` / `libpcap-devel` |
| GCC 或 Clang | GCC ≥ 9,Clang ≥ 11 | 需要 C11 |
| Linux 内核 | ≥ 3.10 | `AF_PACKET`、CPU 亲和性 |
| macOS | ≥ 10.15 | BPF,不支持 CPU 亲和性 |
```
# Debian / Ubuntu
sudo apt install libpcap-dev gcc make
# RHEL / Fedora
sudo dnf install libpcap-devel gcc make
# macOS
brew install libpcap
```
## 构建
```
# 标准构建
gcc -O2 -std=c11 -Wall -Wextra -o oneida oneida.c -lpcap -lm -lpthread
# 编译时覆盖
gcc -O2 -std=c11 -DMAX_FLOWS=65536 -DWINDOW_SIZE=512 \
-o oneida oneida.c -lpcap -lm -lpthread
# 调试构建
gcc -O0 -g -fsanitize=address,undefined -std=c11 \
-o oneida_dbg oneida.c -lpcap -lm -lpthread
```
## 使用
### 实时捕获(需要 root 权限)
```
sudo ./oneida eth0
sudo ./oneida enp3s0
```
### PCAP 文件回放
```
./oneida capture.pcap
./oneida capture.pcapng
```
### 通用选项
```
# 低阈值(更敏感),10 秒冷却时间
sudo ./oneida -t 0.35 -a 10 eth0
# 纳秒时间戳,详尽输出
sudo ./oneida -n -v eth0
# JSON 输出,管道到 jq
sudo ./oneida -j eth0 | jq 'select(.score > 0.6)'
# 固定线程,禁用混杂模式
sudo ./oneida -W 2 -C 3 -p eth0
# 完整选项
sudo ./oneida -t 0.40 -a 5 -i 120 -l 1800 -n -v -W 2 -C 3 eth0
```
## 输出格式
### 纯文本(默认)
```
🚨 STEG ALERT [0.623] 10.0.0.5:54321 -> 8.8.8.8:53 | UDP | pkts=412 frags=0 icmp=0
Timing=0.85 Len=0.85 Flags=0.05 Payload=0.75 Burst=0.85 Asym=0.25 TTL=0.05 Retrans=0.05
DNS tunnel score=0.70 qrate=14 txt/null=3 b32b64=5
```
### JSON(`-j`)
```
{
"alert": true,
"score": 0.6231,
"flow_id": "a3f2c1d490e87b12",
"src": "10.0.0.5",
"dst": "8.8.8.8",
"sport": 54321,
"dport": 53,
"proto": "UDP",
"pkts": 412,
"bytes_fwd": 38204,
"bytes_rev": 12800,
"frags": 0,
"icmp": 0,
"dns_score": 0.700,
"ipid_var": 0.000,
"ch": [0.850, 0.850, 0.050, 0.050, 0.100, 0.050,
0.100, 0.050, 0.750, 0.250, 0.850, 0.050]
}
```
### SIEM 集成
```
# 写入文件
sudo ./oneida -j eth0 >> /var/log/oneida/alerts.jsonl
# 管道到 Elasticsearch
sudo ./oneida -j eth0 | \
while read line; do
curl -s -X POST "http://localhost:9200/oneida/_doc" \
-H 'Content-Type: application/json' -d "$line" > /dev/null
done
```
## 配置参考
| 标志 | 默认值 | 描述 |
|------|--------|------|
| `-t <浮点数>` | `0.45` | 告警阈值(0.0–1.0) |
| `-a <秒>` | `5` | 每个流的告警冷却时间(秒) |
| `-i <秒>` | `300` | 空闲流过期时间(秒) |
| `-l <秒>` | `3600` | 最大流生命周期(秒) |
| `-j` | 关闭 | JSON 输出模式 |
| `-p` | 关闭 | 禁用混杂模式 |
| `-n` | 关闭 | 纳秒时间戳精度 |
| `-W <核心>` | 关闭 | 将工作线程绑定到 CPU 核心 N |
| `-C <核心>` | 关闭 | 将清理线程绑定到 CPU 核心 N |
| `-v` | 关闭 | 详细模式:告警时打印特征值 |
| `-h` | — | 打印帮助并退出 |
### 编译期常量
| 宏 | 默认值 | 描述 |
|----|--------|------|
| `MAX_FLOWS` | 32768 | 最大并发跟踪流数 |
| `FLOW_HASH_SIZE` | 8192 | 哈希表桶数(2 的幂) |
| `WINDOW_SIZE` | 256 | 每个流的滑动窗口包数 |
| `RING_CAPACITY` | 65536 | 环形缓冲区槽位(2 的幂) |
| `KERNEL_RING_BYTES` | 64 MB | libpcap 内核环形缓冲区大小 |
| `RESCORE_INTERVAL` | 64 | 每 N 个包重新评分 |
| `DNS_RATE_THRESH` | 10 | 每 10 秒 DNS 查询数达到阈值则标记为隧道 |
## 信号
| 信号 | 效果 |
|------|------|
| `SIGINT` / `SIGTERM` | 优雅关闭,排出环形缓冲区,打印统计信息 |
| `SIGUSR1` | 打印实时统计信息而不中断捕获 |
```
# 实时统计
kill -USR1 $(pgrep oneida)
# 示例输出
[stats] active_flows=1423 dropped=0 alerts=7
```
## 性能调优
### 高流量环境(> 1 Mpps)
```
# 将线程固定到隔离核心
sudo ./oneida -W 4 -C 5 eth0
# 在编译时增加流表
gcc -O3 -DMAX_FLOWS=131072 -DFLOW_HASH_SIZE=32768 \
-o oneida oneida.c -lpcap -lm -lpthread
# 使用 AF_PACKET 环(Linux)
sudo ethtool -G eth0 rx 4096
# 增加套接字缓冲区
sudo sysctl -w net.core.rmem_max=134217728
```
### 低延迟 PCAP 回放
```
./oneida -n -t 0.35 large_capture.pcapng
```
### 阈值调整指南
| 环境 | 建议的 `-t` 值 |
|------|----------------|
| 实验室/测试 | 0.35 |
|局域网 | 0.45(默认) |
| 面向互联网 | 0.55 |
| 高噪声数据中心 | 0.65 |
## 版本历史
| 版本 | 关键变更 |
|------|----------|
| **v4.2** | TTL 方向修复、slot_valid 使用、死锁修复、uint32_t 池计数器、stat() 检测、capped sem_post、ICMP 支持、脏标志重新评分、SIGUSR1 统计、IP-ID 通道、DNS 隧道字符集/速率/类型、告警计数器 |
| **v4.1** | 标志熵方向、过期分数重置、重传在槽位写入前、O(1) 序列号哈希集、信号驱动工作线程、slab 池、64 MB 内核环形缓冲区、每个流的告警冷却时间、纳秒时间戳、IPv4 分片检测 |
| **v4.0** | 每个桶的读写锁、无锁 SPSC 环形缓冲区、CPU 亲和性、双向流键、基于 CoV 的 IP-ID、负载熵、突发规律性、方向性不对称、TCP 重传率 |
## 已知限制
- **仅支持 IPv4** — IPv6 数据包在解析器处静默丢弃
- **单工作线程** — 评分为单线程;在极高 PPS 下考虑按流哈希范围分片
- **无持久化** — 流状态仅在内存中;重启会清除所有流历史
- **加密流量** — 来自 TLS/QUIC 的高熵负载可能在合法流上产生较高的第 8 章分数;相应调整阈值
- **分片流** — 未实现重组;分片会递增计数器但排除在特征评分之外
## 许可证
MIT 许可证 — 详情见 `LICENSE`。
```
Copyright (c) 2026 Max Gecse
```
```
```
标签:API安全, Bing搜索, dns2tcp, dnscat2, DNS隧道, IP-ID调制, JSON输出, PCAP, SIEM集成, TCP UDP ICMP, TCP标志位滥用, TTL操纵, 包长度模式, 实时流量, 客户端加密, 开源安全工具, 性能调优, 方向不对称, 旁路检测, 熵检测, 碘信道, 突发模式, 统计信道, 网络隐写术, 被动监测, 逆向工程平台, 阈值告警, 隐写检测