Chapter 51

Suricata Setup

Suricata is a high-performance network intrusion detection (IDS), inline prevention (IPS), and network security monitoring (NSM) engine. Unlike Zeek (which focuses on structured logging of all activity), Suricata's primary mode is signature-based: rules are applied against traffic in real-time and alerts are generated when traffic matches. Suricata also produces protocol logs like Zeek (EVE JSON) — the two tools are complementary in a production NSM stack.

Scenario

A SOC deploys both Zeek and Suricata on the same network tap. Zeek provides the structured metadata record (conn.log, ssl.log, dns.log) that supports hunting and historical investigation. Suricata provides real-time alert generation based on ET Open rules and custom rules written by the detection engineering team. When Suricata fires an alert, the analyst looks up the corresponding uid in Zeek's logs for full protocol context.

Suricata Architecture

  Suricata Processing Pipeline
  ═══════════════════════════════════════════════════════════════════

  Packet input sources:
  ├── AF_PACKET: zero-copy, multi-threaded (recommended for Linux)
  ├── PF_RING: commercial high-speed option
  ├── PCAP file: offline analysis (suricata -r capture.pcap)
  └── Inline (IPS mode): via NFQ (netfilter queue) or AF_PACKET XDP

  Packet processing:
  ├── Decode threads (N): decode Ethernet/IP/TCP/UDP headers
  ├── Stream engine: TCP reassembly, stateful tracking
  ├── App layer detection: HTTP, TLS, DNS, SMTP, SMB, SSH, ...
  │     (DPI, not port-based — identifies protocols on any port)
  └── Worker threads (N): apply detection rules to decoded traffic

  Detection:
  ├── Rules loaded from: /etc/suricata/rules/
  ├── Rule evaluation: fast pattern matching → detailed checks
  ├── Alert generation on match → eve.json
  └── Threshold engine: suppress repeated alerts

  Output:
  ├── eve.json: JSON events (alerts + protocol logs)
  │     alert events: rule match details
  │     dns events: queries + responses
  │     http events: requests + responses
  │     tls events: handshake metadata + JA3
  │     flow events: connection summaries (like Zeek conn.log)
  ├── fast.log: one line per alert (less detail than eve.json)
  └── stats.log: performance counters

Installation and Configuration

bashsuricata-setup.sh
#!/bin/bash

echo "=== Install Suricata (Ubuntu) ==="
add-apt-repository ppa:oisf/suricata-stable
apt-get update
apt-get install -y suricata suricata-update

echo ""
echo "=== Update rules with suricata-update ==="
suricata-update update-sources        # List available rule sources
suricata-update enable-source et/open  # Enable Emerging Threats Open rules
suricata-update                        # Download and install rules

echo ""
echo "=== Key suricata.yaml settings ==="
cat > /tmp/suricata-key-settings.yaml << 'YAML'
# /etc/suricata/suricata.yaml — key settings

vars:
  address-groups:
    HOME_NET: "[10.0.0.0/8,172.16.0.0/12,192.168.0.0/16]"
    EXTERNAL_NET: "!$HOME_NET"
  port-groups:
    HTTP_PORTS: "80"
    HTTPS_PORTS: "443"
    DNS_PORTS: "53"

outputs:
  - eve-log:
      enabled: yes
      filetype: regular
      filename: /var/log/suricata/eve.json
      types:
        - alert:
            payload: yes          # Include raw packet bytes (base64)
            payload-buffer-size: 4kb
            metadata: yes
            tagged-packets: yes
        - dns:
            enabled: yes
        - http:
            enabled: yes
            extended: yes
        - tls:
            enabled: yes
            extended: yes         # Includes JA3
        - flow:
            enabled: yes
        - smtp:
            enabled: yes

af-packet:
  - interface: eth0
    threads: auto
    cluster-id: 99
    cluster-type: cluster_flow   # Hash by flow 5-tuple (critical!)
    defrag: yes
    use-mmap: yes
    ring-size: 200000

detect:
  threads: auto
  profile: medium   # low/medium/high — tradeoff between speed and memory

app-layer:
  protocols:
    tls:
      enabled: yes
      detection-ports:
        dp: 443
        dp: "[4444, 31337, 8443, 8080]"  # Catch C2 on common alt ports
    http:
      enabled: yes
    dns:
      enabled: yes
    smtp:
      enabled: yes
    ssh:
      enabled: yes
YAML

echo ""
echo "=== Test configuration ==="
suricata --test -c /etc/suricata/suricata.yaml

echo ""
echo "=== Start Suricata ==="
systemctl start suricata
systemctl enable suricata

echo ""
echo "=== Run against PCAP (testing) ==="
suricata -r capture.pcap -c /etc/suricata/suricata.yaml -l /tmp/suricata-output/
ls /tmp/suricata-output/
Why Suricata and Zeek both on the same tap

They're not duplicates — they provide fundamentally different data. Suricata answers: "Did something in this traffic match a known-bad pattern right now?" Zeek answers: "What was the complete structured record of all network activity over the last 30 days?" Suricata is your alert engine — it fires when a rule matches, requiring no prior knowledge by the analyst. Zeek is your investigation database — you can query it for any attribute of any connection from the past month without needing to have predicted in advance what you'd want to look for. In practice: Suricata alerts are the trigger for an investigation; Zeek logs are the primary data source for that investigation. Without Suricata you miss real-time detection of known threats. Without Zeek you have no retrospective visibility — when Suricata fires an alert, you'd have no way to check what the same host was doing yesterday, or whether the beaconing started 2 weeks ago.

Q & A

Q: Suricata is generating thousands of alerts per day. Most are low-quality. How do I reduce noise?

High alert volume from Suricata is almost always a ruleset tuning problem, not a Suricata configuration problem. Approach: (1) Threshold frequently-firing rules: for rules that fire hundreds of times per day, add a threshold.conf entry: threshold gen_id 1, sig_id 2019401, type threshold, track by_src, count 5, seconds 60 — this fires the alert only once per source per minute. (2) Suppress known-good sources: if your patch management system triggers a Nessus scan rule, suppress it for the scanner's IP: suppress gen_id 1, sig_id 2019401, track by_src, ip 10.0.0.5. (3) Disable low-value rule categories: in suricata-update's suricata.rules, comment out entire categories like "emerging-info" (informational, rarely actionable) and "emerging-games" (game traffic detection, not useful in enterprise). (4) Score-based triage: route all alerts to Elasticsearch and build a Kibana dashboard that shows alert counts by rule. Identify the top 10 rules generating the most volume and tune each one. (5) Drop-in alert enrichment: enrich alerts with asset context (is the affected IP a production server vs. a test machine?) — a high-severity alert against a staging host may be low-priority.