Mastering Zeek: A Complete Guide to Network Security Monitoring with Hands-On Labs

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 FilePurposeKey Information
conn.logConnection summariesSource/destination IPs, ports, duration, bytes transferred
http.logHTTP traffic analysisURLs, user agents, response codes, file transfers
dns.logDNS queries and responsesDomain lookups, DNS tunneling detection
ssl.logSSL/TLS handshake detailsCertificate information, cipher suites, potential SSL attacks
weird.logAnomalous traffic detectionMalformed packets, protocol violations
notice.logSecurity alerts and noticesThreat 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

  1. Create index pattern: zeek-*
  2. 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

  1. Hardware considerations:
    • Use high-performance NICs with hardware timestamping
    • Ensure sufficient RAM for packet buffering
    • Use fast storage (SSD) for log files
  2. Configuration tuning: # Increase buffer sizes in zeekctl.cfg CaptureFilter = PFRINGBufferSize = 4096 PFRINGClusterType = cluster_per_flow
  3. Load balancing:
    • Use PF_RING or similar for traffic distribution
    • Configure workers based on CPU cores
    • Monitor worker utilization

Security Considerations

  1. Log protection:
    • Implement log rotation and compression
    • Use secure transport for log forwarding
    • Set appropriate file permissions
  2. Script security:
    • Review custom scripts for security vulnerabilities
    • Use version control for script management
    • Test scripts in isolated environments first

Maintenance and Monitoring

  1. Regular tasks: # Check cluster health zeekctl cron # Update to latest signatures zeekctl update # Monitor disk space df -h /opt/zeek/logs/
  2. 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:

  1. Set up a test environment and work through the labs
  2. Explore the official Zeek documentation for advanced features
  3. Join the Zeek community for support and script sharing
  4. Consider professional training from organizations like Corelight
  5. 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!

Share: