关于 detecting-network-anomalies-with-zeek
面向安全运营与网络防御人员的 Zeek 被动网络监测实践指南,说明如何生成协议元数据日志、编写自定义检测并开展威胁狩猎。它侧重可观测性与分析,不用于主动阻断流量。
主要功能
- 01生成连接、DNS、HTTP 等日志
- 02编写自定义 Zeek 检测脚本
- 03通过日志开展威胁狩猎
- 04将日志发送到 SIEM
- 05使用 Notice 和 SumStats 检测异常
适用场景
- 01监测网络出口流量
- 02查找 DNS 隧道或信标活动
- 03回溯分析安全事件
- 04将网络元数据接入 SIEM
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ mukul975/ anthropic-cybersecurity-skills --skill detecting-network-anomalies-with-zeek安装后在 Claude Code 中输入/detecting-network-anomalies-with-zeek确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
LICENSEreferences/api-reference.mdscripts/agent.py详细介绍
使用 Zeek 检测网络异常
何时使用
- 在网络关键咽喉点部署被动网络安全监控,以获得持续可见性
- 生成结构化的连接、DNS、HTTP、SSL 和文件传输日志,用于 SIEM 接入和威胁狩猎
- 编写自定义 Zeek 脚本,以检测组织特有的威胁、策略违规或信标行为
- 对网络元数据执行回顾性分析,以调查安全事件
- 通过协议级元数据分析补充 IDS 解决方案,覆盖基于签名的工具可能遗漏的内容
不要使用 作为可主动阻断流量的内联 IDS/IPS 的替代品,用于在没有 TLS 检查的情况下监控加密载荷,或用在基于主机的 Agent 更合适的端点上。
先决条件
- 从源码或包管理器安装 Zeek 6.0+(
zeek --version) - 在 span 端口、网络分路器或虚拟交换机镜像上配置网络接口,以进行被动捕获
- 为日志文件准备足够的磁盘存储(估计每 100 Mbps 被监控流量每天 1-5 GB)
- 熟悉 Zeek 的脚本语言,以编写自定义检测
- 用于集中分析的日志聚合系统(Splunk、Elastic、Graylog)
工作流
步骤 1:安装并配置 Zeek
# Install Zeek on Ubuntu/Debian
sudo apt install -y zeek
# Or install from source for latest version
git clone --recursive https://github.com/zeek/zeek
cd zeek && ./configure --prefix=/opt/zeek && make -j$(nproc) && sudo make install
export PATH=/opt/zeek/bin:$PATH
# Configure the monitoring interface
sudo vi /opt/zeek/etc/node.cfg
# /opt/zeek/etc/node.cfg
[zeek]
type=standalone
host=localhost
interface=eth1
# Configure local network definitions
sudo vi /opt/zeek/etc/networks.cfg
# /opt/zeek/etc/networks.cfg
10.0.0.0/8 Internal
172.16.0.0/12 Internal
192.168.0.0/16 Internal
# Disable NIC offloading for accurate packet capture
sudo ethtool -K eth1 rx off tx off gro off lro off tso off gso off
# Deploy Zeek
sudo zeekctl deploy
# Verify Zeek is running
sudo zeekctl status
步骤 2:理解并浏览 Zeek 日志
# Zeek generates structured log files in /opt/zeek/logs/current/
ls /opt/zeek/logs/current/
# Key log files:
# conn.log - All network connections (TCP, UDP, ICMP)
# dns.log - DNS queries and responses
# http.log - HTTP requests and responses
# ssl.log - SSL/TLS handshake details
# files.log - File transfers observed on the network
# notice.log - Alerts from Zeek detection scripts
# weird.log - Protocol anomalies and errors
# x509.log - X.509 certificate details
# smtp.log - SMTP email transactions
# ssh.log - SSH connection details
# View connection log with zeek-cut for column selection
cat /opt/zeek/logs/current/conn.log | zeek-cut ts id.orig_h id.orig_p id.resp_h id.resp_p proto service duration orig_bytes resp_bytes
# View DNS log
cat /opt/zeek/logs/current/dns.log | zeek-cut ts id.orig_h query qtype_name answers
# View HTTP log
cat /opt/zeek/logs/current/http.log | zeek-cut ts id.orig_h host uri method status_code user_agent
步骤 3:编写自定义检测脚本
# Create a custom detection script directory
sudo mkdir -p /opt/zeek/share/zeek/site/custom-detections
创建一个用于检测 DNS 隧道的脚本:
# /opt/zeek/share/zeek/site/custom-detections/dns-tunneling.zeek
@load base/frameworks/notice
module DNSTunneling;
export {
redef enum Notice::Type += {
DNS_Tunneling_Detected,
DNS_Long_Query
};
# Threshold: number of unique queries per source in time window
const query_threshold: count = 200 &redef;
const time_window: interval = 5min &redef;
const max_query_length: count = 50 &redef;
}
# Track query counts per source IP
global dns_query_counts: table[addr] of count &create_expire=5min &default=0;
event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
{
local src = c$id$orig_h;
# Check for unusually long domain queries (base64-encoded data)
if ( |query| > max_query_length )
{
NOTICE([
$note=DNS_Long_Query,
$msg=fmt("Unusually long DNS query from %s: %s (%d chars)", src, query, |query|),
$src=src,
$identifier=cat(src, query)
]);
}
# Track query volume per source
dns_query_counts[src] += 1;
if ( dns_query_counts[src] == query_threshold )
{
NOTICE([
$note=DNS_Tunneling_Detected,
$msg=fmt("Possible DNS tunneling: %s sent %d queries in %s", src, query_threshold, time_window),
$src=src,
$identifier=cat(src)
]);
}
}
创建一个用于检测信标行为的脚本:
# /opt/zeek/share/zeek/site/custom-detections/beacon-detection.zeek
@load base/frameworks/notice
@load base/frameworks/sumstats
module BeaconDetection;
export {
redef enum Notice::Type += {
Possible_Beaconing
};
const beacon_threshold: count = 50 &redef;
const observation_window: interval = 1hr &redef;
}
event zeek_init()
{
local r1 = SumStats::Reducer(
$stream="beacon.connections",
$apply=set(SumStats::SUM)
);
SumStats::create([
$name="detect-beaconing",
$epoch=observation_window,
$reducers=set(r1),
$threshold_val(key: SumStats::Key, result: SumStats::Result) = {
return result["beacon.connections"]$sum;
},
$threshold=beacon_threshold + 0.0,
$threshold_crossed(key: SumStats::Key, result: SumStats::Result) = {
NOTICE([
$note=Possible_Beaconing,
$msg=fmt("Possible beaconing: %s made %d connections in %s",
key$str, result["beacon.connections"]$sum, observation_window),
$identifier=key$str
]);
}
]);
}
event connection_state_remove(c: connection)
{
if ( c$id$resp_h !in Site::local_nets )
{
local key = fmt("%s->%s:%d", c$id$orig_h, c$id$resp_h, c$id$resp_p);
SumStats::observe("beacon.connections", [$str=key], [$num=1]);
}
}
步骤 4:加载自定义脚本并部署
# Add custom scripts to local.zeek
sudo tee -a /opt/zeek/share/zeek/site/local.zeek << 'EOF'
# Custom detection scripts
@load custom-detections/dns-tunneling.zeek
@load custom-detections/beacon-detection.zeek
# Enable additional protocol analyzers
@load protocols/ftp/software
@load protocols/http/software
@load protocols/smtp/software
@load protocols/ssh/detect-bruteforcing
@load protocols/ssl/validate-certs
@load protocols/ssl/log-hostcerts-only
@load protocols/dns/detect-external-names
# Enable file extraction
@load frameworks/files/extract-all-files
# Enable Intel framework for threat intelligence
@load frameworks/intel/seen
@load frameworks/intel/do_notice
EOF
# Reload Zeek configuration
sudo zeekctl deploy
# Verify scripts loaded without errors
sudo zeekctl diag
步骤 5:对 Zeek 日志执行威胁狩猎查询
# Find long-duration connections (possible C2)
cat /opt/zeek/logs/current/conn.log | zeek-cut ts id.orig_h id.resp_h id.resp_p duration | \
awk '$5 > 3600 {print $0}' | sort -t$'\t' -k5 -rn | head -20
# Find connections with high data transfer volumes
cat /opt/zeek/logs/current/conn.log | zeek-cut ts id.orig_h id.resp_h orig_bytes resp_bytes | \
awk '$4 > 100000000 || $5 > 100000000 {print $0}'
# Identify rare user agents (potential malware)
cat /opt/zeek/logs/current/http.log | zeek-cut user_agent | sort | uniq -c | sort -n | head -20
# Find self-signed or expired certificates
cat /opt/zeek/logs/current/ssl.log | zeek-cut ts id.orig_h id.resp_h server_name validation_status | \
grep -v "ok"
# Detect DNS queries to newly registered domains (DGA patterns)
cat /opt/zeek/logs/current/dns.log | zeek-cut ts id.orig_h query | \
awk -F'\t' '{n=split($3,a,"."); if(length(a[n-1]) > 10) print $0}'
# Find SSH brute force attempts
cat /opt/zeek/logs/current/ssh.log | zeek-cut ts id.orig_h id.resp_h auth_success | \
grep "F" | awk '{print $2}' | sort | uniq -c | sort -rn | head -10
# Identify unusual port usage
cat /opt/zeek/logs/current/conn.log | zeek-cut id.resp_p proto service | \
sort | uniq -c | sort -rn | head -50
步骤 6:与 SIEM 集成并设置告警
# Configure JSON log output for SIEM ingestion
sudo tee /opt/zeek/share/zeek/site/json-logs.zeek << 'EOF'
@load policy/tuning/json-logs.zeek
redef LogAscii::use_json = T;
EOF
# Forward logs to Elastic via Filebeat
# /etc/filebeat/filebeat.yml
sudo tee /etc/filebeat/filebeat.yml << 'EOF'
filebeat.inputs:
- type: log
enabled: true
paths:
- /opt/zeek/logs/current/*.log
json.keys_under_root: true
json.add_error_key: true
fields:
source: zeek
fields_under_root: true
output.elasticsearch:
hosts: ["https://elastic-siem:9200"]
index: "zeek-%{+yyyy.MM.dd}"
username: "elastic"
password: "${ES_PASSWORD}"
EOF
sudo systemctl enable --now filebeat
# Set up log rotation
sudo tee /etc/cron.d/zeek-logrotate << 'EOF'
0 0 * * * root /opt/zeek/bin/zeekctl cron
EOF
# Monitor Zeek health
sudo zeekctl status
sudo zeekctl netstats
关键概念
| 术语 | 定义 |
|---|---|
| 网络安全监控器 | 被动分析工具,观察网络流量并生成结构化元数据日志,而不更改或阻断流量 |
| Zeek 脚本 | 使用 Zeek 领域特定语言编写的事件驱动脚本,用于处理网络事件并生成通知、日志和指标 |
| 连接日志(conn.log) | Zeek 的核心日志,记录每个观察到的连接及其源/目标 IP、端口、协议、持续时间和字节数 |
| Notice Framework | Zeek 的子系统,用于在检测脚本识别到可疑活动时生成告警,并输出到 notice.log |
| SumStats Framework | Zeek 中的统计分析框架,用于跨时间窗口跟踪指标,从而支持基于阈值的异常检测 |
| Intel Framework | Zeek 模块,用于将观察到的网络指标与威胁情报源进行匹配,并在匹配时生成告警 |
工具与系统
- Zeek 6.0+:开源网络安全监控器,通过被动流量分析生成全面的协议级日志
- zeek-cut:Zeek 实用工具,用于从制表符分隔的 Zeek 日志文件中提取特定列以进行快速分析
- zeekctl:Zeek 管理工具,用于在单机或集群部署中部署、监控和管理 Zeek 实例
- RITA(Real Intelligence Threat Analytics):开源工具,用于分析 Zeek 日志中的信标、DNS 隧道和其他威胁指标
- Filebeat:Elastic Agent,用于将 Zeek JSON 日志发送到 Elasticsearch,以进行集中分析和可视化
常见场景
场景:检测企业流量中的命令与控制信标
背景:一份威胁情报报告指出,某个特定的威胁行为者使用 60 秒间隔的 HTTPS 信标与受感染主机通信。SOC 团队需要分析 Zeek 日志,以在承载 2 Gbps 流量的企业网络中识别出表现出此模式的主机。
方法:
- 在互联网出口点的网络分路器上部署 Zeek,并使用 AF_PACKET 进行高吞吐量捕获
- 启用自定义信标检测脚本,将阈值调整为针对 60 秒间隔、1 小时观察窗口
- 查询 conn.log,寻找与外部 IP 的连接,这些连接具有一致的持续时间和连接间时序:筛选出连接间到达时间标准差小于 5 秒的连接
- 将可疑目标 IP 与加载到 Zeek 的 Intel 框架中的威胁情报源进行交叉比对
- 检查 ssl.log 中的相关 TLS 证书——检查自签名证书、异常颁发者名称或有效期较短的证书
- 为每个识别出的信标源生成通知,并送入 SIEM 以供 SOC 分诊
陷阱:
- 未针对环境调整信标检测阈值,导致来自合法更新服务(Windows Update、AV 更新)的误报
- 未能排除天然会接收大量重复连接的 CDN 和云服务提供商 IP 范围
- 运行 Zeek 时 CPU 核心不足,导致高吞吐量链路上出现丢包
- 未启用 JSON 日志输出,使 SIEM 集成因需要自定义解析器而变得不必要地复杂
输出格式
## Zeek Network Anomaly Detection Report
**Sensor**: zeek-sensor-01 (10.10.1.250)
**Monitoring Interface**: eth1 (span port from Core-SW1)
**Analysis Period**: 2024-03-15 00:00 to 2024-03-16 00:00 UTC
**Total Connections Logged**: 2,847,392
### Anomalies Detected
| Notice Type | Source | Destination | Details |
|-------------|--------|-------------|---------|
| DNS_Tunneling_Detected | 10.10.3.45 | 8.8.8.8 | 847 queries to suspect-domain.xyz in 5 min |
| Possible_Beaconing | 10.10.5.12 | 203.0.113.50:443 | 62 connections with 59.8s avg interval |
| SSL::Invalid_Server_Cert | 10.10.8.22 | 198.51.100.33:443 | Self-signed cert, CN=localhost |
| SSH::Password_Guessing | 45.33.32.156 | 10.10.20.11:22 | 487 failed attempts in 30 min |
### Recommendations
1. Isolate 10.10.3.45 and investigate for DNS tunneling malware
2. Block 203.0.113.50 at firewall and forensically image 10.10.5.12
3. Investigate self-signed TLS certificate on 198.51.100.33
4. Block 45.33.32.156 and enforce SSH key-only authentication
评论
支持 Markdown