L’interface est localisée ; les présentations et documents des Skills sont traduits automatiquement par IA dans votre langue. Le code, les commandes, chemins et termes techniques restent en version originale, et le document de l’auteur fait foi.
Explorer les Skills
Productivité · SKILL.md

detecting-network-anomalies-with-zeek

detecting-network-anomalies-with-zeek

部署和配置 Zeek(原名 Bro)网络安全监控器,被动分析网络流量、生成结构化日志、检测异常行为,并为威胁狩猎和事件响应创建自定义检测脚本。

Independent GitHub snapshot · Automated classification · Original documentation governs

Documentation de la Skill

GitHub

name: detecting-network-anomalies-with-zeek description: > 部署和配置 Zeek(原名 Bro)网络安全监控器,被动分析网络流量、生成结构化日志、检测异常行为,并为威胁狩猎和事件响应创建自定义检测脚本。 domain: cybersecurity subdomain: network-security tags: [network-security, zeek, network-monitoring, anomaly-detection, threat-hunting] version: "1.0" author: mahipal license: Apache-2.0

使用 Zeek 检测网络异常

适用场景

  • 在关键网络节点部署被动网络安全监控,实现持续可见性
  • 生成结构化连接、DNS、HTTP、SSL 和文件传输日志,供 SIEM 摄入和威胁狩猎
  • 编写自定义 Zeek 脚本,检测组织特定威胁、策略违规或信标行为(beaconing behavior)
  • 对网络元数据进行回溯分析,以调查安全事件
  • 以协议级元数据分析补充 IDS 解决方案,检测基于签名的工具可能遗漏的威胁

不适用场景:替代可主动拦截流量的内联 IDS/IPS;在无 TLS 检测的情况下监控加密载荷;在更适合主机端代理的终端上使用。

前置条件

  • 从源码或包管理器安装 Zeek 6.0+(zeek --version)
  • 在 SPAN 端口、网络 TAP 或虚拟交换机镜像上配置网络接口,用于被动捕获
  • 足够的磁盘存储空间存放日志(估算:每 100 Mbps 监控流量每天 1-5 GB)
  • 熟悉 Zeek 脚本语言,用于编写自定义检测
  • 日志聚合系统(Splunk、Elastic、Graylog)用于集中分析

工作流程

步骤 1:安装和配置 Zeek

# 在 Ubuntu/Debian 上安装 Zeek
sudo apt install -y zeek

# 或从源码安装以获取最新版本
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

# 配置监控接口
sudo vi /opt/zeek/etc/node.cfg
# /opt/zeek/etc/node.cfg
[zeek]
type=standalone
host=localhost
interface=eth1
# 配置本地网络定义
sudo vi /opt/zeek/etc/networks.cfg
# /opt/zeek/etc/networks.cfg
10.0.0.0/8       内部
172.16.0.0/12    内部
192.168.0.0/16   内部
# 禁用 NIC 卸载以实现准确的数据包捕获
sudo ethtool -K eth1 rx off tx off gro off lro off tso off gso off

# 部署 Zeek
sudo zeekctl deploy

# 验证 Zeek 是否运行
sudo zeekctl status

步骤 2:了解和浏览 Zeek 日志

# Zeek 在 /opt/zeek/logs/current/ 中生成结构化日志文件
ls /opt/zeek/logs/current/

# 关键日志文件:
# conn.log       - 所有网络连接(TCP、UDP、ICMP)
# dns.log        - DNS 查询和响应
# http.log       - HTTP 请求和响应
# ssl.log        - SSL/TLS 握手详情
# files.log      - 网络上观察到的文件传输
# notice.log     - 来自 Zeek 检测脚本的告警
# weird.log      - 协议异常和错误
# x509.log       - X.509 证书详情
# smtp.log       - SMTP 邮件事务
# ssh.log        - SSH 连接详情

# 使用 zeek-cut 选列查看连接日志
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

