How to Set Up Zeek for Network Security Monitoring

Retool's new app builder is where AI-generated code ships safely
Building apps with AI is easy. Getting them to production safely is another story.
Full packet capture is the gold standard for network forensics but impractical at scale: a 10 Gbps link generates 4.3 TB per hour. Zeek solves this by extracting the security-relevant metadata from each network session and storing it as structured JSON logs. You get DNS queries, TLS certificates, HTTP user agents, SMB file access, and Kerberos ticket exchanges: the information needed for security analysis: at a fraction of the storage cost of full packet capture.
Security teams use Zeek logs to answer questions that firewall logs cannot: what DNS names did this host resolve yesterday, which TLS certificates does this connection use, what files were transferred over SMB, and was that Kerberos ticket encrypted with RC4?
Deployment Architecture
Sensor placement: where to put Zeek:
- Core switch SPAN port: Mirror traffic from all VLANs to the Zeek sensor. Most comprehensive: sees all east-west traffic.
- Firewall inline tap: Sees north-south traffic (internet-bound). Misses east-west lateral movement.
- Multiple sensors: One per segment for large environments. Zeek clusters can aggregate logs centrally.
Hardware sizing (single sensor):
| Traffic volume | CPU cores | RAM | Storage (30-day retention) |
|---|---|---|---|
| < 1 Gbps | 4 cores | 8 GB | 200 GB |
| 1-5 Gbps | 8 cores | 16 GB | 1 TB |
| 5-10 Gbps | 16 cores | 32 GB | 3 TB |
| > 10 Gbps | Zeek cluster | 64 GB+ | Scale with log servers |
Installation (Ubuntu 22.04 / Debian):
# Install Zeek from official packages
echo 'deb http://download.opensuse.org/repositories/security:/zeek/xUbuntu_22.04/ /' \
| sudo tee /etc/apt/sources.list.d/security:zeek.list
curl -fsSL https://download.opensuse.org/repositories/security:zeek/xUbuntu_22.04/Release.key \
| gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/security_zeek.gpg > /dev/null
apt update && apt install zeek
# Add Zeek to PATH
export PATH="/opt/zeek/bin:$PATH"
echo 'export PATH="/opt/zeek/bin:$PATH"' >> ~/.bashrc
# Verify installation
zeek --version
Configuration: Networks, Interfaces, and Essential Scripts
Configure the monitored network interface:
# Edit /opt/zeek/etc/node.cfg
[zeek]
type=standalone
host=localhost
interface=eth1 # The interface receiving the SPAN/mirror traffic
# For AF_PACKET (better performance on Linux):
# interface=af_packet::eth1
Define your internal networks:
# Edit /opt/zeek/etc/networks.cfg
# All RFC 1918 private address spaces (adjust for your environment)
10.0.0.0/8 Internal
172.16.0.0/12 Internal
192.168.0.0/16 Internal
# Add your specific internal networks:
10.50.0.0/16 Corp-LAN
10.60.0.0/16 DMZ
10.70.0.0/16 OT-Network
Essential scripts to load in local.zeek:
# /opt/zeek/share/zeek/site/local.zeek
# Load JSON output (critical for SIEM integration)
@load policy/tuning/json-logs
# Protocol analyzers
@load base/protocols/ssl # TLS/SSL certificate extraction
@load base/protocols/http # HTTP logs
@load base/protocols/dns # DNS query logs
@load base/protocols/smb # SMB session and file logs
@load base/protocols/kerberos # Kerberos ticket logs
@load base/protocols/ssh # SSH session logs
@load base/protocols/ftp # FTP logs
@load base/protocols/smtp # Email header logs
# Security-focused scripts
@load policy/protocols/ssl/validate-certs # Alert on invalid certs
@load policy/protocols/ssl/log-hostnames # Log SNI hostnames
@load policy/frameworks/intel # Threat intelligence framework
@load policy/frameworks/files/hash-all-files # Hash all extracted files
# Detection scripts
@load policy/misc/scan # Port scan detection
@load policy/protocols/conn/mac-logging # Log MAC addresses
@load policy/protocols/ssl/expiring-certs # Alert on expiring certs
# Reduce noise from common benign traffic
redef DNS::max_pending_msgs = 0;
Deploy and verify:
# Check configuration
zeekctl check
# Deploy and start
zeekctl deploy
# Verify logs are generating
tail -f /opt/zeek/logs/current/dns.log
tail -f /opt/zeek/logs/current/conn.log
tail -f /opt/zeek/logs/current/ssl.log
# Watch for any errors
zeekctl status
zeekctl diag
Briefings like this, every morning before 9am.
Threat intel, active CVEs, and campaign alerts, distilled for practitioners. 50,000+ subscribers. No noise.
Key Log Files and What Security Teams Use Them For
conn.log: every network connection:
# Fields: ts, uid, id.orig_h, id.orig_p, id.resp_h, id.resp_p, proto,
# service, duration, orig_bytes, resp_bytes, conn_state, local_orig
# Find large outbound transfers (data exfiltration)
zeek-cut ts id.orig_h id.resp_h id.resp_p orig_bytes resp_bytes duration \
< conn.log | \
awk '$6 > 10000000 {print}' | \
sort -k6 -n -r | head -20
# resp_bytes > 10MB outbound to external IPs: potential exfiltration
# Find long-duration connections (C2 keep-alives, tunnels)
zeek-cut ts id.orig_h id.resp_h duration service < conn.log | \
awk '$4 > 3600 {print}' | sort -k4 -n -r
# Duration > 1 hour to external IP: suspicious for non-VPN connections
dns.log: every DNS query and response:
# Fields: ts, uid, id.orig_h, id.resp_h, proto, query, qtype, qtype_name,
# rcode, rcode_name, answers, TTLs
# Find DGA or tunneling (long query names)
zeek-cut query < dns.log | \
awk 'length($1) > 50 {print length($1), $1}' | \
sort -n -r | head -20
# Find all unique domains queried (for threat intel matching)
zeek-cut query < dns.log | sort -u > unique_domains.txt
grep -F -f threat_intel_domains.txt unique_domains.txt
ssl.log: every TLS session with certificate details:
# Fields: ts, uid, id.orig_h, id.resp_h, version, cipher, curve,
# server_name (SNI), subject, issuer, validation_status
# Find self-signed certificates (potential C2 infrastructure)
zeek-cut ts id.orig_h id.resp_h server_name issuer validation_status < ssl.log | \
awk '$6 == "self signed certificate" {print}' | head -20
# Find connections with no SNI (direct IP connections: suspicious for HTTPS)
zeek-cut id.orig_h id.resp_h server_name < ssl.log | \
awk '$3 == "-" {print}' | head -20
kerberos.log: Kerberos ticket exchanges:
# Fields: ts, uid, id.orig_h, id.resp_h, request_type, client, service,
# success, error_msg, cipher, forwardable, renewable
# Find RC4 Kerberos tickets (Kerberoasting indicator)
zeek-cut ts id.orig_h client service cipher < kerberos.log | \
awk '$5 == "rc4-hmac" {print}' | head -20
# Find failed Kerberos authentications (brute force or expired tickets)
zeek-cut ts id.orig_h client error_msg < kerberos.log | \
awk '$4 != "-" {print}' | \
sort -k4 | head -30
SIEM Integration and Threat Intelligence
Ship Zeek JSON logs to Elastic (Filebeat):
# /etc/filebeat/filebeat.yml
filebeat.inputs:
- type: log
enabled: true
paths:
- /opt/zeek/logs/current/conn.log
- /opt/zeek/logs/current/dns.log
- /opt/zeek/logs/current/ssl.log
- /opt/zeek/logs/current/http.log
- /opt/zeek/logs/current/files.log
- /opt/zeek/logs/current/kerberos.log
- /opt/zeek/logs/current/smb_mapping.log
json.message_key: ts
json.expand_keys: true
tags: ["zeek"]
output.elasticsearch:
hosts: ["http://elasticsearch:9200"]
index: "zeek-%{+yyyy.MM.dd}"
# For Splunk:
output.logstash:
hosts: ["splunk-hf:5044"]
Load threat intelligence into Zeek:
# /opt/zeek/share/zeek/site/intel.zeek
@load base/frameworks/intel
@load policy/frameworks/intel/seen
@load policy/frameworks/intel/do_notice
redef Intel::read_files = {
"/opt/zeek/intel/domains.dat", # One IOC per line: domain\tIntel::DOMAIN\t...
"/opt/zeek/intel/ips.dat", # IP IOCs
};
# Format for Zeek intel files (tab-separated):
# indicator indicator_type meta.source meta.desc
echo -e 'evil-domain.com\tIntel::DOMAIN\tThreatFox\tKnown C2' >> /opt/zeek/intel/domains.dat
echo -e '1.2.3.4\tIntel::ADDR\tMandiant\tAPT29 C2' >> /opt/zeek/intel/ips.dat
# Zeek automatically alerts (Notice) when any traffic matches the intel
# Check notices.log for matches
zeek-cut ts note msg sub src dst < /opt/zeek/logs/current/notice.log |
grep Intel | head -20
The bottom line
Zeek transforms raw network traffic into structured protocol logs: conn.log for all connections, dns.log for all DNS queries, ssl.log for TLS certificates and SNI, kerberos.log for Kerberos authentication, and 35+ other protocol-specific logs. Deploy on a SPAN port mirror receiving traffic from your core switch. Enable JSON output for SIEM integration. Load the intel framework to match traffic against threat IOC feeds. Use Zeek logs for threat hunting queries that firewall logs cannot answer: which hosts resolved a specific domain, which connections used RC4 Kerberos, which processes established TLS to self-signed certificates.
Frequently asked questions
What is Zeek and what does it do?
Zeek is an open-source network analysis framework that passively captures network traffic and produces structured JSON logs for DNS, HTTP, SSL/TLS, SMB, Kerberos, SSH, and 40+ other protocols. Unlike IDS tools that match signatures, Zeek produces protocol-aware metadata that security analysts use for threat hunting, C2 detection, lateral movement analysis, and data exfiltration investigation. It runs on a server with a SPAN port receiving mirrored traffic.
What are the most important Zeek log files for security monitoring?
conn.log (every network connection with timing and bytes: foundation of all threat hunting), dns.log (every DNS query and response: C2 domain detection, DNS tunneling), ssl.log (TLS certificates, SNI, cipher suites: C2 infrastructure uses self-signed certs), kerberos.log (RC4 Kerberos tickets indicating Kerberoasting, failed auth indicating brute force), and smb_mapping.log (SMB share access: lateral movement indicator).
What is Zeek and how does it differ from Snort or Suricata?
Zeek (formerly Bro) is a network analysis framework that generates structured logs from captured network traffic. It produces JSON logs describing network activity (connections, DNS queries, HTTP requests, TLS certificates) that can be ingested into a SIEM for threat hunting and correlation. Snort and Suricata are signature-based intrusion detection/prevention systems (IDS/IPS) that match packet content against rules and generate alerts. Zeek provides raw network visibility for behavioral analysis; Snort/Suricata provide real-time alert generation for known-bad signatures. Production environments often use both: Zeek for logs and threat hunting, Suricata for real-time IDS alerting on the same traffic mirror.
How do I deploy Zeek for network security monitoring?
Zeek requires a network tap or SPAN port that mirrors traffic from a chokepoint (core switch, firewall, or internet edge). Install Zeek on a server with a NIC connected to the span port: the span NIC operates in promiscuous mode with no IP address. Install Zeek via package manager (zeek-lts on RHEL/Ubuntu). Configure node.cfg to identify the interface, local.zeek to set the monitored networks, and optionally enable additional protocol analyzers. Logs write to /opt/zeek/logs/current/ and rotate hourly to daily archives. For SIEM ingestion, use Filebeat with the Zeek module or Splunk with the Zeek Technology Add-on to parse and ingest Zeek JSON logs.
What Zeek queries are useful for threat hunting?
Key Zeek-based threat hunting queries: (1) DNS long subdomain detection: in dns.log, filter query length > 40 characters and group by domain to find potential DNS tunneling infrastructure; (2) Self-signed certificate detection: in ssl.log, filter validation_status = 'self signed certificate' grouped by server_name — C2 infrastructure frequently uses self-signed certs; (3) Beaconing detection: in conn.log, calculate the standard deviation of connection intervals per uid to identify connections with suspicious regularity; (4) SMB lateral movement: in smb_mapping.log, alert on ADMIN$ or C$ share access from user workstations; (5) Kerberoasting: in kerberos.log, filter cipher = 'rc4-hmac' on service ticket requests for service accounts.
How do I tune Zeek to handle high-throughput links without dropping packets?
Packet drops on Zeek sensors are tracked in the capture_loss.log file -- any non-zero 'percent_lost' value indicates the sensor is falling behind. On Linux, the primary fix is switching from standard pcap to AF_PACKET with multiple threads: in node.cfg, set the interface to 'af_packet::eth1' and add 'lb_method=custom' with a pin_cpus assignment to dedicate CPU cores to packet processing. Increase the AF_PACKET ring buffer size by setting 'AF_Packet::buffer_size = 128' (MB) in local.zeek. For links above 5 Gbps, deploy Zeek in cluster mode: a manager node handles logging and coordination, proxy nodes handle inter-worker communication, and multiple worker nodes each process a subset of traffic pinned to separate CPU cores via NUMA-aware allocation. Disable Zeek analyzers you do not use to reduce per-packet processing cost -- analyzers for FTP, IRC, and GNUTELLA are rarely needed in enterprise environments. Monitor 'zeekctl diag' output after each configuration change and aim for capture loss below 0.1 percent in steady state.
Sources & references
Free resources
Critical CVE Reference Card 2025–2026
25 actively exploited vulnerabilities with CVSS scores, exploit status, and patch availability. Print it, pin it, share it with your SOC team.
Ransomware Incident Response Playbook
Step-by-step 24-hour IR checklist covering detection, containment, eradication, and recovery. Built for SOC teams, IR leads, and CISOs.
Get threat intel before your inbox does.
50,000+ security professionals read Decryption Digest for early warnings on zero-days, ransomware, and nation-state campaigns. Free, daily, no spam.
Unsubscribe anytime. We never sell your data.

Founder & Cybersecurity Evangelist, Decryption Digest
Cybersecurity professional with expertise in threat intelligence, vulnerability research, and enterprise security. Covers zero-days, ransomware, and nation-state operations for 50,000+ security professionals every morning.
Win a $2,495 Black Hat pass.
Full-access to Black Hat USA 2026 in Las Vegas. Subscribe free to enter.
