sonahangelo/acf_project
GitHub: sonahangelo/acf_project
一个结合签名规则和机器学习的自适应认知防火墙引擎,提供实时网络异常检测、iptables 拦截和可视化仪表盘。
Stars: 1 | Forks: 0
## 安全优先的部署清单
在暴露 dashboard 或启用实时拦截之前:
1. 设置真实的 dashboard 密码。除非您明确选择在本地实验室中使用,否则 ACF 现在会拒绝依赖演示密码的 dashboard 请求。
```
export ACF_DASHBOARD_PASSWORD='replace-with-a-long-random-password'
# 仅限本地课堂/demo:
# export ACF_ALLOW_DEFAULT_PASSWORD=true
```
2. 在审查您自己网络中的告警之前,请保持 `dry_run: true`。仅当您准备好让 ACF 调用 `iptables` 时,才设置 `dry_run: false`。
3. 将 `models/anomaly_model.pkl` 视为受信任的代码,因为 joblib 在内部使用 Python pickle。对于生产环境,请在 `config.yml` 中使用 `model_sha256` 锁定已训练的模型。
```
sha256sum models/anomaly_model.pkl
```
4. 将本地源 IP 威胁情报指示器添加到 `data/threat_intel.txt`,每行一个 IP 地址或 CIDR 网络。使用 `#` 保留注释。
```
203.0.113.10
198.51.100.0/24
```
5. 对于 Docker 部署,在运行 `docker compose up` 之前,请在环境中提供 `ACF_DASHBOARD_PASSWORD`。如果缺少此项,compose 文件将有意以失败关闭。
## 设置:避免使用 sudo 进行抓包
数据包捕获需要原始套接字访问权限。我们没有将其授予系统级的
Python 解释器(这会允许*任何*脚本使用原始
套接字),而是专门为 ACF 使用了一个专用的 Python 副本:
```
cp /usr/bin/python3.11 acf-env/bin/python3-acf
sudo setcap cap_net_raw,cap_net_admin=eip acf-env/bin/python3-acf
```
然后使用 `acf-env/bin/python3-acf` 而不是 `python3`
运行 ACF 命令,用于捕获/学习/检测模式:
```
acf-env/bin/python3-acf main.py --mode learn --count 5000
acf-env/bin/python3-acf main.py --mode detect
```
其他命令(训练、状态、blocklist、反馈、dashboard)不
需要原始套接字访问权限,可以继续使用常规的 `python3`。
注意:`python3-acf` 是一个真实的副本,而不是符号链接,并且不会在虚拟环境
重新创建后保留下来——如果您重建虚拟环境,请重新执行 `cp` + `setcap` 步骤。
保存并退出。
**第 2 步 — 将 `python3-acf` 添加到 `.gitignore`**(它是一个二进制副本,不应该被提交):
```
echo "acf-env/bin/python3-acf" >> .gitignore
```
**第 3 步 — 提交:**
```
git add .
git commit -m "Narrow setcap grant: use a dedicated python3-acf binary instead of the system-wide interpreter, confining raw-socket capability to just ACF"
```
粘贴确认信息——这将关闭 #4 并完成您原始列表中的所有内容。
注意:如果 Python 虚拟环境或系统 Python 版本
发生更改(例如在 `apt upgrade` 或重新创建虚拟环境之后),则必须重新应用此操作,因为
capabilities 存储在特定的二进制文件上,不会自动延续。
实时执行(`dry_run: false`)仍然需要 `sudo` 才能进行实际的
`iptables` 调用——这仅消除了在捕获、
训练和试运行检测期间对 sudo 的需求。
## 真实网络测试(局域网设备访问)
要针对来自真正外部设备(手机、另一台
PC)的流量而不是仅限 WSL 内部流量测试 ACF:
1. 查找您的 Windows 主机的局域网 IP:`ipconfig` (PowerShell) -> IPv4 地址
2. 通过 Windows 将 dashboard 端口转发到 WSL(提升权限的 PowerShell):
netsh interface portproxy add v4tov4 listenport=5050 listenaddress=0.0.0.0 connectport=5050 connectaddress=
New-NetFirewallRule -DisplayName "ACF Dashboard" -Direction Inbound -LocalPort 5050 -Protocol TCP -Action Allow
3. 将 Flask 绑定到 `0.0.0.0`(在 app.py 中已经是默认设置)
4. 运行 `main.py --mode detect` 和 `app.py` 来捕获流量
5. 从另一台设备通过 `http://:5050` 访问
注意:WSL IP 在重启时会发生变化,因此 portproxy 规则每次
都需要更新。完成测试后移除这两个规则(参见上面的命令,使用
`delete`/`Remove-NetFirewallRule`)以避免不必要地保持端口开放。
曾尝试将镜像网络模式(`.wslconfig` 中的 `networkingMode=mirrored`)作为
替代方案,但在当前设置中失败并出现错误 0x8007054f
(可能是 Hyper-V/VPN/防火墙冲突)——因此改为使用上述
portproxy 方法,并成功验证了真实外部设备流量
到达 ACF 的捕获管道。
## 作为后台服务运行 (systemd)
ACF 可以通过 systemd 持续运行,而无需手动终端会话:
```
sudo systemctl start acf-detect.service # detection engine
sudo systemctl start acf-dashboard.service # web dashboard
sudo systemctl enable acf-detect.service # auto-start on WSL boot
sudo systemctl enable acf-dashboard.service
```
检查状态:`./acf_service_status.sh`
查看日志:`sudo journalctl -u acf-detect.service -f`(添加 `-f` 以实时跟踪)
停止:`sudo systemctl stop acf-detect.service` / `acf-dashboard.service`
两个服务在崩溃时都会自动重启(延迟 5 秒)。服务文件位于
`/etc/systemd/system/acf-detect.service` 和 `acf-dashboard.service`。
注意:WSL 本身必须处于运行状态这些服务才能激活——它们在
WSL 启动时启动,不一定在 Windows 引导时启动,除非 WSL
被单独配置为自动启动。
## ARP 欺骗检测
ACF 还会监控 ARP 流量以发现 IP 到 MAC 绑定冲突——这是
ARP 欺骗的经典特征(攻击者冒充另一台
设备,通常是网关,以进行中间人拦截)。
重要提示:这仅用于检测/告警,而不是预防。ARP 欺骗
是一种二层攻击;通过 iptables(三层)拦截违规 IP 并
不能阻止它,因为攻击者仍然存在于您的本地网络
网段上。真正的缓解措施需要交换机级别的保护(动态
ARP 检查)或为您的网关等关键主机设置静态 ARP 条目。
需要捕获 ARP 流量:config.yml 中的 `bpf_filter` 必须包含
`arp`(默认值:`"arp or ip"`)。
## DNS 隧道检测
监控 DNS 查询中经典的隧道特征:将数据编码为
一个基础域名下的许多唯一、随机的子域名
(例如 `a8f3k2x9.tunnel.evil.com`、`b91d7xq2.tunnel.evil.com` 等)。
两个独立的信号,任何一个都会触发告警:
1. 来自一个源的一个基础域名下有许多不同的子域名,
且查询速度很快(默认:10 秒内 15 次以上)
2. 单个高熵、长子域名标签(默认:20 个字符以上,
熵 >= 3.5 比特/字符)——看起来像 base32/64 编码的数据
可通过 config.yml 中的 dns_window_seconds、dns_min_distinct_subdomains、
dns_entropy_threshold、dns_min_label_length 进行调整。
实时验证:在一个虚假基础域名下使用随机子域名精心构造了 20 个 DNS 查询,
恰好在配置的阈值(第 15 个不同的子域名)处触发。
## 隐秘扫描检测 (NULL/FIN/XMAS)
捕获 nmap 的隐秘扫描技术(-sN、-sF、-sX),这些技术故意
避免正常的 SYN,专门为了规避基于 SYN 的扫描/泛洪检测器:
- NULL 扫描:完全没有设置任何标志的 TCP 数据包
- FIN 扫描:仅设置了 FIN 标志(没有 ACK——正常的连接关闭
是 FIN+ACK,这不会被标记)
- XMAS 扫描:FIN+PSH+URG 全部一起设置
这些标志组合在合法流量中基本上不会出现,因此
这是一种无状态、即时的检查(不需要跟踪窗口)——
直接添加到 check_hybrid_rules() 中,而不是像 ARP/DNS 需要
的单独跟踪器模块。
使用针对非白名单回环地址的真实 nmap -sN/-sF/-sX 扫描进行了实时验证;通过捕获的流量(正确的标志值:
''、'F'、'FPU')和记录了正确原因的告警进行了确认。
## ICMP 泛洪(Ping 泛洪)检测
跟踪每个源 IP 的 ICMP 回显请求速率(默认:5 秒内 50 次以上
触发告警),重用了与 SYN 泛洪跟踪
相同的滑动窗口技术。
关于实时验证的诚实说明:经过测试时(向非白名单目标发送 60 个精心构造的 ICMP 数据包),告警
正确地触发了,但实际上是被基础 ML 异常模型捕获的,而不是 icmp_flood 规则具体
捕获的——因为训练数据通常包含接近于零的 ICMP 流量,所以
即使是单个 ICMP 数据包在模型看来也已经在统计学上
异常了,远早于达到规则的体积阈值。该规则
本身通过单元测试(隔离的、确定性的)确认为正确,
并作为后盾:如果训练数据稍后包含一些正常的
ICMP 流量(例如,您偶尔 ping 某些东西),ML 模型的
敏感度将恢复正常,而基于规则的阈值将成为
防御真实泛洪的主要手段。
## 暴力破解登录检测
监控对已知身份验证端口的重复连接尝试
(SSH 22、Telnet 23、FTP 21、RDP 3389、MySQL 3306、PostgreSQL 5432、
MSSQL 1433、VNC 5900),使用比通用 repeated_port_probe 规则更低/更快的阈值(默认:5 次尝试),因为真实的
暴力破解工具会非常快速地访问这些端口。
在通用端口探测规则之前进行检查,因此对已知身份验证
端口的匹配会获得更具体的“brute_force”标签,而不是通用的
那个标签,即使两个阈值在技术上都可以被跨越。
可通过 config.yml 中的 brute_force_ports(列表)和 brute_force_threshold
进行配置。
实时验证:使用 hping3 模拟 SSH 暴力破解(10 个快速 SYN
数据包到端口 22),恰好在配置的
阈值(第 5 次尝试)处触发,并且在告警中确定了特定端口。
## 无效的 TCP 标志组合
检测在真实网络堆栈中永远不会出现的逻辑上自相矛盾的 TCP 标志组合——仅来自用于
防火墙/IDS 规避或 OS 指纹识别的数据包构造工具:
- SYN+FIN:一个声称同时打开和关闭连接的数据包
- SYN+RST:一个声称同时打开和中止连接的数据包
与 check_hybrid_rules() 中现有的 NULL/FIN/XMAS 隐秘扫描检测一起
检查——采用相同的无状态、即时检查模式。
实时验证:通过 Scapy 针对非白名单
回环目标精心构造 SYN+FIN 数据包,正确触发并识别出具体原因。
SYN+RST 使用相同的逻辑(通过单元测试确认);实时确认
由于 blocklist 去重正确地抑制了在同一
进程生命周期内对已被拦截的测试源 IP 的重复告警而变得复杂——这是一个已知的、正确的行为,而不是检测漏洞。
## 基于 TTL 的 IP 欺骗检测
真实主机发送的数据包具有一致的 TTL,源自固定的 OS
起始值(Linux/Mac 为 64,Windows 为 128,某些网络设备为 255)减去
稳定网络路径上的跳数。如果相同的源 IP 突然显示出
截然不同的 TTL,那就是 IP 欺骗的强烈信号——
攻击者的实际路径/OS 与真实主机的
不匹配。
镜像了 arp_monitor.py 的设计:每个 IP 的基准 TTL 在首次出现时固定,标记超出 ttl_anomaly_threshold 的偏差(默认值:20)。
局限性:合法的路由更改偶尔会使 TTL 移动
几跳(罕见的误报);基准不会随时间推移而适应。
实时验证:精心构造了两个具有相同欺骗源 IP
但 TTL 分别为 64 和 128 的 ICMP 数据包——正确触发,并在
告警原因中包含了确切的基准
和差异值。
注意:此会话还暴露了一类真实的反复出现的 bug——在 db.py 中向 TRAFFIC_COLUMNS 添加一
列不会追溯性地更改已经创建的 SQLite 表(CREATE TABLE IF NOT EXISTS 在现有表上是空操作)。通过重新创建数据库修复;添加了一个永久测试
(test_traffic_columns_match_actual_db_schema),用于检查新创建的
表的真实 schema 与 TRAFFIC_COLUMNS 是否一致。这捕获了
Python 列表与新表不匹配的情况,但不能捕获“已部署的数据库已过时”——
当 TRAFFIC_COLUMNS 发生变化时,必须重新创建数据库(如果数据
很重要,请先通过 retention.py 进行备份/
归档)。
## Smurf 攻击检测
检测针对广播地址(255.255.255.255
或 x.x.x.255 样式的子网广播)的 ICMP 回显请求。在真实的 smurf 攻击中,这是
使用欺骗源(受害者的 IP)发送到网络的广播
地址,导致该网络上的每台主机都向受害者回复——
从而放大流量。合法主机基本上永远不会 ping 广播
地址,因此这是一种可靠的无状态信号(与隐秘扫描和无效标志检查的模式相同——不需要跟踪器)。
实时验证:通过 Scapy 精心构造了发往 255.255.255.255 的 回显,
正确触发,并在告警原因中识别出了目标地址。
注意:发往广播的数据包通过默认接口 (eth0) 路由,
而不是 loopback,无论 ACF 的配置接口设置如何——这在最初的实时测试中绊倒了(当 interface="lo" 时发送的数据包
从未被捕获,因为它们根本没有接触到 loopback 接口)。
在调试期间通过 tcpdump -i any 确认。对于任何
未来与广播相关的测试,值得记住这一点。
## Slowloris 检测
检测“许多缓慢涓涓细流般的连接”特征:与泛洪(许多数据包快速发送)不同,Slowloris 打开许多到同一目标端口的连接,并以最少的数据保持它们打开,在不看起来像体积攻击的情况下耗尽
服务器的连接池。
FlowTracker 计算每个(源、目标、端口)有多少当前
活动的流同时具有长持续时间(默认:30 秒以上)和非常低
的字节速率(默认:<=100 字节/秒)。slowloris_min_connections(默认:
10)设置了触发告警的此类缓慢流的数量。
关于实时验证的诚实说明:底层的 slow_flow_count 计算
已完全验证——通过单元测试以及对 check_hybrid_rules() 使用真实特征值(低 port_repeat_count,
高 slow_flow_count)的直接隔离调用进行了确认,这正确地以正确的原因触发了。
然而,实时端到端模拟(精心构造 SYN+ACK 对来模拟保持打开的连接)也碰巧触发了
repeated_port_probe 规则,该规则在 check_hybrid_rules 中较早被检查
并首先返回。这是 SYN 重复模拟
方法的属性,而不是 Slowloris 检测中的缺陷——真正的 Slowloris 攻击
每个连接只发送一个 SYN(没有重复),所以它根本不会触发
repeated_port_probe,而 slowloris 将是实践中捕获
它的规则。直截了当地记录下来,而不是声称产生了特定测试场景实际上并未产生的实时端到端
告警。
测试期间还发现:通过 bash heredoc 管道传输给 sudo 来发送定时脚本可能会悄无声息地破坏 time.sleep() 的时序(所有数据包
最终聚集在一起而不是散开)——可能是 stdin/pipe
交互所致。将脚本保存到文件并直接运行它
(sudo /path/to/script.py)可靠地解决了这个问题。
## 流氓 DHCP 服务器检测
跟踪哪些 IP 已被观察到发送 DHCP 服务器响应
(OFFER 或 ACK 消息)。大多数家庭/小型网络恰好只有一台
合法的 DHCP 服务器(路由器)。如果第二个、不同的 IP 突然
开始作为 DHCP 服务器响应,那就会被标记为可能的流氓
DHCP 服务器——一种常见的中间人技术,因为恶意
服务器可以将假网关或 DNS 服务器分发给任何加入网络的新设备。
镜像了 arp_monitor.py 的设计:看到的第一台服务器建立
基准(不被标记),之后的任何不同的服务器都会被标记。
局限性:合法的 DHCP 故障转移/冗余设置(设计上有多个真实
服务器)会在第二个合法服务器上导致一次性误报。
关于实时验证的诚实说明:在此环境中,WSL 的虚拟网络完全阻止了出站
UDP 广播流量(通过 tcpdump -i any 确认,显示 ANY 广播 UDP 的数据包为零,不仅仅是
DHCP 端口特定或欺骗源数据包——也使用不相关的端口/有效载荷进行了
测试)。这是一个真实的环境限制,
而不是检测缺陷。ICMP 广播(用于 smurf 攻击测试)
在同一环境中运行良好,因此该限制似乎是特定于 UDP 广播的。
检测逻辑本身确实得到了验证:直接调用 check_rogue_dhcp() 处理了
真实的、正确构造的 Scapy DHCP 数据包对象(仅绕过了 WSL 阻止的网络传输步骤),确认了
正确的解析、基准建立以及带有确切预期原因文本的流氓服务器标记。这执行了与实时捕获使用的相同的代码路径——只是不需要数据包穿过 WSL 的
网络堆栈,而这在此设置中对于广播 UDP 是不可能的。
标签:Apex, iptables, 威胁情报, 开发者工具, 异常检测, 机器学习, 红队行动, 网络安全, 请求拦截, 逆向工具, 防火墙, 隐私保护