Zeek: Complete Guide to Network Security Monitoring and Traffic Analysis Using Kali Linux

Zeek: Complete Guide to Network Security Monitoring and Traffic Analysis Using Kali Linux

Zeek (formerly named Bro, renamed in 2018) is an open-source network security monitoring (NSM) framework rather than a simple packet capture or display tool. Where Wireshark, Tshark, and tcpdump focus on showing individual packets, and NetworkMiner focuses on carving artifacts, Zeek operates at a higher level of abstraction: it sits passively on network traffic (live or from a pcap file), reconstructs full application-layer sessions, and generates rich, structured, tab-separated (or JSON) log files describing every connection, DNS lookup, HTTP transaction, TLS handshake, file transfer, SSH session, and dozens of other protocol interactions — continuously, at scale, over long periods of time.

Zeek’s power comes from its event-driven scripting engine. As Zeek’s core parses traffic, it generates a stream of events (connection_established, http_request, dns_request, file_new, etc.), and Zeek scripts (written in Zeek’s own domain-specific language) subscribe to and react to these events. This makes Zeek extremely extensible: analysts and security teams write custom detection scripts that trigger alerts, extract files, tag traffic, or correlate behavior across many connections — something individual-packet tools cannot easily do.

Zeek is heavily used in security operations centers (SOCs), enterprise network security monitoring, threat hunting, and behavioral/anomaly detection at scale, often alongside tools like Suricata (IDS/IPS) and SIEM platforms that ingest Zeek’s logs. In Kali Linux, Zeek is available via the official repositories or the Zeek project’s own APT repository, and is commonly used for both live sensor deployment and offline forensic analysis of large pcap files.

How to Install

Zeek may not be present in the default Kali repositories in all releases, so the recommended method is to add the official Zeek OBS (openSUSE Build Service) repository:

# Install prerequisites
sudo apt update
sudo apt install -y curl gnupg lsb-release

# Add the Zeek repository (Debian-based, adjust release codename if needed)
echo 'deb http://download.opensuse.org/repositories/security:/zeek/Debian_12/ /' | \
    sudo tee /etc/apt/sources.list.d/security:zeek.list

curl -fsSL https://download.opensuse.org/repositories/security:zeek/Debian_12/Release.key | \
    sudo gpg --dearmor -o /etc/apt/trusted.gpg.d/security_zeek.gpg

sudo apt update
sudo apt install zeek -y

Alternatively, if available directly in Kali’s repos:

sudo apt update
sudo apt install zeek -y

Add Zeek’s binaries to your PATH (commonly installed under /opt/zeek):

echo 'export PATH=/opt/zeek/bin:$PATH' >> ~/.bashrc
source ~/.bashrc

Verify installation:

zeek --version

Expected output:

zeek version 6.2.1

Check ZeekControl (used for managing a running deployment), if installed:

zeekctl status

Expected output:

Name         Type    Host          Status    Pid    Started
zeek         standalone  localhost   running   4821   19 Jul 10:15:03

Syntax

zeek [OPTIONS] [ <policy files / pcap file> ]

Common patterns:

zeek -r capture.pcap                      # Offline analysis of a pcap file
zeek -i eth0                               # Live capture on interface eth0
zeek -r capture.pcap local                 # Offline analysis with the "local" default script bundle
zeekctl deploy                             # Deploy/restart a live monitoring cluster
zeek-cut id.orig_h id.resp_h < conn.log     # Extract specific fields from a Zeek log

All Command-Line Options (Kali Linux)

-h, --help                    Print help and exit
-v, --version                 Print version information and exit

Capture:
  -i <interface>               Read packets live from the specified interface
  -r <file>                    Read packets from the specified pcap file (offline)
  -w <file>                    Write packets to the specified pcap file
  -p <prefix>                  Add a prefix for capture filter reference
  -f <filter>                  BPF filter to apply to captured traffic
  -C                           Ignore checksum errors
  -s                           Chroot to the Zeek log directory (privilege drop)

Execution / scripting:
  -a                            Enter "analysis mode" (do not enforce IPv4-only)
  -b                            Bare mode - do not load standard/default scripts
  -e <zeek code>                 Execute a snippet of Zeek code before loading scripts
  -j                              Use JSON output for logging instead of default TSV
  -N <plugin>                     Show information about the named plugin
  -R <trace>                      Rerun a saved trace against loaded scripts
  -S                              Enable step-by-step debugging of the script engine
  -U <file>                       Record state into the given file for restarting

