Introduction
Network security monitoring has evolved dramatically over the past decade, and at the forefront of this evolution stands Zeek (formerly known as Bro) – a powerful open-source network analysis framework that has become indispensable for security professionals worldwide. Whether you’re a SOC analyst, incident responder, or network forensics investigator, understanding Zeek can significantly enhance your ability to detect threats and analyze network behavior.
What Makes Zeek Different?
Unlike traditional Intrusion Detection Systems (IDS) like Snort that focus on signature-based detection and active blocking, Zeek takes a fundamentally different approach. It’s designed as a network analysis framework that passively monitors, logs, and analyzes network traffic to provide deep insights into network behavior.
Key Differentiators:
- Passive monitoring: Zeek doesn’t block traffic – it observes and learns
- Deep protocol analysis: Goes beyond surface-level packet inspection
- Rich scripting capability: Highly customizable with its own domain-specific language
- Comprehensive logging: Generates structured logs in JSON or tab-separated formats
- Event-driven architecture: Translates raw packets into meaningful network events
Understanding Zeek’s Architecture
Zeek’s power lies in its well-designed four-layer architecture:
1. Packet Capture Layer
- Uses libpcap to capture live network packets
- Can also analyze pre-recorded PCAP files
- Handles high-speed network interfaces efficiently
2. Event Engine
- Translates raw network traffic into meaningful events
- Performs protocol parsing and traffic reassembly
- Examples:
connection_established
,http_request
,dns_query
3. Policy Scripts (Scripting Layer)
- Executes custom Zeek scripts written in Zeek’s DSL
- Handles event processing, logging, and alert generation
- Highly modular and customizable
4. Logging Framework
- Generates structured logs for different protocols and behaviors
- Creates files like
conn.log
,http.log
,dns.log
, etc. - Provides the foundation for analysis and threat hunting
Essential Zeek Log Files
Understanding Zeek’s log files is crucial for effective network analysis. Here are the most important ones:
Log File | Purpose | Key Information |
---|---|---|
conn.log | Connection summaries | Source/destination IPs, ports, duration, bytes transferred |
http.log | HTTP traffic analysis | URLs, user agents, response codes, file transfers |
dns.log | DNS queries and responses | Domain lookups, DNS tunneling detection |
ssl.log | SSL/TLS handshake details | Certificate information, cipher suites, potential SSL attacks |
weird.log | Anomalous traffic detection | Malformed packets, protocol violations |
notice.log | Security alerts and notices | Threat detections, policy violations |
Lab 1: Setting Up Zeek and Basic Traffic Analysis
Let’s start with a hands-on lab to get Zeek running and analyze some basic traffic.
Installation
On Ubuntu/Debian:
# Update package repository
sudo apt update
# Install Zeek
sudo apt install zeek
# Verify installation
zeek -v
Building from Source (for latest features):
# Clone the repository
git clone --recursive https://github.com/zeek/zeek
cd zeek
# Configure and build
./configure
make -j$(nproc)
sudo make install
Basic Traffic Capture
Analyzing a PCAP file:
# Download a sample PCAP (or use your own)
wget https://www.malware-traffic-analysis.net/training/host-and-user-ID.pcap.zip
unzip host-and-user-ID.pcap.zip
# Analyze with Zeek
zeek -r host-and-user-ID.pcap
# List generated log files
ls *.log
Live traffic capture:
# Capture on interface eth0 (adjust interface name as needed)
sudo zeek -i eth0
# For specific duration (5 minutes)
sudo timeout 300 zeek -i eth0
Examining the Results
After running Zeek, examine the generated logs:
# View connection summary
head -10 conn.log
# Check HTTP traffic
head -10 http.log
# Look for DNS queries
head -10 dns.log
# Examine any weird/suspicious activity
cat weird.log
Lab 2: Custom Zeek Scripting for Threat Detection
One of Zeek’s most powerful features is its scripting capability. Let’s create custom scripts to detect specific threats.
Basic Script Structure
Create a file called http-monitor.zeek
:
# Event triggered on every HTTP request
event http_request(c: connection, method: string, original_URI: string,
unescaped_URI: string, version: string)
{
# Print basic HTTP request information
print fmt("HTTP Request: %s %s from %s", method, original_URI, c$id$orig_h);
# Detect potential SQL injection attempts
if (/(\bUNION\b|\bSELECT\b|\bINSERT\b|\bDROP\b|\bDELETE\b)/i in original_URI)
{
print fmt("ALERT: Potential SQL injection detected from %s to %s: %s",
c$id$orig_h, c$id$resp_h, original_URI);
}
# Detect potential directory traversal
if (/\.\.\/|\.\.\\/ in original_URI)
{
print fmt("ALERT: Directory traversal attempt from %s: %s",
c$id$orig_h, original_URI);
}
}
# Event triggered when Zeek starts
event zeek_init()
{
print "HTTP monitoring script loaded successfully!";
}
Running Custom Scripts
# Run with custom script
zeek -r sample.pcap http-monitor.zeek
# For live monitoring
sudo zeek -i eth0 http-monitor.zeek
Advanced Threat Detection Script
Create advanced-detection.zeek
:
# Track suspicious domains
global suspicious_domains: set[string] = {
"malicious-site.com",
"phishing-domain.net",
"c2-server.org"
};
# Track large file downloads
global large_download_threshold = 10000000; # 10MB
# DNS monitoring for suspicious domains
event dns_request(c: connection, msg: dns_msg, query: string, qtype: count, qclass: count)
{
if (query in suspicious_domains)
{
print fmt("ALERT: DNS query for suspicious domain %s from %s",
query, c$id$orig_h);
}
# Detect DNS tunneling (unusually long subdomains)
if (|query| > 50)
{
print fmt("ALERT: Potential DNS tunneling detected: %s from %s",
query, c$id$orig_h);
}
}
# Monitor large file transfers
event http_entity_data(c: connection, is_orig: bool, length: count, data: string)
{
if (length > large_download_threshold)
{
print fmt("ALERT: Large file transfer detected: %d bytes from %s to %s",
length, c$id$orig_h, c$id$resp_h);
}
}
# Track connection patterns for potential lateral movement
event connection_state_remove(c: connection)
{
# Look for internal-to-internal connections on unusual ports
if (Site::is_local_addr(c$id$orig_h) && Site::is_local_addr(c$id$resp_h))
{
if (c$id$resp_p !in {22/tcp, 80/tcp, 443/tcp, 445/tcp, 3389/tcp})
{
print fmt("INFO: Internal connection on unusual port %s: %s -> %s",
c$id$resp_p, c$id$orig_h, c$id$resp_h);
}
}
}
Lab 3: Zeek Cluster Deployment
For high-traffic environments, Zeek can be deployed in a cluster configuration for better performance and scalability.
Cluster Architecture Setup
1. Create cluster configuration (/opt/zeek/etc/node.cfg
):
[manager]
type=manager
host=10.0.1.10
[proxy-1]
type=proxy host=10.0.1.11
[worker-1]
type=worker host=10.0.1.12 interface=eth0
[worker-2]
type=worker host=10.0.1.13 interface=eth1
2. Configure networks (/opt/zeek/etc/networks.cfg
):
10.0.0.0/8 Private IP space
172.16.0.0/12 Private IP space
192.168.0.0/16 Private IP space
3. Deploy and manage cluster:
# Deploy cluster configuration
zeekctl deploy
# Check cluster status
zeekctl status
# Start cluster
zeekctl start
# Stop cluster
zeekctl stop
# Restart individual nodes
zeekctl restart worker-1
Lab 4: Integration with ELK Stack
Integrating Zeek with Elasticsearch, Logstash, and Kibana creates a powerful platform for log analysis and visualization.
Logstash Configuration
Create /etc/logstash/conf.d/zeek.conf
:
input {
file {
path => "/opt/zeek/logs/current/*.log"
start_position => "beginning"
sincedb_path => "/dev/null"
}
}
filter {
if [path] =~ "conn" {
mutate { add_field => { "zeek_log_type" => "conn" } }
}
else if [path] =~ "http" {
mutate { add_field => { "zeek_log_type" => "http" } }
}
else if [path] =~ "dns" {
mutate { add_field => { "zeek_log_type" => "dns" } }
}
# Parse TSV format
if [zeek_log_type] {
csv {
separator => " " # Tab separator
skip_header => true
columns => ["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", "local_resp", "missed_bytes", "history", "orig_pkts", "orig_ip_bytes", "resp_pkts", "resp_ip_bytes", "tunnel_parents"]
}
}
# Convert timestamp
date {
match => [ "ts", "UNIX" ]
}
}
output {
elasticsearch {
hosts => ["localhost:9200"]
index => "zeek-%{+YYYY.MM.dd}"
}
}
Kibana Dashboard Setup
- Create index pattern:
zeek-*
- Build visualizations for:
- Top talkers (source/destination IPs)
- Protocol distribution
- HTTP response codes
- DNS query patterns
- Geographic traffic distribution
Advanced Use Cases and Threat Hunting
Detecting Command and Control (C2) Traffic
# C2 beacon detection based on regular intervals
global c2_beacon_tracker: table[addr] of vector of time;
event connection_established(c: connection)
{
local src = c$id$orig_h;
if (src !in c2_beacon_tracker)
c2_beacon_tracker[src] = vector();
c2_beacon_tracker[src][|c2_beacon_tracker[src]|] = network_time();
# Check for regular intervals (potential beaconing)
if (|c2_beacon_tracker[src]| >= 5)
{
local intervals: vector of interval;
for (i in c2_beacon_tracker[src])
{
if (i > 0)
intervals[|intervals|] = c2_beacon_tracker[src][i] - c2_beacon_tracker[src][i-1];
}
# Detect regular intervals (adjust threshold as needed)
local avg_interval = 0.0;
for (interval in intervals)
avg_interval += interval;
avg_interval = avg_interval / |intervals|;
local variance = 0.0;
for (interval in intervals)
variance += (interval - avg_interval) * (interval - avg_interval);
variance = variance / |intervals|;
if (variance < 10.0) # Low variance indicates regular beaconing
{
print fmt("ALERT: Potential C2 beaconing detected from %s (avg interval: %.2f seconds)",
src, avg_interval);
}
}
}
Lateral Movement Detection
# Track authentication attempts across internal networks
global auth_tracker: table[addr] of set[addr];
global auth_threshold = 5;
event smb_tree_connect(c: connection, hdr: SMB1::Header, path: string, service: string)
{
if (Site::is_local_addr(c$id$orig_h) && Site::is_local_addr(c$id$resp_h))
{
local src = c$id$orig_h;
local dst = c$id$resp_h;
if (src !in auth_tracker)
auth_tracker[src] = set();
add auth_tracker[src][dst];
if (|auth_tracker[src]| >= auth_threshold)
{
print fmt("ALERT: Potential lateral movement - %s has connected to %d internal hosts",
src, |auth_tracker[src]|);
}
}
}
Best Practices for Zeek Deployment
Performance Optimization
- Hardware considerations:
- Use high-performance NICs with hardware timestamping
- Ensure sufficient RAM for packet buffering
- Use fast storage (SSD) for log files
- Configuration tuning:
# Increase buffer sizes in zeekctl.cfg CaptureFilter = PFRINGBufferSize = 4096 PFRINGClusterType = cluster_per_flow
- Load balancing:
- Use PF_RING or similar for traffic distribution
- Configure workers based on CPU cores
- Monitor worker utilization
Security Considerations
- Log protection:
- Implement log rotation and compression
- Use secure transport for log forwarding
- Set appropriate file permissions
- Script security:
- Review custom scripts for security vulnerabilities
- Use version control for script management
- Test scripts in isolated environments first
Maintenance and Monitoring
- Regular tasks:
# Check cluster health zeekctl cron # Update to latest signatures zeekctl update # Monitor disk space df -h /opt/zeek/logs/
- Performance monitoring:
- Monitor packet drop rates
- Track CPU and memory usage
- Set up alerts for service failures
Troubleshooting Common Issues
High Packet Loss
# Check interface statistics
zeekctl netstats
# Verify buffer sizes
cat /proc/sys/net/core/rmem_max
# Increase buffer sizes if needed
echo 'net.core.rmem_max = 134217728' >> /etc/sysctl.conf
sysctl -p
Script Errors
# Check script syntax
zeek -a script.zeek
# Debug script execution
zeek -r sample.pcap -e 'print "Debug: Script loaded"' script.zeek
Log Analysis Issues
# Verify log format
zeek-cut -h < conn.log
# Check for corrupted logs
file *.log
Conclusion
Zeek represents a paradigm shift in network security monitoring, moving beyond simple signature-based detection to provide deep, customizable network analysis capabilities. Its event-driven architecture, powerful scripting language, and comprehensive logging make it an invaluable tool for:
- Threat hunting: Discovering hidden threats through behavioral analysis
- Incident response: Providing detailed forensic data for investigation
- Compliance monitoring: Ensuring network activity meets regulatory requirements
- Network forensics: Maintaining long-term visibility into network behavior
The labs and examples in this guide provide a solid foundation for implementing Zeek in your environment. Remember that mastering Zeek is an iterative process – start with basic deployments, gradually add custom scripts, and continuously refine your detection capabilities based on your organization’s specific threat landscape.
As network threats continue to evolve, tools like Zeek that provide deep visibility and flexible analysis capabilities become increasingly critical. The investment in learning Zeek’s capabilities will pay dividends in improved security posture and incident response capabilities.
Next Steps:
- Set up a test environment and work through the labs
- Explore the official Zeek documentation for advanced features
- Join the Zeek community for support and script sharing
- Consider professional training from organizations like Corelight
- Contribute back to the community by sharing useful scripts and techniques
The journey to mastering network security monitoring with Zeek starts with a single packet – begin your analysis today!