# 查看 DNS 日志
cat /opt/zeek/logs/current/dns.log | zeek-cut ts id.orig_h query qtype_name answers

# 查看 HTTP 日志
cat /opt/zeek/logs/current/http.log | zeek-cut ts id.orig_h host uri method status_code user_agent

步骤 3:编写自定义检测脚本

# 创建自定义检测脚本目录
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
    };

    # 阈值:时间窗口内每个源的唯一查询数
    const query_threshold: count = 200 &redef;
    const time_window: interval = 5min &redef;
    const max_query_length: count = 50 &redef;
}

# 按源 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;

    # 检查异常长的域名查询(base64 编码数据)
    if ( |query| > max_query_length )
    {
        NOTICE([
            $note=DNS_Long_Query,
            $msg=fmt("来自 %s 的异常长 DNS 查询:%s(%d 字符)", src, query, |query|),
            $src=src,
            $identifier=cat(src, query)
        ]);
    }

    # 按源跟踪查询量
    dns_query_counts[src] += 1;

    if ( dns_query_counts[src] == query_threshold )
    {
        NOTICE([
            $note=DNS_Tunneling_Detected,
            $msg=fmt("可能的 DNS 隧道:%s 在 %s 内发送了 %d 个查询", src, time_window, query_threshold),
            $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("可能的信标行为:%s 在 %s 内建立了 %d 次连接",
                         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:加载自定义脚本并部署

# 将自定义脚本添加到 local.zeek
sudo tee -a /opt/zeek/share/zeek/site/local.zeek << 'EOF'

# 自定义检测脚本
@load custom-detections/dns-tunneling.zeek
@load custom-detections/beacon-detection.zeek

# 启用额外的协议分析器
@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

# 启用文件提取
@load frameworks/files/extract-all-files

# 启用 Intel 框架用于威胁情报
@load frameworks/intel/seen
@load frameworks/intel/do_notice
EOF

# 重新加载 Zeek 配置
sudo zeekctl deploy

# 验证脚本加载无误
sudo zeekctl diag

步骤 5:Zeek 日志威胁狩猎查询

# 查找长时间连接(可能的 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#x27;\t' -k5 -rn | head -20

# 查找高数据传输量的连接
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}'

# 识别罕见 User-Agent(潜在恶意软件)
cat /opt/zeek/logs/current/http.log | zeek-cut user_agent | sort | uniq -c | sort -n | head -20

# 查找自签名或过期证书
cat /opt/zeek/logs/current/ssl.log | zeek-cut ts id.orig_h id.resp_h server_name validation_status | \
  grep -v "ok"

# 检测 DGA 模式的 DNS 查询(新注册域名)
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}'

# 查找 SSH 暴力破解尝试
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

# 识别异常端口使用
cat /opt/zeek/logs/current/conn.log | zeek-cut id.resp_p proto service | \
  sort | uniq -c | sort -rn | head -50

步骤 6:与 SIEM 集成并设置告警

# 配置 JSON 日志输出以便 SIEM 摄入
sudo tee /opt/zeek/share/zeek/site/json-logs.zeek << 'EOF'
@load policy/tuning/json-logs.zeek
redef LogAscii::use_json = T;
EOF

# 通过 Filebeat 将日志转发到 Elastic
# /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

# 设置日志轮转
sudo tee /etc/cron.d/zeek-logrotate << 'EOF'
0 0 * * * root /opt/zeek/bin/zeekctl cron
EOF

# 监控 Zeek 健康状态
sudo zeekctl status
sudo zeekctl netstats

核心概念

术语定义
网络安全监控器(Network Security Monitor)被动分析工具,观察网络流量并生成结构化元数据日志,不改变或拦截流量
Zeek 脚本(Zeek Script)用 Zeek 领域特定语言编写的事件驱动脚本,处理网络事件并生成通知、日志和指标
连接日志(conn.log)核心 Zeek 日志,记录每个观察到的连接,包含源/目标 IP、端口、协议、持续时间和字节计数
Notice 框架(Notice Framework)当检测脚本识别到可疑活动时,Zeek 用于生成告警的子系统,输出到 notice.log
SumStats 框架(SumStats Framework)Zeek 中的统计分析框架,用于跟踪时间窗口内的指标,实现基于阈值的异常检测
Intel 框架(Intel Framework)Zeek 模块,将观察到的网络指标与威胁情报 feeds 进行匹配,并在匹配时生成告警

工具与系统

  • Zeek 6.0+:开源网络安全监控器,通过被动流量分析生成全面的协议级日志
  • zeek-cut:Zeek 实用工具,用于从制表符分隔的 Zeek 日志文件中提取特定列进行快速分析
  • zeekctl:Zeek 管理工具,用于在单机或集群部署中部署、监控和管理 Zeek 实例
  • RITA(Real Intelligence Threat Analytics):开源工具,分析 Zeek 日志以检测信标、DNS 隧道和其他威胁指标
  • Filebeat:Elastic 代理,用于将 Zeek JSON 日志传输到 Elasticsearch 进行集中分析和可视化

常见场景

场景:检测企业流量中的命令与控制信标

背景:威胁情报报告指出,某特定威胁行为者对被入侵主机使用 60 秒间隔的 HTTPS 信标。SOC 团队需要分析 Zeek 日志,在承载 2 Gbps 流量的企业网络中识别任何表现出此模式的主机。

方法:

  1. 在互联网出口点的网络 TAP 上部署 Zeek,使用 AF_PACKET 进行高吞吐量捕获
  2. 启用自定义信标检测脚本,将阈值调整为 1 小时观察窗口内的 60 秒间隔
  3. 查询 conn.log,查找连接时间一致的外部 IP 连接:过滤连接到达时间间隔标准差小于 5 秒的连接
  4. 将可疑目标 IP 与加载到 Zeek Intel 框架的威胁情报 feeds 进行交叉比对
  5. 检查关联的 ssl.log 中的 TLS 证书——查找自签名证书、异常颁发者名称或短有效期证书
  6. 为每个识别出的信标源生成 notice,并输入 SIEM 供 SOC 分类

常见陷阱:

  • 未针对环境调整信标检测阈值,导致来自合法更新服务(Windows Update、AV 更新)的误报
  • 未排除 CDN 和云服务提供商 IP 范围,这些 IP 自然会收到大量重复连接
  • 在高吞吐量链路上运行 Zeek 时 CPU 核心不足,导致数据包丢弃
  • 未启用 JSON 日志输出,导致 SIEM 集成需要额外的自定义解析器

输出格式

## Zeek 网络异常检测报告

**传感器**:zeek-sensor-01(10.10.1.250)
**监控接口**:eth1(来自 Core-SW1 的 SPAN 端口)
**分析周期**:2024-03-15 00:00 至 2024-03-16 00:00 UTC
**记录的连接总数**:2,847,392

### 检测到的异常

| 通知类型 | 来源 | 目标 | 详情 |
|-------------|--------|-------------|---------|
| DNS_Tunneling_Detected | 10.10.3.45 | 8.8.8.8 | 5 分钟内向 suspect-domain.xyz 发出 847 次查询 |
| Possible_Beaconing | 10.10.5.12 | 203.0.113.50:443 | 62 次连接,平均间隔 59.8 秒 |
| SSL::Invalid_Server_Cert | 10.10.8.22 | 198.51.100.33:443 | 自签名证书,CN=localhost |
| SSH::Password_Guessing | 45.33.32.156 | 10.10.20.11:22 | 30 分钟内 487 次失败尝试 |

### 建议
1. 隔离 10.10.3.45 并调查 DNS 隧道恶意软件
2. 在防火墙封锁 203.0.113.50 并对 10.10.5.12 进行取证镜像
3. 调查 198.51.100.33 上的自签名 TLS 证书
4. 封锁 45.33.32.156 并强制执行仅 SSH 密钥认证
Skills enregistrées