Environment / deployment:
  -B <options>                   Enable specific debug streams
  -D                              Enable Zeek's own internal debug output
  --pseudo-realtime[=speedup]     Replay a pcap file with realistic timing
  -G <file>                       Generate/read seeds from the given file
  -Y                              Enable "auto-detect" of new event handlers
  -z script tag                  Enable a specific analyzer tag

Environment for zeekctl (cluster/standalone management, separate command):
  zeekctl install                  Install/update configuration to all nodes
  zeekctl deploy                   Install and restart Zeek (common one-step deploy)
  zeekctl start / stop / restart   Control the Zeek process(es)
  zeekctl status                    Show running status of all nodes
  zeekctl diag                      Collect diagnostics for troubleshooting
  zeekctl top                       Show resource usage of running Zeek processes
  zeekctl netstats                  Show packet capture statistics
  zeekctl cron                       Manage log rotation / periodic maintenance

Zeek’s own scripting language (.zeek files) is a separate, extensive syntax used for writing detection logic; it is loaded rather than passed as a flag, e.g. zeek -r capture.pcap my_script.zeek.

Basic Usage (Expected Output in Bash)

Analyze a pcap file offline (most common initial use):

zeek -r capture.pcap

Expected output (terminal):

(no verbose stdout by default; Zeek silently processes the file and writes
 log files into the current working directory)

List the log files generated:

ls

Output:

conn.log       dns.log        files.log      http.log
notice.log     packet_filter.log   reporter.log   ssl.log
weird.log      x509.log

View a sample of the primary connection log:

head -n 5 conn.log

Output:

#separator \x09
#set_separator ,
#empty_field   (empty)
#unset_field   -
#path  conn
#fields ts   uid   id.orig_h   id.orig_p   id.resp_h   id.resp_p   proto  service duration
1721385761.221034  CHhAvVGS1DHFjwGM9  192.168.1.10   51322   93.184.216.34   443    tcp    tls     14.221

Practical Examples with Output

Example 1: Run Zeek against a pcap with the full default script bundle

zeek -r incident.pcap local

Output:

(Generates conn.log, dns.log, http.log, ssl.log, files.log, notice.log,
 weird.log, and more in the current directory.)

Example 2: Live capture on an interface

sudo zeek -i eth0

Output:

listening on eth0
(Zeek runs continuously, writing/rotating logs such as conn.log every hour
 by default until stopped with Ctrl+C.)

Example 3: View HTTP requests logged from a capture

cat http.log | zeek-cut ts id.orig_h host uri status_code

Output:

1721385762.001  192.168.1.10   example.com   /index.html   200
1721385763.552  192.168.1.10   example.com   /style.css    200
1721385770.113  192.168.1.10   malicious.biz /payload.exe  200

Example 4: View DNS queries logged from a capture

cat dns.log | zeek-cut ts id.orig_h query answers

Output:

1721385761.221  192.168.1.10   example.com     93.184.216.34
1721385762.884  192.168.1.10   malicious.biz    185.220.101.5

Example 5: Extract and review any files detected/extracted from traffic

cat files.log | zeek-cut ts fuid tx_hosts rx_hosts source mime_type filename

Output:

1721385770.552  FpqR8y2z  93.184.216.34   192.168.1.10   HTTP  application/x-dosexec  payload.exe
1721385780.100  FhT92kLm  151.101.1.69    192.168.1.10   HTTP  application/pdf         invoice.pdf

Example 6: Review generated notices (Zeek’s built-in alerting)

cat notice.log | zeek-cut ts id.orig_h note msg

Output:

1721385770.552  192.168.1.10  SSL::Invalid_Server_Cert  SSL certificate validation failed for malicious.biz
1721385790.221  192.168.1.10  Scan::Port_Scan            192.168.1.10 scanned 20+ ports on 10.0.0.5

Example 7: Convert Zeek logs to JSON output for SIEM ingestion

zeek -r incident.pcap -j local
head -n 2 conn.log

Output:

{"ts":1721385761.221034,"uid":"CHhAvVGS1DHFjwGM9","id.orig_h":"192.168.1.10","id.orig_p":51322,"id.resp_h":"93.184.216.34","id.resp_p":443,"proto":"tcp","service":"tls","duration":14.221}
{"ts":1721385762.884112,"uid":"CTn82nQpz8x1abcd","id.orig_h":"192.168.1.10","id.orig_p":55123,"id.resp_h":"8.8.8.8","id.resp_p":53,"proto":"udp","service":"dns","duration":0.021}

