khalilu020/Network-Security-Monitoring-Threat-Hunting-with-Suricata-Zeek-and-Wazuh
GitHub: khalilu020/Network-Security-Monitoring-Threat-Hunting-with-Suricata-Zeek-and-Wazuh
基于 Suricata、Zeek 和 Wazuh 构建网络层安全监控体系,并通过假设驱动的威胁狩猎发现签名检测盲区的 SOC 实战项目。
Stars: 0 | Forks: 0
# 使用 Suricata、Zeek 和 Wazuh 进行网络安全监控与威胁狩猎
我为我的 SOC 增加了网络可见性,然后在 Suricata 的 5.2 万条规则漏报后,手动在 Zeek 的日志中狩猎端口扫描行为——发现了该模式,找到了根本原因(其规则仅监控外部→内部流量),并将其记录为狩猎操作手册。
# 网络安全监控与威胁狩猎
这是一个在现有以端点为核心的 Wazuh SIEM 基础上,构建网络层可见性(Suricata + Zeek)的项目,随后利用该可见性进行了一次真正的假设驱动的威胁狩猎——刻意测试基于签名的自动化检测会漏掉什么,以及对原始连接数据的手动分析仍然能捕获什么。
这是一个渐进式 SOC 作品集中的第四个项目:(1) 使用 Wazuh/Shuffle/TheHive 进行 SOC 自动化,(2) 结合自定义 MISP 集成并映射 MITRE ATT&CK 的检测工程,(3) 内存取证和事件时间线重建(DFIR),以及 (4) 本项目,补齐了之前所有工作中都缺失的那一层可见性:网络本身。
## 目录
- [项目目标](#project-goal)
- [实验环境架构](#lab-architecture)
- [阶段 1:Suricata 部署](#phase-1-suricata-deployment)
- [阶段 2:Zeek 部署](#phase-2-zeek-deployment)
- [阶段 3/4:Wazuh 集成](#phase-34-wazuh-integration)
- [阶段 5/6:狩猎](#phase-56-the-hunt)
- [为什么 Suricata 会漏报:详细记录的解释](#why-suricata-missed-it-a-documented-explanation)
- [狩猎操作手册总结](#hunt-playbook-summary)
- [挑战与经验教训](#challenges--lessons-learned)
- [局限性与未来工作](#limitations--future-work)
## 项目目标
在此作品集中,之前的每个项目都提供了强大的**端点**可见性(单个 Windows 主机上的 Sysmon、Wazuh agent、内存/磁盘取证)。但它们都无法看到机器之间**在线路上**实际发生了什么——而这恰恰是横向移动、侦察扫描和命令与控制流量等攻击者行为经常变得可见的地方,即使它们在端点上是不可见的。
本项目特意区分开来,提出了两个独立的问题:
1. **检测工程问题:** 一个开箱即用、内容丰富的 Suricata 规则集(52,000+ 社区签名)在此网络上能自动捕获什么?
2. **威胁狩猎问题:** 从关于原始连接数据中攻击者行为*应该*是什么样子的假设开始,即使没有被自动标记,人类分析师手动能发现什么?
这两个问题之间的区别正是本项目的核心所在——检测工程(项目 2)为已知模式编写规则;威胁狩猎是一门独立的学科,它假设规则永远都会有漏洞,并直接搜索证据。
## 实验环境架构
| 组件 | 角色 |
|---|---|
| Windows 10 (VM) | 受监控的端点 —— Sysmon、Wazuh agent(来自之前的项目) |
| Kali (宿主机) | 网络监控点 —— Suricata、Zeek 和 Wazuh agent,均为本次新增 |
| Debian (VM) | Wazuh Manager(来自之前的项目),现用于接收 Kali 的网络遥测数据 |
**与之前项目相比的一项关键基础设施变更:** Kali(运行 VirtualBox 的物理宿主机)实际上从未参与到虚拟机使用的现有 `192.168.100.x` 内部网络中——它只运行 VirtualBox 本身,并通过虚拟机内部的浏览器访问 Wazuh dashboard。为了让 Kali 能够实际观察到虚拟机之间的网络流量,创建了一个新的 **VirtualBox Host-only Network** (`192.168.56.0/24`),并将其作为第二个网络适配器添加到 Windows 10 和 Wazuh manager 上,同时保留它们现有的适配器——刻意保持原样不动,以避免破坏之前项目中正常工作的设置。
```
+---------------------+
| Windows 10 (VM) |
| 192.168.56.102 |------+
+---------------------+ |
| (vboxnet0 - Host-only network)
+---------------------+ |
| Kali (host) |<-----+
| 192.168.56.1 |
| |
| +-----------------+ |
| | Suricata (IDS) |--+--> /var/log/suricata/eve.json
| +-----------------+ |
| +-----------------+ |
| | Zeek (NSM) |--+--> ~/zeek-logs/conn.log
| +-----------------+ |
| +-----------------+ |
| | Wazuh Agent |--+--> Debian Wazuh Manager (192.168.56.101)
| +-----------------+ |
+---------------------+
```
## 阶段 1:Suricata 部署
**Suricata 是什么:** 一个网络入侵检测系统(IDS)——它根据庞大的签名库(已知的恶意模式)检查实时流量,并在匹配时生成警报。在概念上,它是项目 2 中构建的自定义 Wazuh 规则的网络层等价物,只不过它匹配的是网络数据包而不是 Windows 命令行。
**设置:**
```
sudo apt install suricata -y
sudo suricata-update
```
此操作下载并启用了来自 Emerging Threats Open 规则集(Suricata 默认的、免费提供的签名来源)的 52,087 条规则。
**验证:** 在依赖更大的规则集之前,编写了一条自定义测试规则,并确认其能够端到端正常工作:
```
alert icmp 192.168.56.102 any -> 192.168.56.1 any (msg:"TEST: Ping from Windows10 VM detected"; sid:1000001; rev:1;)
```
从 Windows 10 发出的 ping 请求正确触发了此规则,确认 Suricata 正在监听正确的接口,并且能够正确生成警报。
## 阶段 2:Zeek 部署
**Zeek 是什么:** 与 Suricata 不同,Zeek 主要不是寻找“恶意”模式——它记录了其观察到的*每一个*网络连接的详细、结构化摘要(源/目的地、协议、持续时间、字节数、连接状态),无论是否有任何内容看起来是恶意的。这使得 Zeek 的日志成为**威胁狩猎**的原始素材:在全面的连接记录中搜索没有为之编写签名的模式。
**设置:**
```
# 添加了 Zeek 的官方仓库(基于 Debian 12),然后:
sudo apt install zeek -y
```
短暂的验证运行确认 Zeek 能够在 Suricata 正在使用的同一个 `vboxnet0` 接口上观察流量,并为测试流量(一个 ICMP ping)生成了干净的 `conn.log` 连接摘要。
## 阶段 3/4:Wazuh 集成
通过直接在 Kali (`host-kali`) 上安装 **Wazuh agent**,然后配置它通过 `ossec.conf` 中的 `` 块来监控这两个日志文件,将这两个工具的日志文件接入到 Wazuh 中——这与之前项目中用于 Windows 10 上的 Sysmon 日志的机制相同。
### 一个重大的集成漏洞及其真正的根本原因
Suricata 的 `eve.json` 在第一次尝试时就顺利集成了。而配置完全相同的 Zeek 的 `conn.log` 却默默未能出现在 Wazuh 的任何地方——甚至连原始的 archive index 中也没有——尽管 Wazuh agent 自己的日志确认它正在主动读取该文件。
**根本原因(通过直接的、独立的测试确认):** Zeek 的原生 JSON 输出对连接端点使用了带有点号(`.`)的字段名(`id.orig_h`、`id.resp_h` 等)。Wazuh 基于 OpenSearch 构建,后者将 JSON key 中的点号解释为**嵌套对象分隔符**——这意味着 `id.orig_h` 被解释为“对象 `id` 内部的字段 `orig_h`”。因为 Suricata 自身的 JSON 输出已经导致 OpenSearch 在同一个索引的其他地方对 `id` 字段建立了不同且冲突的解释,包含 Zeek 带点号 `id.*` 字段的文档很可能被 OpenSearch 的映射验证直接拒绝了——而且静默执行,在 Wazuh 自己的日志中没有可见的错误,因为拒绝发生在索引层,而不是日志收集层。
**修复:** Zeek 为这种情况提供了一个有文档说明的机制——`Log::default_field_name_map`,它会在字段写入磁盘之前对其进行重命名。添加了一个本地的 Zeek 脚本:
```
redef LogAscii::use_json = T;
redef Log::default_field_name_map = {
["id.orig_h"] = "id_orig_h",
["id.orig_p"] = "id_orig_p",
["id.resp_h"] = "id_resp_h",
["id.resp_p"] = "id_resp_p"
};
```
这彻底解决了问题——Zeek 的连接数据开始出现在 Wazuh 的 archive index 中,字段干净、解析正确(`data.id_orig_h`、`data.id_resp_h` 等),完全可搜索。
**过程中的一个次要、属于操作失误的问题:** 在故障排除期间反复停止和重启 Zeek 导致其日志文件每次都被替换,触发了 Wazuh 自带的内置“日志文件大小减小”规则(`rule.id: 592`,映射到 MITRE T1565.001 — Stored Data Manipulation)——这是一个真实的安全检测,正确地对看起来像日志篡改的行为做出了触发反应,但实际上只是重复的测试。通过将两个工具作为稳定的、持久的后台进程运行(`nohup ... &`),而不是在前台手动重启它们,解决了这个问题。
## 阶段 5/6:狩猎
### 建立有意义的测试
最初尝试使用 Atomic Red Team 的 `T1046-10`(子网端口扫描)完全没有产生可观察到的网络流量。调查(通过在监控接口上进行实时的 `tcpdump` 捕获确认)显示,扫描几乎完全由 ARP(“谁有这个 IP?”)广播请求组成——因为实验室的 Host-only 网络只包含两台真实设备,被扫描的地址范围中绝大多数没有主机响应,因此 Windows 根本没有继续尝试对不存在的地址发起真实的 TCP/UDP 连接。这是一个真实的、有文档说明的局限性,即在小型、节点稀疏的实验室网络中测试子网范围的侦察技术时会出现这种情况,而不是工具故障。
**调整后的方法:** 直接从 Windows 10 针对 Kali(一个真实的、有响应的主机)运行了真实的端口扫描,检查了 8 个常见端口:
```
$ports = 22,80,443,445,3389,8080,3306,5432
foreach ($port in $ports) {
Test-NetConnection -ComputerName 192.168.56.1 -Port $port -InformationLevel Quiet -WarningAction SilentlyContinue
}
```
### 结果 1 —— Suricata(自动检测)
没有针对此扫描生成警报。
### 结果 2 —— Zeek(手动狩猎)
**搜索前形成的假设:** “针对真实主机的端口扫描在连接日志中应表现为:在紧凑的时间窗口内,从同一源到同一目的地、跨越不同目标端口的多个短时连接,且大多数处于被拒绝或重置状态。”
针对 Zeek 归档的连接数据**执行的搜索**:
```
agent.name:"host-kali" and data.id_orig_h:"192.168.56.102" and data.id_resp_h:"192.168.56.1" and data.conn_state:"REJ"
```
**发现:** 大约 10 次连接尝试,全部在一个约 6 秒的窗口内,全部处于 `REJ`(rejected)状态,每次都针对不同的目标端口——这是一个明确的、教科书式的侦察签名,完全是在 Suricata 零警报支持的情况下,通过对原始连接数据的手动调查发现的。
## 为什么 Suricata 会漏报:详细记录的解释
这个问题经过了适当的调查,而不是作为一个无法解释的漏洞被搁置。Suricata 默认的 Emerging Threats Open 规则集确实包含扫描检测签名——但它们明确具有**方向性**,是围绕 `$EXTERNAL_NET` 和 `$HOME_NET` 等变量编写的。以下是规则集中一条真实的代表性规则:
```
alert tcp $EXTERNAL_NET any -> $HOME_NET 3306 (msg:"ET SCAN Suspicious inbound to mySQL port 3306"; ...)
```
这条规则——以及其他类似的规则——仅对被认为**源自**受保护网络**外部**、并**指向**内部的流量触发。在本实验室中,Windows 10 和 Kali 都属于同一个内部信任的网络范围,因此它们之间的流量不符合这些签名旨在检测的“外部攻击者向内扫描”的模式。
**这是基于签名、具备方向感知能力的网络 IDS 部署中一个真实的、现实世界的盲点**:它们通常围绕攻击者从外部向内扫描的假设进行调优,导致**在已信任主机之间的内部、横向移动式扫描**在默认情况下得到的覆盖显著较少。这正是威胁狩猎旨在弥补的场景——也恰恰是本次狩猎所证明的。
## 狩猎操作手册总结
| 字段 | 详情 |
|---|---|
| **假设** | 针对真实主机的端口扫描会产生多个持续时间短、同源/同目的地、跨越不同端口的连接,时间窗口紧凑,且大多数处于 rejected/reset 状态 |
| **检查的数据源** | Zeek `conn.log`,通过 Wazuh archive index 获取 |
| **使用的搜索** | `agent.name:"host-kali" and data.id_orig_h:"192.168.56.102" and data.id_resp_h:"192.168.56.1" and data.conn_state:"REJ"` |
| **发现** | 在 6 秒时间窗口内,跨 8 个不同目标端口的约 10 次 REJ 状态连接 |
| **自动检测状态** | 未被 Suricata 标记(已加载 52,087 条规则)—— 根本原因已确认:方向性规则设计(`$EXTERNAL_NET -> $HOME_NET`)未覆盖内部到内部的扫描 |
| **结果** | 确认了横向/内部侦察的检测漏洞;记录为一个真实的、可解释的局限性,而不是工具故障 |
## 挑战与经验教训
- **Kali 从未加入现有的 VM 网络。** 通过检查 `ip a` 并发现没有与 VM 共享的子网来进行诊断;通过添加一个新的 VirtualBox Host-only Network 解决了该问题,刻意将其作为附加适配器,而不是修改现有的 Internal Network 设置,以避免破坏之前项目的连通性。
- **Suricata 的 User-Agent 欺骗和 Nmap SYN 扫描测试均未能触发任何警报**,尽管确实生成了流量并通过数据包捕获进行了确认——这是一个早期且坦诚的信号,表明“规则集没有匹配的签名”是一个真实且常见的结果,而不是设置失败,并且值得在假设 Suricata 本身损坏之前,使用受控的自定义规则(它确实正确触发了)进行验证。
- **Zeek 的 JSON 集成默默失败**,原因是带点号的字段名导致 OpenSearch 字段映射冲突——通过独立的测试找到了根本原因(没有点号的手动测试行成功了;带点号的真实 Zeek 数据没有成功),而不是靠假设,并使用 Zeek 官方文档记录的 `field_name` 机制解决了该问题。
- **在故障排除期间反复重启 Zeek 触发了合法的 Wazuh 安全规则**(“日志文件大小减小” / T1565.001)——这是一个有用的、虽然一开始令人困惑的现实提醒,即操作测试活动本身也会产生与安全相关的噪音。
- **Atomic Red Team 的子网范围扫描测试在这个特定的实验室拓扑中没有产生真实流量**,因为地址范围几乎完全未被使用;通过实时的数据包捕获(`tcpdump`)直接进行了验证,而不是靠假设,随后调整为直接针对真实主机的扫描。
## 局限性与未来工作
- 本次仅深入测试了一个狩猎假设(通过 `conn_state:REJ` 进行端口扫描模式);更全面的狩猎活动将测试多个假设(例如,通过异常长/频繁的 DNS 查询进行 DNS 隧道传输,通过定期间隔的出站连接进行 beaconing)。
- Suricata 的规则集被按原样使用(Emerging Threats Open,默认);在本次迭代中未编写针对内部到内部流量的自定义扫描检测规则,尽管调查清楚地指出了此类规则需要覆盖的内容。
- 实验室网络规模较小(2 台真实主机)限制了可以多么逼真地测试子网范围的侦察技术;一个拥有多台伪主机的大型实验室将允许进行更逼真的大规模扫描模拟。
- 除了 `conn.log` 之外,本次迭代并未探索 Zeek 更加丰富的协议级日志(DNS、HTTP、files);未来的工作可以跨这些额外的日志类型进行狩猎。
标签:AI合规, Metaprompt, 安全信息与事件管理, 安全运营中心, 插件系统, 搜索引擎爬取, 网络安全, 网络映射, 隐私保护