
Snort 3 IDS → IPS lab on Kali. Custom detection rules + iptables enforcement against ICMP recon, Nmap SYN scans, Hydra FTP brute force, and vsftpd 2.3.4 backdoor (CVE-2011-2523).
A full-cycle deployment of Snort 3 as both an Intrusion Detection System (passive monitoring) and an Intrusion Prevention System (active blocking via iptables), validated against four attack vectors across a three-machine virtual network on Kali Linux.
The lab proves the operational distinction between detection and prevention by running an identical four-vector attack chain twice — first against an IDS that logs but cannot block, then against an IDS + iptables IPS layer that drops attacks selectively while preserving legitimate traffic.
| Component | Details |
|---|
| Analyzer / Router | Kali Linux — 3 adapters: eth0 WAN (192.168.10.143, NAT), eth1 LAN1 (10.10.10.1, host-only), eth2 LAN2 (192.168.50.1, host-only) |
| Attacker | Kali Linux — eth0 on VMnet9 (10.10.10.10) — default gateway 10.10.10.1 |
| Target | Metasploitable 2 — eth0 on VMnet10 (192.168.50.10) — default gateway 192.168.50.1 |
| Snort version | Snort++ 3.12.1.0-0kali1 (installed on Analyzer) |
| Attack tooling | Nmap 7.99, Hydra v9.6, Metasploit Framework (msfconsole) |
| Virtualisation | VMware — VMnet9 = 10.10.10.0/24, VMnet10 = 192.168.50.0/24 (both host-only) |
All traffic between the Attacker and Metasploitable is forced through the Analyzer, making it the natural chokepoint for both monitoring and enforcement.
┌─────────────────────────┐
│ Analyzer / Router │
│ Kali + Snort 3 │
│ │
Attacker Kali ──VMnet9──┤ eth1: 10.10.10.1 │
10.10.10.10 │ │
│ eth0: 192.168.10.143 ───┼──> WAN (NAT)
│ │
Metasploitable 2 ─VMnet10┤ eth2: 192.168.50.1 │
192.168.50.10 │ │
└─────────────────────────┘
Replace this ASCII sketch with
screenshots/01-network-topology.pngonce you have the figure in place:Topology
The lab executes in two stages with an identical four-vector attack chain in each:
ping for host discoverynmap -sS for port enumeration (1000 ports)Stage 1 (IDS) runs Snort passively on the Analyzer with five custom rules — observe alerts in real time, confirm exploitation proceeds anyway.
Stage 2 (IPS) pairs Snort with an iptables enforcement layer using surgical drop rules — confirm attacks are blocked while ICMP ping and legitimate FTP login remain functional.
MASQUERADE + FORWARD rules so the Analyzer routes between subnets and out to the WAN — see scripts/router_config.sh.scripts/ping_check.sh before installing Snort.Snort is installed via the Kali package manager (sudo apt install snort -y) and configured in /etc/snort/snort.conf:
HOME_NET = "10.10.10.0/24,192.168.50.0/24"
EXTERNAL_NET = "any"
ips = {
enable_builtin_rules = true,
include = "/etc/snort/rules/local.rules",
variables = default_variables
}
alert_fast = { file = true, packet = false }
HOME_NET covers both internal subnets so Snort treats all inter-subnet traffic on the Analyzer as worth inspecting. alert_fast produces compact one-line alerts (per-packet logging would generate excessive volume).
Config validation:
sudo snort -T -c /etc/snort/snort.conf
# Result: 652 rules loaded (5 custom text + 647 built-in), 0 warnings
Five rules in /etc/snort/rules/local.rules (full file in scripts/local.rules):
| SID | Name | Trigger |
|---|---|---|
| 1000001 | ICMP Ping Detected | Any ICMP traffic in either direction — catches reconnaissance pings |
| 1000002 | FTP Connection Attempt | Any TCP connection to port 21 — catches legitimate and brute force traffic |
| 1000003 | Possible Nmap SYN Scan | TCP packets with only the SYN flag set (flags:S) — the signature of a half-open scan |
| 1000004 | VSFTPD 2.3.4 Backdoor Attempt | content:":)" on FTP port 21 — the exact CVE-2011-2523 trigger string |
| 1000005 | Possible Metasploit Shellcode | `content:" |
Snort runs in passive mode on both internal interfaces:
sudo snort -c /etc/snort/snort.conf -i eth1 -i eth2 \
-A alert_fast -l /var/log/snort/
# Watch alerts in a second terminal:
sudo tail -f /var/log/snort/alert_fast.txt
Startup output confirms pcap DAQ configured to passive — Snort sees every packet but cannot drop or modify any of them.
After executing scripts/attack_simulator.sh from the Attacker:
| Attack | Detection | Outcome |
|---|---|---|
| ICMP recon | ✅ SID 1000001 — bidirectional alerts | Ping completed |
| Nmap SYN scan | ✅ SID 1000003 — thousands of alerts in <1 second | 23 open ports enumerated |
| Hydra FTP brute force | ✅ SID 1000002 — repeated FTP connection alerts | msfadmin:msfadmin credentials cracked |
| vsftpd 2.3.4 backdoor | ✅ SID 1000004 — :) content match fired | Root Meterpreter shell obtained |
The IDS detected everything and stopped nothing. This is the central lesson of Stage 1: a working IDS without enforcement is an alarm system, not a lock. By the time a human analyst reads the alerts, the attacker is already root.
A secondary observation: Snort's built-in rules (116:408, 116:414) fire on DHCP broadcast traffic — not malicious, but in a production deployment they'd need suppression rules to keep the alert log actionable.
The IPS layer is deployed with scripts/ips_setup.sh, which:
-D) for continued logging| Rule | What it does |
|---|---|
ACCEPT icmp | Explicitly allows all ICMP — preserves connectivity checks |
DROP tcp dpt:21 STRING ":)" | Drops packets containing the vsftpd 2.3.4 backdoor trigger on port 21 |
ACCEPT tcp --syn -m limit --limit 10/s --limit-burst 20 | Allows normal TCP handshakes within rate limit |
DROP tcp --syn (after limit) | Drops SYN floods exceeding 10/s — defeats Nmap SYN scans |
DROP tcp dpt:21 -m connlimit --connlimit-above 5 --connlimit-mask 32 | Blocks > 5 concurrent FTP connections per source — defeats Hydra's parallelism |
ACCEPT eth1→eth0, ACCEPT eth2→eth0 | Normal egress routing |
ACCEPT -m conntrack --ctstate RELATED,ESTABLISHED | Stateful — preserves established sessions |
The same attack script was re-run from the Attacker:
| Attack | Stage 2 outcome |
|---|---|
| ICMP recon | ✅ Allowed (intentional) |
| Nmap SYN scan | ❌ Blocked — 1000 filtered tcp ports (no-response), scan took 21.71 s instead of <1 s |
| Hydra FTP brute force | ❌ Blocked — all children were disabled due too many connection errors — 0 valid password found |
| vsftpd backdoor | ❌ Blocked — Rex::ConnectionTimeout — Exploit completed, but no session was created |
Two manual checks confirmed selective enforcement:
ping -c 4 192.168.50.10 → 4 packets transmitted, 4 received, 0% lossftp 192.168.50.10 with msfadmin:msfadmin → 220 (vsFTPd 2.3.4) … 230 Login successfulQuantitative proof from iptables packet counters during the run: 2051 packets accepted, 12 packets dropped by the FTP connlimit rule, 808 ICMP packets accepted — selective enforcement in numbers.
Even in IPS mode, Snort continued to fire SID 1000002 / 1000003 alerts on packets that reached its passive inspection point before iptables dropped subsequent ones — meaning iptables provides enforcement while Snort provides audit logging, operating in tandem.
| Attack / Traffic | Stage 1 (IDS only) | Stage 2 (IDS + iptables IPS) |
|---|---|---|
| ICMP ping | Detected ✅ | Allowed ✅ (intentional) |
| Nmap SYN scan | Detected — 23 open ports found | Blocked — 1000 filtered |
| Hydra FTP brute force | Detected — msfadmin:msfadmin cracked | Blocked — 0 passwords found |
| vsftpd 2.3.4 exploit | Detected — Root Meterpreter shell | Blocked — connection timeout |
| Legitimate FTP login | n/a | Preserved (230 Login successful) |
Yes — every one of SIDs 1000001–1000004 fired correctly during the attack simulation:
:) content match caught the exact exploit byte sequence.But detection ≠ prevention. The vsftpd exploit opened a root Meterpreter shell while every alert was firing. A SOC analyst watching the IDS in real time would have seen the compromise — but with the attacker already root in seconds, alerting alone is not enough. This is the operational core of why IPS exists.
The implementation achieved complete attack mitigation with zero observable impact on legitimate traffic. The effectiveness comes from surgical rule design — each iptables rule targets a behavioral signature, not a broad protocol:
connlimit per source blocks the parallelism of brute force tools without breaking single-session FTP.STRING match drops the exact exploit payload without filtering legitimate FTP login traffic.One acknowledged limitation: ICMP is fully allowed, which means an attacker can still confirm Metasploitable is alive via ping. In a higher-security environment this would be rate-limited or restricted to trusted sources. In this lab, ICMP is the primary connectivity verification mechanism, so it stays open.
This lab uses a dedicated Snort machine. Compared to running Snort as a plugin inside a firewall appliance like pfSense or OPNsense:
Advantages of the dedicated approach:
Trade-offs:
Dedicated Snort is the correct choice for enterprise environments needing performance, positioning, and customisation. The pfSense/OPNsense plugin approach makes more sense for small business or home lab environments prioritising ease of use.
Stage 2 is technically passive Snort + iptables enforcement, not Snort running in true inline mode — Snort itself logs (pcap DAQ configured to passive), and iptables performs the dropping based on rate limits, string matches, and connection counts.
This is a legitimate and common deployment pattern (it's how many real-world Linux-based IDS/IPS stacks operate). A natural follow-up would be migrating Stage 2 to a true inline configuration using snort --daq nfq (or afpacket in inline mode) with Snort's reject / drop rule actions, so Snort itself performs the dropping based on full signature matching rather than delegating to iptables.
snort-ids-ips-lab/
├── README.md ← this file
├── report/
│ ├── Snort-IDS-IPS-Report.pdf ← full lab report
│ └── Snort-IDS-IPS-Report.docx ← editable source
├── scripts/
│ ├── router_config.sh ← IP forwarding + iptables routing
│ ├── ping_check.sh ← connectivity verification
│ ├── attack_simulator.sh ← 4-vector attack chain
│ ├── ips_setup.sh ← IPS iptables rules + Snort daemon
│ └── local.rules ← 5 custom Snort rules (SID 1000001-1000005)
├── screenshots/ ← report figures
├── .gitignore
└── LICENSE
⚠️ Lab use only. These scripts run real exploits and brute-force tools against a deliberately vulnerable target. Do not run them against any system you do not own and have explicit written authorisation to test.
scripts/router_config.sh, then scripts/ping_check.sh to confirm full connectivity.sudo apt update && sudo apt install snort -y
scripts/local.rules at /etc/snort/rules/local.rules and set HOME_NET = "10.10.10.0/24,192.168.50.0/24" in /etc/snort/snort.conf.sudo snort -T -c /etc/snort/snort.conf — expect 652 rules loaded, 0 warnings.sudo snort -c /etc/snort/snort.conf -i eth1 -i eth2 -A alert_fast -l /var/log/snort/
# In another terminal:
sudo tail -f /var/log/snort/alert_fast.txt
sudo ./scripts/attack_simulator.sh — observe alerts firing and the Meterpreter shell.sudo ./scripts/ips_setup.sh, then re-run the attack chain on the Attacker. Confirm blocks, then manually test:
ping -c 4 192.168.50.10 # should succeed
ftp 192.168.50.10 # msfadmin / msfadmin — should succeed
All activities documented in this repository were conducted exclusively within a self-contained VMware virtual lab environment for supervised academic learning purposes. No external, production, or real-world systems were targeted, scanned, or affected in any way. Metasploitable 2 is an intentionally vulnerable virtual machine designed specifically for security training.
This material must not be used to replicate these activities against any real system without explicit written authorisation from the system owner. Unauthorised port scanning, credential attacks, or exploitation of network services is illegal in most jurisdictions.
MIT — see LICENSE. The lab report itself is provided for educational reference.