deaconsec/suricata-detection-lab
GitHub: deaconsec/suricata-detection-lab
基于 pfSense 分段网络和 Suricata 构建的跨网段 IDS 实验室,演示了从攻击检测到自定义规则工程的完整蓝队实践流程。
Stars: 0 | Forks: 0
# Suricata 检测实验室 - 基于 pfSense 的跨网段 IDS
在现有的分段 pfSense 实验室中构建基于网络的入侵检测链路。脆弱的 Web 服务 (DVWA) 受到来自不受信任网段的攻击;Suricata 会检查跨网段流量。文中记录了三个检测案例,以及通过编写自定义规则独立修复检测漏洞的过程。
本实验室建立在 [`network-segmentation-pfsense`](#) 的基础之上,并补充了防御/蓝队方面的内容:不仅是分段隔离,还实现了检测。
## 结果!
- **在现有网络分段基础上构建了可正常运行的跨网段检测流水线**
- **记录了三个检测案例:侦察 (nmap)、漏洞扫描 (nikto)、SQLi 攻击 (sqlmap)**
- **独立诊断出的检测漏洞(ET Open 与具体的 UNION-SELECT 特征之间的覆盖缺失)**
- **编写、调试并验证了自定义的 Suricata 规则签名**
## 拓扑结构
所有组件均虚拟化运行在同一宿主机上 (KVM/QEMU),pfSense 作为一台配有四个 libvirt 网络的虚拟机运行。
| 网段 | 子网 | 角色 |
|------------|------------------|----------------------------------------------|
| GUEST | 10.10.20.0/24 | 攻击者 (Kali, 10.10.20.100) |
| PRODUCTION | 10.10.40.0/24 | 目标 (Ubuntu Server + DVWA, 10.10.40.100) |
| MGMT | 10.10.50.0/24 | 管理 |
Suricata 以 **IDS 模式**(仅告警,不阻断)运行在 **PRODUCTION 接口** (vtnet3) 上。
原因:需要监控的是受保护的区域,而非攻击源。从 GUEST 到 PRODUCTION 的攻击流量必然经过 pfSense,并在该处接受检查。
## 架构搭建
### 1. 防火墙 - 在保持默认拒绝原则的前提下设定严格放行例外
攻击路径仅需一条穿过网段边界的通道。我们没有将 GUEST 对 PRODUCTION 的访问权限完全敞开,而是设定了最小化的放行例外:
仅限单一主机、单一端口。

- **放行 (Pass):** GUEST 主机 10.10.20.100 → 10.10.40.100,**仅限 TCP/80**
- 网段之间其余的 Implicit Deny 规则保持不变。
- 注意规则顺序(首条匹配优先生效):放行规则必须位于**现有**的阻止规则**之上**,否则会优先触发阻断。

此外,还对 PRODUCTION 的出站流量进行了安全加固(此前该网段处于完全的 Default-Deny 状态,无法访问互联网):
- **阻断 (Block):** PRODUCTION → GUEST 以及 PRODUCTION → MGMT(防止 Lateral Movement)
- **放行 (Pass):** PRODUCTION → any(受控的互联网访问,用于拉取软件包/镜像)
规则构建逻辑:将用于阻止 Lateral Movement 的 Block 规则放置在宽泛的互联网 Pass 规则之前。不受欢迎的内部目标会在触发放行规则之前被拦截。这体现了“防止 Lateral Movement”的原则。

### 2. 脆弱的目标主机
位于 PRODUCTION 网段的 Ubuntu Server (10.10.40.100,由 pfSense 通过 DHCP 分配)。

DVWA 作为 Docker 容器运行,方便复现且可随时销毁重建。端口映射 `-p 80:80` 使得 DVWA 可以在 10.10.40.100:80 上被访问,这正是防火墙放行例外所针对的地址:
```
sudo docker run -d -p 80:80 --name dvwa vulnerables/web-dvwa
```

从 Kali 确认了连通性,跨网段访问正常工作:

### 3. Suricata
在 pfSense 上安装组件,选用接口 PRODUCTION,运行模式为 IDS。

规则集:**ET Open** (Emerging Threats Open)。pfSense 本身也提示,其覆盖范围不如 ETPro 广。这一点在后续操作中变得尤为关键:


由于使用的是虚拟网卡,我们禁用了 Hardware Offloading (Checksum/TSO/LRO),否则 Suricata 会观察到不完整的数据包。接口已正常运行,Blocking 已被禁用(纯 IDS 模式):

## 检测案例
### 案例 1 - 侦察 (nmap)
完整的扫描起初被防火墙拦截。nmap 的主机发现机制 发被最小权限规则(仅允许 TCP/80)阻断,对目标的 Ping 请求没有响应,因此主机显示为“宕机 (down)”。


使用 `-Pn` 跳过主机发现,`-p80` 针对被允许的端口,扫描得以通过并成功识别出 Apache 2.4.25:

Suricata 告警:**`1:2024364 ET SCAN Possible Nmap User-Agent Observed`**
(属于 `emerging-scan.rules` 类别)。该规则匹配 `http.user_agent` 中的 `content:"|20|Nmap"` - 即检测发生在 Layer 7,基于 HTTP 探测的 User-Agent 进行识别,而不是依赖传统的端口扫描启发式算法。这就是为什么即使是单端口扫描也能被检测到的根本原因。

### 案例 2 - Web 漏洞扫描器 (nikto)
```
nikto -h http://10.10.40.100
```

在三个类别中产生了广泛的告警:
- **Web-Attack (Pri 1):** 针对 ColdFusion、WordPress 插件的探测 (ET WEB_SERVER / WEB_SPECIFIC_APPS)。注意:DVWA 并未运行这些软件 - Suricata 是针对流量中的*尝试行为*进行告警,与目标处是否攻击成功无关。
- **协议异常 (Pri 3):** SURICATA 自带的引擎识别出错误的 HTTP 请求(模糊/无效的 Host header)。
- **Info (Pri 3):** Spring-Boot-Actuator 探测。
SOC 分析定性:这不是一次针对性的单点攻击,而是一个在几秒钟内发射大量 Web 探测的源 = 自动化扫描器。这些事件通过告警关联被归纳为单一的安全事件。

### 案例 3 - 针对性 SQL 注入 (sqlmap)
```
sqlmap -u "http://10.10.40.100/vulnerabilities/sqli/?id=1&Submit=Submit" --cookie="PHPSESSID=; security=low" --batch --dbs
```
`id` 参数可以通过四种技术进行注入(布尔盲注、报错注入、时间盲注、UNION query);后端数据库、Web 服务器 (Apache 2.4.25) 和操作系统 (Debian 9) 信息均被成功读取。sqlmap 在启发式扫描中还报告该参数可能存在 XSS 漏洞。由于重点关注的是 SQLi 检测,此处未对该发现做进一步深入。

## 检测漏洞与自定义规则
**现象:** 成功的 sqlmap 攻击(包含 SQLi payload 的 146 个 HTTP 请求)**未**产生任何 SQL 注入告警,尽管 Suricata 能够看到这些流量(同时进行的 nmap 依然触发了告警 - 证明流水线完好)。
**原因:** 当前激活的 ET Open 规则中,没有任何一条能匹配这种具体的攻击模式:
- `emerging-sql` 规则针对的是**直接的数据库流量**(`$SQL_SERVERS`,端口 1433/3306)- 而不是针对 80 端口 HTTP 参数中的 SQLi。

- 虽然也存在一些通用的 SQLi Web 规则(`ET WEB_SERVER SQLi`,`ATTACKER SQLi`),但它们匹配的是其他模式(如 `SELECT and sysobject`,`Schema Columns`),或者部分在默认情况下处于禁用状态 - 没有一条规则能够捕获 HTTP URI 中具体的 `UNION SELECT` 字符串。

这是开源规则集在面对通用 Web SQLi 时存在的真实覆盖盲区(ET Open 自身也提示了其覆盖范围受限),并非配置错误。

**解决方案 - 编写自定义签名** (`custom.rules`):
```
alert http any any -> $HOME_NET any (msg:"LOCAL SQLi UNION SELECT detected in HTTP request"; flow:established,to_server; http.uri; content:"UNION"; nocase; content:"SELECT"; nocase; distance:0; classtype:web-application-attack; sid:1000001; rev:1;)
```
逻辑分析:如果发往 `$HOME_NET` 的已建立 HTTP 请求中,URI 包含紧跟 `SELECT` 的 `UNION`(不区分大小写,`distance:0` 允许匹配 `UNION ALL SELECT`),则触发告警。这种特征模式在合法请求中几乎不存在 → 因此误报率极低。SID 设定为 1000001(本地规则范围 ≥ 1000000)。

**调试:** 规则的第一版未能加载。排查步骤如下:
1. 使用保证可被读取的 payload 进行 curl 测试,排除了编码问题的可能。
2. 启动日志 (`suricata.log`) 显示了两个解析错误:将方向操作符错写成了 `>` 而不是 `->`,以及 `msg` 字段后漏掉了冒号 `:`。
3. 修复后,规则顺利加载(错误日志行消失)

**验证:** 使用保证可被明文读取的 payload:
```
curl "http://10.10.40.100/vulnerabilities/sqli/?id=1+UNION+SELECT+1,2&Submit=Submit" --cookie "PHPSESSID=; security=low"
```

**结果:** 自定义签名可靠地触发了告警 -
**`1:1000001 LOCAL SQLi UNION SELECT detected in HTTP request`**:


**规则的局限性(已知):** 它仅涵盖了 UNION 注入这种变体。
报错注入(`EXTRACTVALUE`)、时间盲注(`SLEEP`)和布尔盲注(`OR NOT ...`)并不包含 `UNION SELECT`,因此需要编写其他的自定义签名。我们优先考虑编写命中率精确的规则,而不是包含过多判断条件、容易导致误报的臃肿规则。
## 技术侧重点
- 防火墙(pfSense,最小权限规则,Lateral-Movement 阻断)·
- IPS/IDS(Suricata,接口布局选择,规则分类)·
- Detection Engineering(签名构建,自定义规则,通过日志排错)·
- 同一核心逻辑中体现的攻防双重视角
标签:CISA项目, DOE合作, Metaprompt, pfSense, Suricata, 插件系统, 现代安全运营, 网络安全, 网络流量分析, 虚拟化实验环境, 请求拦截, 隐私保护