fabs-net/swarmnoise
GitHub: fabs-net/swarmnoise
自动从 GreyNoise Swarm 传感器收集针对 Fortinet 的攻击流量,生成可直接接入 FortiGate 防火墙的 IP 威胁情报源。
Stars: 0 | Forks: 0
# swarmnoise
自动收集器,用于获取 GreyNoise Project Swarm 传感器数据,专门针对位于德国法兰克福的传感器所观测到的针对 Fortinet 的攻击流量。
生成纯文本 IP 情报源,兼容 **FortiGate External Threat Feed**(以及任何其他通过 HTTPS 消费以换行符分隔的 IP 黑名单的防火墙)。
## 威胁情报源
### 完整情报源
```
https://raw.githubusercontent.com/fabs-net/swarmnoise/main/feeds/fortinet_ips.txt
```
过去 30 天内观测到攻击该传感器的所有源 IP。覆盖范围最广,但存在略高的误报风险。
### 过滤后的情报源
```
https://raw.githubusercontent.com/fabs-net/swarmnoise/main/feeds/fortinet_ips_filtered.txt
```
完整情报源的子集,其中会话被 GreyNoise 分类为 **malicious**。数据源自 [GreyNoise v3 Sessions API](https://docs.greynoise.io/reference/getsessions) 并通过 Lucene 查询进行过滤——不涉及任何受速率限制的富化 API。每个 IP 在 `feeds/filtered_metadata.json` 中包含富化的元数据(标签、CVE、来源地理位置、Suricata 签名)。
两种情报源均:
- 每行一个 IP,无注释,无标头
- 滚动的 30 天时间窗口 —— 超过 30 天未被观测到的 IP 会自动修剪
- 每天在随机时间更新 1 到 10 次
### FortiGate 设置
**Security Fabric → External Connectors → Threat Feeds → IP Address**
| 字段 | 值 |
|---|---|
| 名称 | `swarmnoise-fortinet` |
| URI | `https://raw.githubusercontent.com/fabs-net/swarmnoise/main/feeds/fortinet_ips.txt` |
| HTTP 基本认证 | 关闭 |
| 刷新频率 | 60 分钟 |
若要使用误报率较低的过滤情报源,请改用 `fortinet_ips_filtered.txt` 作为 URI。
然后在防火墙策略中引用此连接器,动作为 **Deny**,或在 IPS 传感器中引用。
## 工作原理
GitHub Actions 工作流**每小时**触发一次。每天 UTC 午夜时分它会:
1. 选择一个介于 **1 到 10** 之间的随机数 —— 作为当天的获取次数
2. 将这些获取任务随机分配到当天剩余的小时中
3. 将计划持久化到 `state/today.json` 中
随后的每小时检查会将当前小时与计划进行比较,并在到期时触发获取。在 `workflow_dispatch`(手动触发)时,计划检查门会被绕过,始终执行一次获取。
提交模式是**有机且不可预测的** —— 每天随机时间产生 1 到 10 次提交。
### 双 API 架构
收集器使用两个独立的 GreyNoise API 端点:
| | 完整情报源 | 过滤情报源 |
|---|---|---|
| **API** | v1 Swarm (`/v1/workspaces/{id}/sensors/activity`) | v3 Sessions (`/v3/sessions`) |
| **过滤器** | 无 —— 所有会话 | `classification:malicious`(Lucene 查询) |
| **分页大小** | 1,000 | 100 |
| **分页方式** | 30 分钟时间块(无法使用滚动令牌) | 标准基于页面的分页 |
| **元数据** | 基础(IP、端口、协议) | 丰富(标签、CVE、地理位置、Suricata) |
### 首次运行(引导)
首次运行时 `feeds/ip_metadata.json` 不存在,因此脚本会通过获取过去 30 天的数据来自动引导情报源。此过程大约需要 37 分钟(以 0.5 秒/次的速度进行 1,437 次 API 调用)。
### 分页
GreyNoise API 将每次请求的响应上限设定为 1,000 个会话。它返回的滚动/游标令牌大约为 8 KB 的 base64 数据 —— 太大而无法作为查询参数(HTTP 414)或请求标头(HTTP 400)传回。因此未使用滚动分页。
相反,每次获取的时间窗口被分割成 **30 分钟的块**。根据观测到的传感器速率(约 2,000 个会话/30 分钟),某些数据块仍然会达到 1,000 个会话的上限,这些时间窗口中的部分会话可能会被遗漏。尽管如此,IP 情报源依然全面 —— 唯一的攻击者 IP 在多次获取过程中会迅速收敛。
## 仓库结构
```
swarmnoise/
├── .github/workflows/
│ └── scheduler.yml # Hourly trigger, randomised schedule logic + fetch
├── scripts/
│ └── fetch_sessions.py # v1 full feed + v3 filtered feed, run log
├── feeds/
│ ├── fortinet_ips.txt # Full IP blocklist (one IP per line)
│ ├── fortinet_ips_filtered.txt # Filtered feed (malicious IPs only)
│ ├── ip_metadata.json # Per-IP first_seen/last_seen (full feed)
│ └── filtered_metadata.json # Per-IP enriched metadata (filtered feed)
├── runs/ # Run log JSON files (always written)
├── state/
│ └── today.json # Daily schedule state
├── requirements.txt
└── README.md
```
## 所需的 GitHub Secrets
在 **Settings → Secrets and variables → Actions** 下设置以下内容:
| Secret | 描述 |
|---|---|
| `GREYNOISE_API_KEY` | GreyNoise API 密钥 (viz.greynoise.io → Settings → API Key) |
| `WORKSPACE_ID` | GreyNoise 工作区 UUID |
| `SENSOR_ID` | Swarm 传感器 UUID (viz.greynoise.io → Observe → Sensors) |
`GITHUB_TOKEN` 会被 Actions 自动用于提交 —— 无需个人访问令牌(PAT)。
## 文件结构
**`feeds/ip_metadata.json`** —— 滚动的 30 天 IP 索引
```
{
"1.2.3.4": { "first_seen": "2026-04-05T09:00:00Z", "last_seen": "2026-05-05T10:26:00Z" }
}
```
**`runs/YYYY-MM-DD_HHMM_run_log.json`** —— 即使未发现会话也始终会写入
```
{
"timestamp": "2026-05-05T12:00:00Z",
"time_window_start": "2026-05-05T06:00:00Z",
"time_window_end": "2026-05-05T12:00:00Z",
"sessions_found": 412,
"feed_ip_count": 1349,
"filtered_ip_count": 87,
"duration_seconds": 8.3,
"error": null
}
```
**`feeds/filtered_metadata.json`** —— 每个 IP 的富化元数据(仅限过滤情报源)
```
{
"1.2.3.4": {
"first_seen": "2026-04-05T09:00:00Z",
"last_seen": "2026-05-05T10:26:00Z",
"classification": "malicious",
"tags": ["Mirai TCP Scanner", "Mirai"],
"tag_categories": ["worm"],
"tag_intentions": ["malicious"],
"cves": [],
"country": "United States",
"country_code": "US",
"asn": "AS32181",
"org": "GigeNET",
"is_vpn": false,
"is_tor": false,
"is_bot": false,
"rdns": "host.example.com",
"destination_ports": [23, 80],
"protocols": ["tcp"],
"suricata_signatures": ["Mirai TCP Scanner"]
}
}
```
## 本地查询数据
```
# 显示当前 Feed IP 数量
wc -l feeds/fortinet_ips.txt
# 显示所有恶意 IP 的 enriched metadata
jq '.' feeds/filtered_metadata.json
```
标签:CISA项目, CVE, FortiGate, Fortinet, GitHub Actions, GreyNoise, IPS, IP 地址批量处理, IP黑名单, Suricata, 外部威胁源, 威胁情报, 威胁检测与响应, 威胁源, 开发者工具, 恶意流量, 攻击流量, 数字签名, 现代安全运营, 网络传感器, 自动化采集, 自动笔记, 逆向工具, 防火墙策略