I built an IDS lab with Snort 2
By Sanjeev · SOC Analyst L1 · May 2026
I built an IDS lab with Snort 2
By Sanjeev · SOC Analyst L1 · May 2026
Lab environment: Snort 2 on Kali Linux · Rules written from scratch (no Snort Community ruleset) Coverage: ICMP tunneling · Network sweeps · Nmap scans · SSH/RDP/FTP brute force · SQLi · XSS
Most people learn intrusion detection by reading documentation. I learned it by firing real attack traffic at my home network and watching Snort catch it — rule by rule. Here’s every custom detection rule I wrote, why I wrote it, and what it taught me.
Why write custom rules at all?
The Snort community ruleset ships with thousands of signatures. But copy-pasting someone else’s rules teaches you nothing about why they work. I wanted to understand the packet-level logic — what a TCP SYN scan actually looks like on the wire, why ICMP payload size matters, what makes an FTP auth failure distinguishable from a successful login.
ICMP: floods, sweeps, and tunnels
ICMP looks harmless because it’s usually just used for ping, but it can actually be abused for scanning networks, launching DDoS attacks, and even hiding command-and-control traffic. I created four detection rules to cover all these different types of threats.
- ICMP flood detection — rate-based threshold on inbound echo requests from a single source:
# ICMP flood detection - rate-based threshold on inbound echo requests from a single source:
alert icmp $EXTERNAL_NET any -> $HOME_NET any (
msg:"ICMP flood detected";
sid:1000004; rev:1;
threshold:type threshold, track by_src, count 40, seconds 60;
)
40 pings per minute per source is the threshold — tuned above normal OS ping behavior but well below flood tooling.
- Network sweep (ping scan) — detects host discovery sweeps:
alert icmp any any -> $HOME_NET any (
msg:"ICMP Network Sweep";
itype:8;
detection_filter:track by_src, count 15, seconds 30;
sid:1000005; rev:1;
)
- ICMP tunnel detection — oversized payloads are the tell:
# Oversized packet (passive anomaly)
alert icmp any any -> $HOME_NET any (
msg:"Oversized ICMP Packet Detected";
dsize:>800; sid:1000006; rev:1;
)
# ICMP tunnel (oversized + repeated = data exfil)
alert icmp any any -> $HOME_NET any (
msg:"Potential ICMP Tunnel Large Payload";
itype:8; dsize:>800;
detection_filter:track by_src, count 5, seconds 30;
sid:1000007; rev:1;
)
Nmap scan detection
Nmap is used so widely that security teams often ignore it as normal traffic. But that is a mistake. A finished Nmap scan is actually early-stage reconnaissance before an attack, because it shows open ports, operating system details, and running services that could be exploited. I created rules to detect the four most risky scan types.
# SYN scan — half-open connections at scale
alert tcp $EXTERNAL_NET any -> $HOME_NET $COMMON_PORTS (
msg:"TCP SYN Scan Detected";
flow:stateless; flags:S,12;
detection_filter:track by_src, count 20, seconds 5;
sid:3000001; rev:1;
)
# XMAS scan — FIN + PSH + URG flags set
alert tcp any any -> $HOME_NET $COMMON_PORTS (
msg:"Detection - XMAS Scan";
flags:FPU;
detection_filter:track by_src, count 30, seconds 60;
sid:10000012; rev:1;
)
# NULL scan — no flags at all
alert tcp any any -> $HOME_NET $COMMON_PORTS (
msg:"Detection - NULL Scan";
flags:0;
detection_filter:track by_src, count 30, seconds 60;
sid:10000014; rev:1;
)
Brute force: SSH, RDP, FTP
Brute force attacks happen when an attacker repeatedly tries many passwords against a service. Instead of focusing only on the repeated login attempts, detection works better by looking at the server’s replies. Failed logins usually generate consistent error responses, and Snort can detect those repeating patterns to spot the attack early.
- SSH brute force — the SSH banner is present in every connection attempt:
alert tcp any any -> $HOME_NET 22 (
msg:"Possible SSH Brute Force";
flow:to_server,established; content:"SSH-";
detection_filter:track by_src, count 5, seconds 60;
sid:1000020; priority:1; rev:1;
)
- RDP brute force — TPKT/X.224 connection request magic bytes:
alert tcp any any -> $HOME_NET 3389 (
msg:"Possible RDP Brute Force";
flow:to_server,established; content:"|03 00|"; offset:0; depth:2;
detection_filter:track by_src, count 5, seconds 60;
sid:10000031; priority:1; rev:1;
)
- FTP brute force + anonymous login:
# Auth failure — 530 response from server to attacker
alert tcp $HOME_NET 21 -> $EXTERNAL_NET any (
msg:"FTP Brute Force - Auth Failure";
flow:from_server,established; content:"530 "; offset:0; depth:4;
detection_filter:track by_dst, count 5, seconds 60;
sid:10000041; priority:2; rev:1;
)
# Anonymous login attempt
alert tcp $EXTERNAL_NET any -> $HOME_NET 21 (
msg:"FTP Anonymous Login Attempt";
flow:to_server,established; content:"USER anonymous"; nocase;
sid:10000042; priority:2; rev:1;
)
Web attacks: SQLi and XSS
Web attack detection in Snort is often noisy because HTTP traffic is high volume and malicious payloads can look similar to normal requests. Accuracy improves when simple content matches are used as anchors and refined with PCRE for deeper pattern detection.
alert tcp any any -> $HOME_NET 80 (
msg:"SQLi UNION SELECT in URI";
flow:to_server,established;
content:"UNION";
nocase; http_uri;
pcre:"/union\s+(all\s+)?select/Ui";
priority:1;
sid:9000051; rev:1;
)
alert tcp any any -> $HOME_NET 80 (
msg:"XSS script tag in URI";
flow:to_server,established;
content:"<script"; nocase; http_uri;
pcre:"/(%3C|<)\s*script/Ui";
priority:1; sid:9000054; rev:2;
)
github — SNORT-IDS-IPS/local.rules at main · s-anjeev/SNORT-IDS-IPS
메타데이터
- post_id
- 5b5dfd14c751
- slug
- i-built-an-ids-lab-with-snort-2-5b5dfd14c751
- url
- https://medium.com/@sanjeevkumar96335/i-built-an-ids-lab-with-snort-2-5b5dfd14c751
- canonical_url
- https://medium.com/@sanjeevkumar96335/i-built-an-ids-lab-with-snort-2-5b5dfd14c751
- author_url
- https://medium.com/@sanjeevkumar96335
- status
- ok
- fetched_at
- 2026-07-10 13:32:34