Post

Building a Zeek and Suricata Dual Sensor for a Home Lab

Building a Zeek and Suricata Dual Sensor for a Home Lab

A single IDS can only see part of the story. Zeek gives you rich protocol metadata and context, while Suricata provides fast signature and protocol anomaly detection. Running both on a single passive sensor in a home lab gives you the best of both worlds: high fidelity logs for hunting and real-time alerts for triage.

The key to a dual sensor is capture discipline. You want the sensor to be passive, never in the forwarding path, and you want to be explicit about what traffic you mirror. In a home lab, a managed switch with a SPAN port or a cheap copper TAP is usually enough. Mirror a single VLAN first, make sure you are not oversubscribing the sensor, and then scale out.

Context

Problem: A single sensor misses either rich context or fast alerts in a lab setup. Approach: Build a passive dual sensor with disciplined capture and tuned outputs. Outcome: Protocol metadata for hunting and reliable alerts for triage.

Lab topology and capture strategy

The cleanest layout uses a dedicated sensor with two NICs. One NIC is the management interface with a normal IP. The second NIC is connected to the SPAN port and has no IP at all. This avoids accidental ARP replies and prevents the sensor from ever being in the routing path. If your switch only mirrors a trunk, filter aggressively in software to avoid saturating the capture ring.

If you are using Linux, set the capture interface to promisc mode and disable offloads. This matters for both Zeek and Suricata because checksum offload can cause false positives or broken reassembly.

1
2
sudo ip link set dev eth1 promisc on
sudo ethtool -K eth1 gro off lro off gso off tso off

Base installation

On Ubuntu 22.04 or Debian, you can install both from packages, but I prefer the official Suricata PPA for newer features and Zeek from the upstream repository for consistent scripts. If you are on a small Intel box, build once and pin versions to avoid surprises.

1
2
3
4
5
6
sudo apt update
sudo apt install -y software-properties-common
sudo add-apt-repository ppa:oisf/suricata-stable
sudo add-apt-repository ppa:zeek/zeek
sudo apt update
sudo apt install -y suricata zeek jq

Make sure the binaries are on your PATH. Zeek also ships zeekctl, which is still the easiest way to manage clusters, even in a single node lab.

Suricata tuning for AF-PACKET

For a single sensor, AF-PACKET is stable and fast. The goal is to size your ring buffers so you do not drop packets when the lab gets noisy. Start with this minimal AF-PACKET section in suricata.yaml and increase the ring size if you see drops.

1
2
3
4
5
6
7
8
9
af-packet:
  - interface: eth1
    cluster-id: 99
    cluster-type: cluster_flow
    defrag: yes
    use-mmap: yes
    ring-size: 400000
    block-size: 65536
    checksum-checks: no

Enable EVE JSON output so you have a uniform log format for alerts, flows, DNS, and HTTP. If your storage is tight, enable only the datasets you actually use.

1
2
3
4
5
6
7
8
9
10
11
outputs:
  - eve-log:
      enabled: yes
      filetype: regular
      filename: /var/log/suricata/eve.json
      types:
        - alert
        - dns
        - http
        - tls
        - flow

Suricata rules matter. Start with ET Open and your own local rules. For a lab, I also keep a focused rule file for my own services so I can test end to end alerting quickly.

1
2
3
sudo suricata-update
sudo suricata-update enable-source et/open
sudo suricata-update

Zeek deployment and policy

Zeek is a script engine, so the art is choosing the logs you want and keeping them consistent. For a lab sensor, enable the core protocol analyzers and avoid heavy file extraction unless you have a strong reason.

Edit /opt/zeek/share/zeek/site/local.zeek and include a few targeted scripts. This example enables JSON logs and adds basic notice hooks so that Zeek emits a single record you can index cleanly.

@load base/protocols/conn
@load base/protocols/dns
@load base/protocols/http
@load base/protocols/ssl
@load base/frameworks/notice

redef LogAscii::use_json = T;

event Notice::policy(n: Notice::Info)
  {
  if ( n$note == SSL::Invalid_Server_Cert )
    add n$tags["invalid_cert"];  
  }

Deploy with zeekctl and point it at your capture interface.

1
2
sudo zeekctl deploy
sudo zeekctl status

Log pipeline and storage

If you only need local analysis, use jq and zeek-cut for quick slices. Suricata EVE JSON can be filtered by event type, and Zeek JSON logs are line-delimited so they work well with tools like ripgrep and jq.

1
jq -c 'select(.event_type=="tls" and .tls.sni!=null) | {ts, src_ip, dest_ip, sni:.tls.sni}' /var/log/suricata/eve.json | head

For long term retention, forward both datasets into OpenSearch or Elasticsearch. The key is to normalize timestamps and hostnames so you can pivot across Zeek conn.log and Suricata flow data during a hunt.

Validation traffic in the lab

Generate traffic with a mix of benign and noisy commands. This makes sure you are seeing alerts and metadata from both sensors.

1
2
3
4
5
6
7
8
# basic port scan
nmap -sS -sV -p 22,80,443 192.168.56.0/24

# drive a TLS handshake
openssl s_client -connect example.com:443 -servername example.com < /dev/null

# simulate a tiny HTTP beacon
curl -H 'User-Agent: lab-beacon/1.0' http://192.168.56.10:8080/ping

Suricata should emit alerts for scan patterns if your rules are active. Zeek should log conn, dns, http, and ssl entries for the same flows. If either side is missing, check drops and interface settings.

Performance and maintenance

Monitor packet drops. Suricata provides a built in command to read counters, and Zeek exposes capture_loss in stats.log. If drops climb, you can reduce capture scope, increase ring size, or move the sensor to a faster NIC.

Also keep your rule and script versions pinned. In a lab, upgrading weekly can change log fields. That makes it hard to compare across time when you are testing detection logic. Batch updates and revalidate your dashboards after every change.

Signature strategy and evasion testing

Suricata rules are only as good as the assumptions behind them. Start with community rules, then add a small local ruleset for the services you run in the lab. For example, if you host a vulnerable web app, write a rule that matches the exact path of your test payloads and verify alerting end to end. This gives you a known good signal and helps you validate the pipeline after updates.

You should also test evasion. Generate traffic with fragmented packets, unusual MTUs, and multiple encodings of the same payload. Suricata defragmentation settings and stream depth limits can hide attacks if they are too low. Document which test cases are detected and which are missed so you can tune stream settings deliberately rather than blindly increasing resource usage.

Takeaways

A dual Zeek and Suricata sensor is a force multiplier for a home lab. You get rich protocol metadata for hunting and fast alerting for detection, without the cost of a full enterprise stack. The key is to keep capture passive, tune the ring buffers, and maintain a clean log pipeline. Once this is stable, you can add enrichment like GeoIP, JA3 fingerprints, and custom rules to turn your lab into a realistic network defense playground.

This post is licensed under CC BY 4.0 by the author.