Example 8: Replay a pcap in “pseudo-realtime” to simulate live traffic timing

zeek -r capture.pcap --pseudo-realtime local

Output:

(Zeek processes the file but paces event generation to match the original
 packet timestamps, useful for testing live-response scripts against
 recorded traffic.)

Example 9: Write and load a custom detection script

cat > detect_ftp.zeek << 'EOF'
event ftp_request(c: connection, command: string, arg: string)
    {
    if ( command == "USER" || command == "PASS" )
        print fmt("FTP credential seen: %s %s from %s", command, arg, c$id$orig_h);
    }
EOF

zeek -r ftp_capture.pcap detect_ftp.zeek

Output:

FTP credential seen: USER admin from 192.168.1.10
FTP credential seen: PASS Sup3rSecret! from 192.168.1.10

Example 10: Check Zeek’s own weird.log for protocol anomalies

cat weird.log | zeek-cut ts id.orig_h id.resp_h name

Output:

1721385900.112  192.168.1.10   93.184.216.34  TCP_ack_underflow_or_misc
1721385920.552  10.0.0.7       10.0.0.9       DNS_unmatched_reply

Example 11: Deploy Zeek as a persistent live sensor using zeekctl

sudo zeekctl deploy
sudo zeekctl status

Output:

checking configurations ...
installing ...
removing old policies ...
generating standalone-layout.zeek ...
generating local-networks.zeek ...
generating zeekctl-config.sh ...
stopping ...
starting zeek ...

Name         Type        Host        Status    Pid     Started
zeek         standalone  localhost   running   5122    19 Jul 11:02:10

Example 12: Search all connection logs for a specific suspicious IP

cat conn.log | zeek-cut id.orig_h id.resp_h id.resp_p proto | grep "185.220.101.5"

Output:

192.168.1.10   185.220.101.5   443   tcp
192.168.1.10   185.220.101.5   8080  tcp

Common Use Cases

  • Continuous, always-on network security monitoring deployed at a network tap or SPAN port in a SOC environment.
  • Threat hunting: querying months of structured conn.log/dns.log/http.log data for indicators of compromise, far faster than re-parsing raw pcaps.
  • Behavioral detection: writing custom Zeek scripts to flag anomalies such as beaconing intervals, DNS tunneling, or long-lived low-and-slow connections.
  • File extraction and malware analysis: automatically carving files transferred over the network for later sandboxing/hash lookups.
  • Compliance and audit logging: maintaining a structured, queryable record of all network activity for a given retention period.
  • Feeding log pipelines: Zeek logs are commonly shipped into ELK/Splunk/SIEM platforms for correlation with endpoint and other telemetry.
  • Offline forensic analysis of large pcap captures where individual-packet review in Wireshark would be impractically slow.

Automation with Bash

Automated batch processing of many stored pcap files into per-file log directories:

#!/bin/bash
# zeek_batch.sh - process a directory of pcaps with Zeek, one output folder each

PCAP_DIR="/data/pcaps"
OUT_DIR="/data/zeek_logs"
mkdir -p "$OUT_DIR"

