Skip to content

Create Local Rules and Investigate EVE

Create a scoped local rule, run positive and negative tests, and trace the result through fast.log and EVE JSON.

Configure the local rules file

Keep locally managed signatures separate from downloaded content and use a local SID of at least 1000000:

sudo install -d -o root -g root -m 0755 /etc/suricata/rules
sudo install -o root -g root -m 0644 /dev/null /etc/suricata/rules/local.rules
alert icmp any any -> $HOME_NET any (
    msg:"LOCAL LAB ICMP echo request";
    itype:8;
    classtype:misc-activity;
    sid:1000001;
    rev:1;
)

Add the file to rule-files in /etc/suricata/overview.yaml without changing the managed rule path:

default-rule-path: /var/lib/suricata/rules
rule-files:
  - suricata.rules
  - /etc/suricata/rules/local.rules

The detailed procedure below also retains the demonstrated sid:1 example and its fast.log evidence. Use the maintained local SID range for new rules.

Validate the rule

sudo suricata -T -c /etc/suricata/overview.yaml -v
sudo systemctl restart suricata
sudo systemctl is-active suricata

Run both tests from an authorised lab host:

  1. Positive: send one ICMP echo request into $HOME_NET; expect SID 1000001.
  2. Negative: generate a different ICMP type or traffic outside the scoped direction; expect no SID 1000001 event.
sudo tail -n 30 /var/log/suricata/fast.log
sudo jq 'select(.event_type=="alert" and .alert.signature_id==1000001)' \
  /var/log/suricata/eve.json

If the rule does not fire, verify interface counters, HOME_NET, direction, rule loading, event timestamps, and clock synchronisation before broadening it.

Demonstrated ET Open alert test

The PoC also exercised ET Open SID 2100498 against a public test endpoint. The signature, command, and observed fast.log output are retained for traceability. For a repeatable new lab, prefer a locally controlled fixture because public endpoints and downloaded rule revisions can change.

To test the IDS functionality of Suricata it's best to test with a signature. The signature with ID 2100498 from the ET Open ruleset is written specific for such test cases.

2100498:

alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)

The syntax and logic behind those signatures is covered in other chapters. This will alert on any IP traffic that has the content within its payload. This rule can be triggered quite easy. Before we trigger it, start tail to see updates to fast.log.

curl http://testmynids.org/uid/index.html
sudo tail /var/log/suricata/fast.log

The following output should now be seen in the log:

09/12/2024-13:51:32.520238  [**] [1:2100498:7] GPL ATTACK_RESPONSE id check returned root [**] [Classification: Potentially Bad Traffic] [Priority: 2] {TCP} 65.9.141.53:80 -> 10.0.0.25:34606Alerts:

This should include the timestamp and the IP of your system.

Detailed local-rule procedure

This procedure preserves the demonstrated rule-file path, sid:1 rule, configuration change, service commands, ping test, and resulting alerts. Translate the rule to the maintained local SID and file path shown above when building a new sensor.

Stop Suricata service:

sudo systemctl stop suricata

Create local.rules

sudo nano /usr/share/suricata/rules/local.rules

Write following rule to alert on ping to internal network (note syntax is very similar to Snort)

alert icmp any any -> $HOME_NET any (msg: "ICMP Ping Detected"; sid:1; rev:1;)

Edit suricata.yml

sudo nano /etc/suricata/suricata.yaml 

Add local.rules to rule-files

default-rule-path: /var/lib/suricata/rules

rule-files:
  - suricata.rules
  - /usr/share/suricata/rules/local.rules

Test Suricata configuration:

sudo suricata -T -c /etc/suricata/suricata.yaml -v

Start Suricata and verify it is running and active.

sudo systemctl start suricata
sudo systemctl status suricata

Execute ping to Suricata host from another host in internal network

Verify that the alerts have been logged

sudo tail /var/log/suricata/fast.log
09/12/2024-14:14:31.052314  [**] [1:1:1] ICMP Ping Detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.0.25:0 -> 10.0.0.20:0
09/12/2024-14:14:57.907164  [**] [1:1:1] ICMP Ping Detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.0.20:3 -> 10.0.0.1:3

Investigate EVE JSON

Use EVE as the primary structured evidence source:

sudo jq 'select(.event_type=="alert")' /var/log/suricata/eve.json
sudo jq 'select(.event_type=="dns")' /var/log/suricata/eve.json
sudo jq 'select(.event_type=="http")' /var/log/suricata/eve.json
sudo jq 'select(.event_type=="tls")' /var/log/suricata/eve.json
sudo jq 'select(.event_type=="stats") | .stats.capture' /var/log/suricata/eve.json

For one alert, record its timestamp, signature, action, source and destination, flow_id, community_id, interface, and related protocol events. Community ID can correlate a flow with Zeek, Security Onion, or another compatible data source; flow_id links Suricata events from the same flow. The Wazuh Suricata integration guide provides one example of forwarding this structured evidence into a wider security-monitoring workflow.

Complete EVE alert example

The demonstrated EVE workflow and complete ICMP alert are included below so the structured fields can be compared directly with the shorter queries above.

The more advanced output is the EVE JSON output which is explained in detail in Eve JSON Output. To see what this looks like it's recommended to use jq to parse the JSON output. Alerts:

sudo tail /var/log/suricata/eve.json | jq 'select(.event_type=="alert")'

This will display more detail about each alert with a better readability, including meta-data.

{
  "timestamp": "2024-09-12T14:21:18.932116+1200",
  "flow_id": 1750955545135946,
  "in_iface": "ens32",
  "event_type": "alert",
  "src_ip": "10.0.0.25",
  "src_port": 0,
  "dest_ip": "10.0.0.20",
  "dest_port": 0,
  "proto": "ICMP",
  "icmp_type": 0,
  "icmp_code": 0,
  "pkt_src": "wire/pcap",
  "community_id": "1:7Z0C1taw8mzKweAktDBR9AYDoBA=",
  "alert": {
    "action": "allowed",
    "gid": 1,
    "signature_id": 1,
    "rev": 1,
    "signature": "ICMP Ping Detected",
    "category": "",
    "severity": 3
  },
  "direction": "to_client",
  "flow": {
    "pkts_toserver": 1,
    "pkts_toclient": 1,
    "bytes_toserver": 98,
    "bytes_toclient": 98,
    "start": "2024-09-12T14:21:18.931964+1200",
    "src_ip": "10.0.0.20",
    "dest_ip": "10.0.0.25"
  }
}

Stats:

sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="stats")|.stats.capture.kernel_packets'
sudo tail -f /var/log/suricata/eve.json | jq 'select(.event_type=="stats")'

The first example displays the number of packets captured by the kernel; the second examples shows all of the statistics.

Tune and version the rule

Change one condition at a time, increment rev, repeat both tests, and retain:

  • the rule before and after tuning;
  • the reason for the change;
  • positive and negative evidence;
  • observed event volume; and
  • expected blind spots.
Completion criteriaThe local rule validates, matches only the intended test, and its EVE evidence can be correlated and explained.