HackBlue

Tools · Nmap and network discovery · 23 / 25

Detecting Nmap scans with Suricata: rules, thresholds, and testing

Write a threshold-based Suricata rule for SYN sweeps, recognize built-in scan signatures, and test detection against your own lab scan.

10 min read · practice only with authorization

Signatures versus thresholds

Suricata, like Snort, inspects packets against rules. Some community rules match Nmap-specific artifacts, such as the user agent of NSE HTTP scripts, “Mozilla/5.0 (compatible; Nmap Scripting Engine)”. Others use thresholds: alert when one source sends more than N SYNs to distinct ports in T seconds.

Signature rules are precise but easy to sidestep with a changed user agent. Threshold rules catch any scanner, including Nmap’s raw SYN scan, but need tuning so legitimate busy clients do not trigger them.

A simple threshold rule

The rule below matches TCP packets with only SYN set from outside the home network and uses detection_filter to alert once a source exceeds 100 matches in 60 seconds. Put it in a local rules file, include that file in suricata.yaml, and reload.

Set HOME_NET correctly first. Most noisy or silent Suricata deployments trace back to address variables that do not match the real network.

Snippet
alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"LOCAL possible TCP SYN scan"; flags:S,12; \
  detection_filter:track by_src, count 100, seconds 60; classtype:attempted-recon; sid:9000001; rev:1;)

Lab: prove the rule fires

On a lab sensor running Suricata against the host-only interface, load the rule and run a SYN scan from the scanner VM. Check eve.json for the alert with jq. Then run a single connection with curl and confirm it does not fire. Finally run an NSE HTTP script and look for the community user-agent signature if you have the ET Open ruleset loaded.

Record the scan command, the alert, and the timestamp. A detection that has never been tested is a hope, and this lab turns it into evidence.

Snippet
sudo suricata -T -c /etc/suricata/suricata.yaml
sudo systemctl restart suricata
sudo nmap -sS --top-ports 500 192.168.56.101   # from scanner
jq 'select(.event_type=="alert") | [.timestamp, .src_ip, .alert.signature]' /var/log/suricata/eve.json | tail

Tuning for real networks

Exclude your sanctioned vulnerability scanners by address with a pass rule or a suppress entry in threshold.config, and document the exclusion. Otherwise the scanner becomes noise and real scans hide behind it.

For internal networks, lower the count. A workstation sending SYNs to 100 ports in a minute is far more unusual than an internet host doing the same to your edge.

Diagram

From rule to tested detection

  1. Variables

    Set HOME_NET and EXTERNAL_NET to the real ranges.

  2. Rule

    Add a SYN threshold rule with detection_filter.

  3. Test

    Scan from the lab and confirm one alert in eve.json.

    Command
    jq 'select(.event_type=="alert")' eve.json
  4. Tune

    Suppress sanctioned scanners and lower thresholds internally.

Check yourself

1. Which Suricata keyword makes a rule alert only after a count is exceeded?

2. Why are user-agent signatures for NSE weaker than threshold rules?

3. Your vulnerability scanner triggers the rule weekly. What is the right fix?