for pcap in "$PCAP_DIR"/*.pcap; do
    base=$(basename "$pcap" .pcap)
    mkdir -p "${OUT_DIR}/${base}"
    (cd "${OUT_DIR}/${base}" && zeek -r "$pcap" local)
    echo "[*] Processed $pcap -> ${OUT_DIR}/${base}"
done

Daily log rotation and IOC extraction script (intended to run via cron on a live sensor):

#!/bin/bash
# daily_ioc_report.sh - extracts suspicious activity from the previous day's Zeek logs

LOGDIR="/opt/zeek/logs/$(date -d 'yesterday' +%Y-%m-%d)"
REPORT="/data/reports/ioc_report_$(date -d 'yesterday' +%Y%m%d).txt"
mkdir -p /data/reports

{
  echo "=== Notices ==="
  zcat "$LOGDIR"/notice.*.log.gz 2>/dev/null | zeek-cut ts id.orig_h note msg

  echo ""
  echo "=== Suspicious file transfers (.exe) ==="
  zcat "$LOGDIR"/files.*.log.gz 2>/dev/null | zeek-cut tx_hosts rx_hosts mime_type filename | grep -i "exe"

  echo ""
  echo "=== Top talkers by connection count ==="
  zcat "$LOGDIR"/conn.*.log.gz 2>/dev/null | zeek-cut id.orig_h | sort | uniq -c | sort -rn | head -10
} > "$REPORT"

echo "[*] Daily IOC report written to $REPORT"

Cron entry to run the report automatically each morning:

# crontab -e
0 6 * * * /usr/local/bin/daily_ioc_report.sh

Tips and Best Practices

  • Always load the local script bundle (zeek -r file.pcap local) rather than running Zeek in bare mode unless you specifically need minimal processing; local enables sane default detections and logging.
  • Use zeek-cut rather than raw awk/cut on Zeek TSV logs — it correctly respects the #fields header and column ordering, which can change between log types and Zeek versions.
  • For production deployments, use zeekctl to manage Zeek as a service (start/stop/restart/deploy) rather than invoking zeek directly — it handles log rotation, process supervision, and cluster configuration.
  • Enable JSON logging (-j or the JSON::Log framework) when feeding logs into a SIEM or Elasticsearch, since JSON is easier to ingest than raw TSV.
  • Write custom .zeek scripts incrementally and test them offline against representative pcaps (zeek -r test.pcap myscript.zeek) before deploying live.
  • Regularly review weird.log — while noisy, it often surfaces genuinely malformed or evasive traffic that other logs miss.
  • Tune local-networks.zeek to accurately reflect your internal address space; many built-in scripts (e.g., scan detection) depend on correctly distinguishing internal from external hosts.
  • Monitor Zeek’s own resource usage (zeekctl top) on high-throughput links; consider Zeek clusters (multiple worker processes) for line-rate monitoring beyond what a single process can handle.

Troubleshooting

Problem: zeek: command not found after installation. Solution: Zeek typically installs to /opt/zeek/bin; ensure this is added to your PATH (export PATH=/opt/zeek/bin:$PATH) and persisted in ~/.bashrc.

Problem: No interfaces found / permission denied on live capture. Solution: Run with sudo, or grant the Zeek binary capture capabilities: sudo setcap cap_net_raw,cap_net_admin=eip /opt/zeek/bin/zeek.

Problem: Logs are empty or missing expected protocols after analysis. Solution: Confirm you loaded the local script bundle (bare mode disables most analyzers); verify the pcap actually contains the expected traffic using capinfos/tshark first.

Problem: zeekctl deploy fails with configuration errors. Solution: Run zeekctl check to validate the configuration before deploying; review /opt/zeek/etc/node.cfg and networks.cfg for syntax errors.

Problem: High packet drop rate during live monitoring on a busy link. Solution: Increase capture buffer sizes, use PF_RING/AF_PACKET-based high-performance capture if available, or deploy a Zeek cluster with multiple worker processes rather than a single standalone instance.

Problem: Custom Zeek script fails to load with a syntax error. Solution: Run zeek -a myscript.zeek or simply attempt to load it standalone to isolate the error; check the Zeek scripting reference for correct event signatures, since event handler arguments must exactly match Zeek’s built-in event definitions.

Problem: Log file timestamps appear in Unix epoch format and are hard to read. Solution: Use zeek-cut -d ts to convert epoch timestamps in the ts field to human-readable date format automatically.

References

  • Official Zeek website: https://zeek.org/
  • Zeek Documentation: https://docs.zeek.org/en/current/
  • Zeek Script Reference: https://docs.zeek.org/en/current/script-reference/index.html
  • Zeek GitHub repository: https://github.com/zeek/zeek
  • Kali Linux Tools listing for Zeek: https://www.kali.org/tools/zeek/
  • Zeek Log Format / zeek-cut documentation: https://docs.zeek.org/en/current/logs/index.html
Total
0
Shares

Leave a Reply

Previous Post
XSSHunter Complete Guide to Blind Cross-Site Scripting (Blind XSS) Detection Using Kali Linux

XSSHunter: Complete Guide to Blind Cross-Site Scripting (Blind XSS) Detection Using Kali Linux

Next Post
NetworkMiner: Complete Guide to Network Forensics and Packet Analysis Using Kali Linux

NetworkMiner: Complete Guide to Network Forensics and Packet Analysis Using Kali Linux

Related Posts