The digital world isn’t just a “place” anymore—it’s the battlefield. Every single day, billions of attacks are launched, from automated bots scanning for vulnerabilities to highly sophisticated state-sponsored actors targeting critical infrastructure. Most of this fight is completely invisible. You don’t see the malicious packet, the SQL injection query, or the malware beaconing home. You just see the consequences: the “site down” message, the stolen credit card, the ransomware note.
What if you could see it? What if you could build a digital tripwire—a silent guardian for your network that watches every single piece of data and screams, “Intruder!” the moment something suspicious happens?
That is what a Network Intrusion Detection System (NIDS) does. And today, you are going to build one.
Welcome to the definitive, all-in-one, guide to building a NIDS from scratch using Snort, the most famous and foundational open-source NIDS in the world.
This is not a “copy-paste these five commands” tutorial. This is a “zero-to-hero” masterclass. We’re going to assume you’re starting from scratch. By the end of this guide, you will have gone from “What is a network packet?” to “I am writing my own advanced detection rules to catch hackers” and, most importantly, “I know how to put this on my resume to get a job in cybersecurity.”
This guide will cover:
- Network Fundamentals: We’ll demystify the OSI model, TCP/IP, ports, and packets. You can’t catch a thief if you don’t understand what a “house” or a “door” is.
- Attacker Mindset: We’ll explore how attackers think—port scans, SQL injection, buffer overflows—so you know what to look for.
- Your Home Lab: You’ll build a safe, virtual battlefield to practice on, with attacker and victim machines.
- Snort Installation (The “Pro” Way): We’ll install Snort 3 from source, giving you complete control and a deep understanding of the system.
- Configuration Deep Dive: We will dissect the new
snort.luaconfiguration file, line by line. - The Art of Snort Rules: This is the core of the guide. We will spend thousands of words on a masterclass in rule writing. We’ll go from a simple
pingdetector to complex, stateful rules that catch real-world attack tools. - Logging & Visualization: We’ll make sense of the noise and discuss how to view your alerts in a clean, professional way.
- From Project to Career: We will literally write the resume bullet points this project gives you, turning your new skills into your new job.
Grab a coffee (or three). Open your terminal. Let’s begin.

Demystifying Network Fundamentals
Before we can build our security system, we have to be the architect. We need to understand the blueprints of the very thing we’re protecting. In our case, the blueprint is the modern network. If this section is new to you, do not skip it. This knowledge is the entire foundation of our NIDS.
The OSI Model in Plain English
You’ve probably heard of the “OSI Model.” It’s a 7-layer conceptual model that standardizes how a network functions. You don’t need to be a professor in it, but you do need to know what the key layers do.
- Layer 1: Physical: The wires. The Wi-Fi signals. The literal “physics” of sending a 1 or a 0. We don’t care about this (unless a cable is unplugged).
- Layer 2: Data Link: This is the “local neighborhood” layer. It handles communication between devices on the same network. The key here is the MAC Address, the unique hardware address of your network card (e.g.,
00:1A:2B:3C:4D:5E). - Layer 3: Network: This is the “city-to-city” layer. It handles routing packets between different networks. The key here is the IP Address (e.g.,
192.168.1.10or8.8.8.8). This is Snort’s bread and butter. - Layer 4: Transport: This is the “conversation” layer. It manages the reliability and flow of data. The two protocols you must know are TCP and UDP. This is arguably the most important layer for Snort.
- Layer 5: Session: Manages the “sessions” between applications (e.g., logging in, logging out).
- Layer 6: Presentation: Translates data (e.g., encryption/decryption,
ASCIIvs.EBCDIC). - Layer 7: Application: The layer you interact with. Your browser (HTTP), your email client (SMTP), your file transfer (FTP).
Snort’s Sweet Spot: Snort lives and breathes at Layers 3, 4, and 7. It makes decisions based on:
- Layer 3: “Is this packet from a-bad-IP-address?”
- Layer 4: “Is this a-weird-TCP-handshake?” (like a port scan)
- Layer 7: “Does this-HTTP-data-contain-SQL-injection?”
The TCP/IP Suite
While the OSI model is the theory, the TCP/IP Suite is the practical implementation. Let’s meet the main players.
TCP (Transmission Control Protocol): The “Phone Call”
Think of TCP as a reliable, connection-oriented phone call.
- You pick up the phone and dial.
- The other person answers and says, “Hello?” (Connection established).
- You talk. You know they’re listening because they say “uh-huh” and “yes.” (Flow control and acknowledgment).
- You say “Okay, goodbye.” They say, “Goodbye.” You both hang up. (Connection terminated).
This “phone call” setup is called the Three-Way Handshake. It’s critical.

- Client to Server: “Hi, I’d like to talk.” (This packet has a
SYNflag set). - Server to Client: “Okay, I’m here! Let’s talk. Are you ready?” (This packet has
SYNandACKflags set). - Client to Server: “Yep, I’m ready!” (This packet has an
ACKflag set).
Connection is now established. Why does Snort care? Attackers love to mess with this handshake. An Nmap “SYN Scan” (or “half-open” scan) sends the SYN but never sends the final ACK. A “FIN Scan” sends only a FIN packet to a closed port, which a normal computer would never do. Snort sees this and knows it’s reconnaissance.
UDP (User Datagram Protocol): The “Postcard”
Think of UDP as a postcard.
- You write a message on it.
- You put an address on it.
- You drop it in the mailbox.
You have no idea if it arrived, if it arrived in order, or if it was even readable. You just “fire and forget.” It’s connectionless.
Why use this? It’s FAST. It’s used for services that prioritize speed over perfect reliability, like DNS (Domain Name System), VoIP (voice calls), and online gaming. Snort also cares about UDP. A “UDP Scan” involves sending UDP packets to various ports to see which ones send back an “ICMP Destination Unreachable” message (meaning the port is closed).
IP (Internet Protocol): The “Address on the Envelope”
IP is the “addressing” system. Its only job is to put an “address” (an IP Header) on a piece of data (a packet) and send it on its way. It’s the “to” and “from” address for every packet on the internet. This is Layer 3.
ICMP (Internet Control Message Protocol): The “Network’s Messenger”
ICMP is not for user data. It’s for network devices to talk about the network.
- “Hey, are you there?” – This is a
ping(ICMP Echo Request). - “Yep, I’m here!” – This is a
pingreply (ICMP Echo Reply). - “Sorry, I couldn’t find that network.” – (ICMP Destination Unreachable).
Attackers use this for ping sweeps—pinging every single IP in a network to see who is “alive.” Snort can detect this instantly.
Ports and Protocols
If an IP address (Layer 3) is the street address of a large apartment building, a port (Layer 4) is the specific apartment number.
A single server (one IP) can run many services. Your server might be running a website, an email server, and a secure login service all at once. Ports are how computers know which service to talk to.
80(HTTP): Standard web traffic.443(HTTPS): Secure web traffic.22(SSH): Secure Shell (secure remote login).53(DNS): Domain Name System (translatinggoogle.comto172.217.14.228).25(SMTP): Simple Mail Transfer Protocol (sending email).
Snort uses ports to understand the context of traffic. If it sees traffic on port 80, it will assume it’s HTTP and apply its HTTP-specific detection rules. If an attacker tries to run a command shell on port 80, Snort (if configured correctly) will spot the mismatch and alert.
What is a “Packet” Anyway? Let’s Dissect One
So, let’s put it all together. A “packet” is the unit of data that travels your network. It’s like a digital “Turducken”—a thing stuffed inside a thing stuffed inside a thing. This is called encapsulation.

When your browser requests google.com, here’s what happens:
- Application Layer (Layer 7): Your browser creates an “HTTP GET” request. This is the Data Payload.
- Transport Layer (Layer 4): The OS slaps a TCP Header on it. This header includes the source port (a random high number, e.g.,
51234) and the destination port (443for HTTPS). - Network Layer (Layer 3): The OS slaps an IP Header on that. This includes your IP address (source) and
google.com‘s IP address (destination). - Data Link Layer (Layer 2): The OS slaps an Ethernet Header on that. This includes your network card’s MAC address (source) and your router’s MAC address (destination).
This final, bundled-up “thing” is sent over the wire. Snort’s job is to “de-encapsulate” this—to unwrap all those layers, look deep inside the Data Payload, and ask, “Is this malicious?”
Now that we know what a “normal” network looks like, let’s look at what “abnormal” looks like.
Understanding the Enemy: A NIDS Attacker Primer
You cannot detect what you do not understand. A NIDS is only as smart as the rules it’s given, and those rules are written by people who understand how attackers operate.
A simplified model for cyber attacks is the Cyber Kill Chain. It’s a 7-step process most attackers follow.
- Reconnaissance: Gaining intel. (Who works there? What IPs do they own? What services are they running?)
- Weaponization: Crafting the “weapon” (e.g., a malicious PDF, an exploit script).
- Delivery: Sending the weapon (e.g., a phishing email, a malicious web link).
- Exploitation: The weapon “detonates,” exploiting a vulnerability.
- Installation: The exploit installs malware or a “backdoor” for persistent access.
- Command & Control (C2): The malware “phones home” to the attacker’s server, awaiting instructions.
- Actions on Objectives: The attacker finally does what they came for (steal data, encrypt files, etc.).
A NIDS like Snort is not good at detecting steps 1, 2, or 7. But it is exceptionally good at detecting steps 1 (the active part), 3, 4, and 6.
Common Attack Signatures Snort Catches
Let’s look at the “digital fingerprints” attackers leave behind.
Reconnaissance (The “Casing the Joint” Phase)
Before an attacker breaks in, they “jiggle the doorknobs” and “peek in the windows.” This is port scanning.
- Ping Sweep: The attacker sends an ICMP Echo Request (
ping) to every IP in your network (e.g.,192.168.1.1to192.168.1.254). Everyone who replies is “alive.”- Snort Detects: “Why is one IP suddenly pinging 254 other IPs in 10 seconds? That’s not normal.” -> Alert!
- Port Scan (e.g., Nmap): After finding “alive” hosts, the attacker scans each one for open “doors” (ports).
SYNScan: The “half-open” scan we discussed.XMASScan: Sends a packet withFIN,PSH, andURGflags set. A “closed” port will respond in one way, an “open” port won’t respond at all. This is highly abnormal.NULLScan: Sends a packet with no flags set.- Snort Detects: “This packet has a weird flag combination. That’s a known scan technique.” -> Alert!
Exploitation (The “Boom” Phase)
This is when the attacker tries to break a “door” or “window.”
- SQL Injection (SQLi): An attacker “injects” database commands into a web form.
- A website form asks for your username.
- You type:
' OR 1=1 -- - The website’s insecure code might build a query like:
SELECT * FROM users WHERE username = '' OR 1=1 --' AND password = '...'; - Because of that injection, the query becomes
...WHERE username = '' OR 1=1. Since1=1is always true, the database returns all users. The attacker is in. - Snort Detects: “I see the characters
' OR 1=1in the HTTP request payload. That’s a classic SQLi attempt.” -> Alert!
- Buffer Overflow: The attacker sends too much data to an application that isn’t prepared for it.
- An old app asks for your 20-character name.
- The attacker sends 1,000 “A”s, followed by malicious code.
- The “A”s “overflow” the space reserved for the name and “spill” into the part of memory that holds instructions. The malicious code is now in the instruction path and gets executed.
- Snort Detects: “I see a string of 1,000
\x90(NOP) bytes, which is a ‘NOP Sled’ commonly used in buffer overflows.” -> Alert!
- Cross-Site Scripting (XSS): An attacker injects malicious Javascript into a website (e.g., in a comment). When you visit that page, the script runs in your browser and steals your session cookie.
- Snort Detects: “I see
<script>tags andalert()functions in an HTTP request. That’s a potential XSS attack.” -> Alert!
- Snort Detects: “I see
Command & Control (C2) (The “Phoning Home” Phase)
The exploit worked. The malware is installed. Now what? The malware needs to “phone home” to its master for instructions. This is C2.
- Beaconing: The malware will send a small “heartbeat” packet to a known-bad attacker IP every 60 seconds. “I’m alive. Any instructions?”
- Snort Detects: “This internal IP (
192.168.1.50) is sending traffic to a known Russian C2 server IP (123.45.67.89) every 60 seconds on the dot.” -> Alert!
- Snort Detects: “This internal IP (
- Suspicious DNS: The attacker might use a
google.com-looking domain likegoog1e.com.badguy.ru.- Snort Detects: “I see a DNS request for a domain on a known-bad-domain-list.” -> Alert!
This is what we’re building our NIDS to find. Now, let’s build the lab to test it.
Your Home Lab: Forging the Perfect Battlefield
STOP. Do not install Snort on your main computer.
We are going to be inviting attackers into our network. We will be using real attack tools. You must do this in a safe, isolated, virtual environment. If you do this on your main network, you risk attacking your own router, your roommate’s laptop, or getting your IP banned by your ISP.
You have been warned.
Our lab will be built using VirtualBox (it’s free and works on Windows, Mac, and Linux) and will have three machines:
- The Sensor (Our “Guardian”): We’ll use Ubuntu 22.04 LTS Server. This is where we will install Snort.
- The Attacker (Our “Villain”): We’ll use Kali Linux. This is a Linux distribution pre-loaded with hundreds of hacking tools (like Nmap and Metasploit).
- The Victim (Our “Bait”): We’ll use Metasploitable 2. This is a purposefully vulnerable Linux machine, designed to be hacked for practice.
The Virtual Lab Setup
- Download: Go download and install VirtualBox and the VirtualBox Extension Pack.
- Download OSes:
- Ubuntu Server 22.04 LTS: Get the
.isofrom the official website. - Kali Linux: Get the VirtualBox 64-bit
.ovafile from the official “Kali Linux VM-Images” page. This is a pre-built machine, so it’s easy. - Metasploitable 2: This is a
.zipfile containing a.vmdk. You’ll have to create a new VM and attach this existing disk.
- Ubuntu Server 22.04 LTS: Get the
- Set Up VirtualBox Networking (THE MOST IMPORTANT STEP):
- Go to
File->Tools->Network Manager. - Click
Create. This will make a new “Host-only Network” (e.g.,vboxnet0). - Click on it, and in the “Adapter” tab, make sure “Configure Adapter Manually” is set. Give it an IP like
192.168.56.1and a netmask of255.255.255.0. - This
192.168.56.0/24network is now our private, isolated battlefield.
- Go to
- Create Your VMs:
- Kali: Import the
.ovafile. In the VM’sSettings->Network->Adapter 1, setAttached to:to Host-only Adapter and select yourvboxnet0. - Metasploitable 2:
- Create a “New” VM. Call it “Victim”. Type “Linux”, Version “Ubuntu (64-bit)”.
- Give it 1GB RAM.
- At the “Hard disk” step, choose “Use an existing virtual hard disk file” and select the
.vmdkfile you unzipped. - In
Settings->Network->Adapter 1, setAttached to:to Host-only Adapter and selectvboxnet0.
- Ubuntu Server (Sensor):
- Create a “New” VM. Call it “Sensor”. Type “Linux”, Version “Ubuntu (64-bit)”.
- Give it at least 2GB RAM and 2 CPU cores if you can.
- Create a new virtual hard disk (25GB is fine).
- CRITICAL: In
Settings->Network, we will use TWO network adapters.Adapter 1:SetAttached to:to NAT. This is how our Sensor will get updates from the real internet.Adapter 2:Enable this adapter. SetAttached to:to Host-only Adapter and selectvboxnet0. This is the adapter Snort will listen on. In the “Advanced” dropdown, setPromiscuous Mode:to Allow All. This lets it see all traffic on thevboxnet0network, not just traffic meant for it.
- Kali: Import the
- Install and Update:
- Install Ubuntu Server on your “Sensor” VM. It’s a text-based installer but very straightforward.
- Once all three VMs are running, log in to each and check their IPs.
ip aon each Linux machine.
- Your Kali machine might be
192.168.56.101. - Your Victim machine might be
192.168.56.102. - Your Sensor machine will have two IPs: one (e.g.,
10.0.2.15) on its NAT adapter (let’s sayenp0s3) and one (e.g.,192.168.56.103) on its Host-only adapter (let’s sayenp0s8). - Write these down. The Host-only adapter (
enp0s8in this example) is your monitoring interface.
Your lab is built. The battlefield is set. Now, to arm the guardian.
Installing and Configuring Snort 3
This is the main event. We are going to install Snort 3 from source.
Why not just sudo apt install snort? Because a professional (or someone who wants to be one) needs to know what is in their system. Compiling from source ensures you have the absolute latest version, allows you to customize build flags (for performance), and gives you a deep understanding of the dependencies. It’s the “pro” way.
Log in to your Ubuntu Sensor VM. All the following commands are run on this machine.
Step 1: Get Dependencies
First, let’s update our system. Remember, this works because of our NAT adapter.
sudo apt update
sudo apt upgrade -y
Now, Snort 3 has a lot of dependencies. It needs tools to compile code, libraries to handle regular expressions, libraries for packet capture, and much more. Let’s install them all in one go.
sudo apt install -y build-essential cmake pkg-config libssl-dev libluajit-5.1-dev \
libpcap-dev libpcre3-dev zlib1g-dev liblzma-dev libdnet-dev \
libdumbnet-dev libnetfilter-queue-dev libnet1-dev libyaml-dev \
flex bison git
That’s a beast. Let’s quickly break down the most important ones:
build-essential,cmake: Tools to build (compile) our code.libpcap-dev: The “packet capture” library. This is what lets Snort grab traffic.libpcre3-dev: “Perl-Compatible Regular Expressions” library. For advanced rule matching.libluajit-5.T-dev: The “LuaJIT” library. Snort 3 uses the Lua scripting language for its configuration. This is a huge change from Snort 2.
Step 2: Install libdaq
Before Snort 3, there was libdaq (Data Acquisition Library). This is a helper library that Snort uses to abstract how it gets packets. It’s a prerequisite and must also be built from source.
We’ll build it in a ~/snort-src directory to keep things clean.
mkdir ~/snort-src
cd ~/snort-src
# Clone the repository from GitHub
git clone [https://github.com/snort3/libdaq.git](https://github.com/snort3/libdaq.git)
# Go into the new directory
cd libdaq
# Run the bootstrap script
./bootstrap
# Configure the build
./configure
# Make (compile) the code. -j $(nproc) uses all your CPU cores to speed it up
make -j $(nproc)
# Install the compiled code to the system
sudo make install
Easy. libdaq is now installed.
Step 3: Install Snort 3
Let’s go back to our source directory and get Snort itself.
cd ~/snort-src
# Clone the Snort 3 repository
git clone [https://github.com/snort3/snort3.git](https://github.com/snort3/snort3.git)
# Go into the new directory
cd snort3
# Run the CMake configure script. This is the big one.
# We are telling it where to install ('--prefix') and enabling extra features.
./configure_cmake.sh --prefix=/usr/local/snort
# Go into the 'build' directory that script created
cd build
# Compile Snort! This will take a few minutes.
make -j $(nproc)
# Install Snort to the /usr/local/snort directory
sudo make install
Wait! We’re not done. We’ve installed Snort, but our OS doesn’t know where we put it. We need to update our “shared library” path and create a “symbolic link” so we can type snort from anywhere.
# Update the dynamic linker to find Snort's new libraries
sudo ldconfig
# Create a symbolic link to the 'snort' binary
sudo ln -s /usr/local/snort/bin/snort /usr/sbin/snort
Step 4: Verifying the Install
If everything worked, this next command should be a beautiful thing.
snort -V
You should see output similar to this:
,,_ -*> Snort++ <*-
o" )~$
'''' Version 3.x.x
By Martin Roesch & The Snort Team
(C) 2014-2025 Cisco Systems, Inc., et al.
Congratulations. You have just compiled and installed a professional-grade NIDS from source. Take a bow.
Step 5: The First Run (Sniffer and Dumper Modes)
Snort has three main modes:
- Sniffer Mode: Just shows you the packet headers.
- Packet Dumper Mode: Logs all packets to disk (like Wireshark).
- NIDS Mode: The one we want. Runs against a set of rules.
Let’s test the first two. Find your monitoring interface (the Host-only one, e.g., enp0s8).
# Test Sniffer Mode (v = verbose)
sudo snort -v -i enp0s8
You’ll see a live stream of packet headers. Go to your Kali machine and ping 192.168.56.103 (your Sensor). You’ll see the ICMP packets fly by. Press Ctrl+C to stop.
# Test Packet Dumper Mode (d = dump payload, e = show headers)
sudo snort -d -e -i enp0s8
This will show you the headers and the data. Now, let’s get to the real configuration.
Step 6: The Heart of Snort: Dissecting snort.lua
Welcome to the new world. Snort 2 used snort.conf, a text file. Snort 3 uses snort.lua, a Lua script. This is infinitely more powerful.
The default config is at /usr/local/snort/etc/snort/snort.lua. DO NOT EDIT THIS FILE. We’ll override it.
Let’s copy the defaults to a place we can edit.
sudo mkdir /etc/snort
sudo cp -r /usr/local/snort/etc/snort/* /etc/snort/
Now, let’s edit our new config file: sudo nano /etc/snort/snort.lua.
You will see a lot of stuff. Don’t be intimidated. 90% of it is fine as-is. We only care about a few key variables.
HOME_NET and EXTERNAL_NET
This is, without question, the most important setting in Snort. You must get this right.
HOME_NET: This is your network. The one you are protecting.EXTERNAL_NET: This is everyone else (the “internet”).
Snort uses this to understand the direction of an attack. A connection from EXTERNAL_NET to HOME_NET is very different from one inside HOME_NET.
Find this section in your snort.lua (around line 100):
-- setup the network addresses you want to protect
HOME_NET = 'any'
-- set up the external network addresses.
-- (must be a string! see manual)
EXTERNAL_NET = '!$HOME_NET'
Change HOME_NET from 'any' to our virtual lab network.
-- setup the network addresses you want to protect
HOME_NET = '192.168.56.0/24'
-- set up the external network addresses.
-- (must be a string! see manual)
EXTERNAL_NET = '!$HOME_NET'

Now Snort knows that any IP from 192.168.56.1 to 192.168.56.254 is “us.” Everyone else is “them.”
ips block and RULE_PATH
Scroll down (a lot) until you see the ips = { ... } block. This is the main “Intrusion Prevention System” configuration.
Inside it, you’ll see a rules = [[ ... ]] section. This is where we tell Snort where to find its rules. It’s pre-filled with a lot of include statements.
We need to make sure the paths are correct. Our default rule files were copied to /etc/snort/rules. The default config should be set up to use relative paths, but it’s good to check.
The main thing we need to do is create a file for our own custom rules.
Find the ips block and add this line inside the rules = [[ ... ]] string, right at the top:
ips =
{
...
rules = [[
include 'local.rules'
-- all the other 'include $RULE_PATH/...' stuff is here
...
]]
}
This tells Snort to load a file named local.rules. This file doesn’t exist yet. We’ll create it. This is where we will write all our rules.
Save the snort.lua file and exit nano (Ctrl+X, Y, Enter).
Step 7: Getting Your Rules
Snort is just an “engine.” The “rules” are the “ammunition” that tell the engine what to look for.
You can get rule sets (thousands of pre-written rules) from a few places.
- Snort Subscriber Ruleset: The official, up-to-the-minute rules from Cisco Talos. This is paid, but it’s free for personal/home use (with a 30-day delay).
- Snort Community Ruleset: Free, open-source rules. Good, but not as comprehensive.
- Emerging Threats (ET) Open: A very popular free ruleset (now owned by Proofpoint).
For a professional setup, you’d use a tool like PulledPork or Oinkmaster to automatically download, manage, and update these rulesets every day. This is a massive topic on its own.
For now, our installation came with the basic Community Ruleset, which is enough for us to start. We copied them to /etc/snort/rules/.
Let’s create our local.rules file:
sudo touch /etc/snort/local.rules
This file is currently empty. We’ll fill it in Part 5.
Step 8: Validating Configuration and Firing Up NIDS Mode!
We’re ready. We’ve installed Snort, we’ve configured HOME_NET, and we’ve told Snort where to find its rules.
Let’s do a Test Run. The -T flag tells Snort to load its configuration, parse all the rules, and then… exit. It’s a “syntax check.” If this command works, you are golden.
sudo snort -c /etc/snort/snort.lua -T
You will see a ton of output as Snort loads and parses thousands of rules. Be patient. This can take 30-60 seconds.
If it ends with a beautiful message like this, you are ready:
Snort successfully validated the configuration!
Snort exiting
If it fails, read the error. 99% of the time, it’s a typo in snort.lua or a bad HOME_NET variable.
Now, let’s run it for real.
# -c : path to our config
# -i : our MONITORING interface
# -A full : Alert mode. 'full' logs the full packet
# -q : Quiet. Don't print to console, just log
# & : The '&' at the end runs the process in the background
sudo snort -c /etc/snort/snort.lua -i enp0s8 -A full -q &
Snort is now running, silently, in the background. It is watching everything on the 192.168.56.0/24 network.
Where are the logs? By default, they go to /var/log/snort/. Let’s watch the alert log file in real-time:
tail -f /var/log/snort/alert.log
This will sit and wait. It’s an empty file.
…for now.
Go to your Kali Attacker VM. Let’s make some noise. Let’s run a simple ping.
# On the Kali VM
ping 192.168.56.102 # The Victim's IP
Look back at your Sensor’s terminal. Nothing. Why? Because a ping is normal. We haven’t written a rule to detect it yet.
This is the most important lesson: Snort only detects what it’s told to detect.
Let’s go tell it something.
A Masterclass on Snort Rules
This is the part that separates the script-kiddies from the security professionals. A rule is a single line of text, but it’s a line of pure, condensed logic.
Let’s open our custom rules file.
sudo nano /etc/snort/local.rules
It’s empty. Let’s add our very first rule.
Anatomy of a Snort Rule
A Snort rule has two parts: [Rule Header] ([Rule Options])
- Rule Header: Who, what, where. (The “metadata”).
- Rule Options: The “evidence.” What specifically to look for.
Let’s write our first rule, Rule #1: Detect a Ping (ICMP Echo) Sweep.
Add this line to your local.rules file:
alert icmp $EXTERNAL_NET any -> $HOME_NET any (msg:"ICMP Ping (Possible Sweep)"; icode:8; icmptype:8; classtype:attempted-recon; sid:1000001; rev:1;)
Save and exit (Ctrl+X, Y, Enter).
Let’s break this down, word by word.
Rule Header Breakdown:
alert icmp $EXTERNAL_NET any -> $HOME_NET any
alert: This is the Action. What to do.alert(create an alert and log the packet) is the most common. Others arelog,pass(ignore),drop(if in IPS mode),reject.icmp: This is the Protocol. (Layer 3/4). We’re looking foricmppackets. Other values aretcp,udp,ip.$EXTERNAL_NET: This is the Source IP. We’re using the variable we defined insnort.lua. This means “any IP not in our home network.”any: This is the Source Port. ICMP doesn’t really use ports, so we sayany.->: This is the Direction Operator. It means “going to.”$HOME_NET: This is the Destination IP. “Any IP inside our protected network.”any: This is the Destination Port.
In English, this header says: “Alert me on any ICMP packet that comes from the outside world and is going to my network.”
Rule Options Breakdown:
(msg:"ICMP Ping (Possible Sweep)"; icode:8; icmptype:8; classtype:attempted-recon; sid:1000001; rev:1;)
This whole section is wrapped in (...). Every option ends with a semicolon ;.
msg:"...": This is the Message. It’s what you see in the log. Make it descriptive.icode:8; icmptype:8;: These are Rule Options specific to ICMP. An ICMP Type 8, Code 8 packet is an Echo Request. Aping. This is the “evidence” that makes our rule specific. We don’t care about all ICMP, just pings.classtype:attempted-recon;: This categorizes the alert. It’s a standard classification.sid:1000001;: The Snort ID. This is a unique ID for the rule. The official rules use SIDs below 1,000,000. All your custom rules must besid:1000001or higher.rev:1;: The Revision number. If you edit this rule later, you’d change it torev:2;.
Let’s test it.
We need to restart Snort to load the new rule.
# Stop the old, backgrounded Snort
sudo pkill snort
# Start it again, just like before
sudo snort -c /etc/snort/snort.lua -i enp0s8 -A full -q &
# Watch the log file
tail -f /var/log/snort/alert.log
Now… go to your Kali Attacker VM. Your vboxnet0 adapter has an IP of 192.168.56.101. This is inside $HOME_NET. A ping from here won’t trigger the rule.
Your main computer (the “Host”) also has an IP on that vboxnet0 network, 192.168.56.1. This is also inside $HOME_NET.
Let’s change the rule slightly to test it. Change $EXTERNAL_NET to any.
alert icmp any any -> $HOME_NET any ( ... )
Restart Snort. Go to your Kali VM. ping 192.168.56.102 (The Victim)
BOOM. Look at your Sensor terminal.

[**] [1:1000001:1] ICMP Ping (Possible Sweep) [**] [Classification: attempted-recon] [Priority: 2] {ICMP} 192.168.56.101 -> 192.168.56.102
You did it. You wrote a rule, and it fired. This is the fundamental loop of a NIDS analyst. Write, test, deploy, tune.
Let’s get more advanced. Change the rule back to $EXTERNAL_NET.
Let’s Write More Rules!
Open sudo nano /etc/snort/local.rules again.
Rule #2: Detect an Nmap XMAS Scan (Recon)
Attackers use this to be stealthy. It’s highly suspicious.
alert tcp $EXTERNAL_NET any -> $HOME_NET any (msg:"SCAN Nmap XMAS Scan"; flags:FPU, 12; classtype:attempted-recon; sid:1000002; rev:1;)
- Header:
alert tcp ...We’re looking for TCP packets this time. - Options:
flags:FPU, 12;: This is the magic. Theflagskeyword looks at the TCP flags (SYN,ACK,FIN,PSH,URG, etc.). This rule says “Alert if theFIN,PSH, andURGflags are SET (FPU), and theACK,RST, andSYNflags are NOT set (12is the “mask” for those).” This is the exact signature of an Nmap XMAS scan.
Test it: Restart Snort. Go to your Kali VM. sudo nmap -sX 192.168.56.102 (The -sX is for XMAS scan). Your log file will explode with alerts.
Rule Options (The “Body”): The General Keywords
Let’s pause and build our toolkit.
msg: The message. (Required, sort of).sid: The ID. (Required).rev: The revision. (Required).classtype: The category. (Good practice).priority:priority:1;(1-4, 1 is highest. Good for sorting).
Rule Options (The “Payload”): The Detection Keywords
This is the real power. This is how we look inside the packet’s data.
content:"...": The workhorse. This searches the entire packet payload for this exact string.content:"/bin/bash";– Looks for the literal string “/bin/bash”.content:"|90 90 90|";– Looks for hex content.|...|means “treat this as hex bytes.”\x90is a “No-Operation” (NOP) byte, used in buffer overflows.
nocase: Makes the previouscontentmatch case-insensitive.content:"Password="; nocase;– Will matchPassword=,password=,PaSsWoRd=, etc.
http_...keywords: These are pre-processor keywords. They are much faster than a simplecontentmatch because they only look in specific parts of an HTTP request.http_method: Looks only in the method.content:"POST"; http_method;http_uri: Looks only in the URL.content:"/admin.php"; http_uri;http_user_agent: Looks only at the User-Agent.content:"sqlmap"; http_user_agent;(Detects thesqlmaphacking tool).http_header: Looks at the general headers.
pcre:"/.../": Perl-Compatible Regular Expressions. The “god mode” of content matching. This lets you use complex patterns.pcre:"/SELECT.+FROM.+WHERE/i"– A very basic SQLi detector. The/iat the end means “case-insensitive.”
- Payload Location Keywords:
offset:10;: Start searching 10 bytes into the payload.depth:5;: Only search for 5 bytes from the start (or from the offset).content:"SSH-"; depth:4;distance:5;: After acontentmatch, the nextcontentmust be at least 5 bytes away.within:10;: After acontentmatch, the nextcontentmust be within 10 bytes.
Rule Options (The “State”): The Flow Keywords
flow:: This is super important. It tracks TCP sessions.flow:established,to_server;: “Alert only on packets from the client to the server in an established (post-handshake) session.” This is how you ignore all the noise and look for the attack payload.flow:to_client;: “Alert on packets from the server to the client.” (e.g., sending the exploit back).
flowbits:: The “memory” of Snort.flowbits:set,user.logged.in;– In a rule that detects a successful login, set this flag.flowbits:isset,user.logged.in;– In another rule (e.g.,content:"rm -rf /"), check if that flag is set. This lets you chain rules: “Alert if a logged-in user tries to delete the server.”
Rule Options (The “Rate”): The Thresholding Keywords
threshold:/detection_filter:: This is how you stop alert floods.detection_filter: track by_src, count 1, seconds 60;– “This rule can only fire once every 60 seconds for each unique source IP.” This is essential for rules like ourpingrule.threshold: type limit, track by_src, count 5, seconds 60;– “Don’t alert on the 1st, 2nd, 3rd, or 4th event. Alert on the 5th event, and then stop alerting for 60s.” This is how you detect a brute-force attack.
Okay. Class is over. Let’s write the rest of the rules.
Rule #3: Detect a Simple SQL Injection Attempt (Exploitation)
alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (msg:"WEB Basic SQLi Attempt (1=1)"; flow:established,to_server; content:"OR 1=1"; nocase; http_uri; classtype:web-application-attack; sid:1000003; rev:1;)
- Header:
tcp, fromEXTERNAL_NET, going to our server on port 80 (HTTP). - Options:
flow:established,to_server;: Only on real client requests.content:"OR 1=1";: The “evidence.”nocase;: Makes it case-insensitive.http_uri;: Only look in the URL (e.g.,.../page.php?id=1 OR 1=1).
Test it: Restart Snort. From your Kali VM, open a terminal (or Firefox): curl "http://192.168.56.102/index.php?id=1' OR 1=1" Check your logs. You’ll get an alert.
Rule #4: Detect the “sqlmap” Hacking Tool (Recon/Exploitation)
alert tcp $EXTERNAL_NET any -> $HOME_NET 80 (msg:"TOOL User-Agent sqlmap"; flow:established,to_server; content:"User-Agent|3a| sqlmap"; nocase; http_header; classtype:policy-violation; sid:1000004; rev:1;)
- Options:
content:"User-Agent|3a| sqlmap";: We’re looking forUser-Agent: sqlmap. The|3a|is the hex code for the colon (:) character. This is more reliable than a literal:.http_header;: Tells Snort thiscontentis in the HTTP headers.
Test it: sqlmap isn’t installed on Kali by default, but if it were, and you ran it (sqlmap -u "http://..."), this rule would fire instantly.
Rule #5: Detect a Brite Force SSH Login Attempt (Exploitation)
This one is cool. We want to detect repeated failures.
alert tcp $EXTERNAL_NET any -> $HOME_NET 22 (msg:"ATTACK SSH Brute Force"; flow:established,to_server; content:"SSH-2.0-"; depth:8; threshold: type limit, track by_src, count 5, seconds 120; classtype:attempted-admin; sid:1000005; rev:1;)
- Header: Going to our server on port 22 (SSH).
- Options:
content:"SSH-2.0-"; depth:8;: This just identifies an SSH connection.threshold: type limit, track by_src, count 5, seconds 120;: This is the entire rule.type limit: Don’t alert on the first ones.track by_src: Track this count per source IP.count 5: Alert on the 5th attempt.seconds 120: Within a 120-second (2 minute) window.
In English: “If a single IP tries to connect to our SSH port 5 times in 2 minutes, then send me an alert.”
Test it: Restart Snort. On Kali, use the hydra tool (a brute-forcer): hydra -l user -p passwordlist.txt 192.168.56.102 ssh (You’ll need to make a fake passwordlist.txt). After the 5th attempt, your log will light up.
You are now writing advanced, stateful detection rules.
Logging and Visualization
Okay, so we have alerts popping up in alert.log. This is great for real-time testing, but in the real world, you’d get thousands of alerts a day. A text file is useless.
We need a way to store, sort, and visualize this data.
The Old Way: Barnyard2 + Snorby + MySQL
For a decade, the “classic” stack was:
- Snort: Runs in NIDS mode and outputs to a special binary format (
unified2). - Barnyard2: A separate program that only reads the
unified2files and “shovels” them into… - A MySQL Database: A standard SQL database.
- Snorby: A beautiful (but now-dead) web interface that reads from the MySQL database and gives you a dashboard.
This stack is obsolete and Snorby is unmaintained. Do not use it.
The Modern Way: The ELK/Elastic Stack
The professional standard today is the Elastic Stack (formerly ELK):
- Elasticsearch: A powerful, scalable search database.
- Logstash: A “pipeline” tool that can receive logs, parse them, and send them to Elasticsearch.
- Kibana: A gorgeous visualization and dashboard tool that sits on top of Elasticsearch.

Snort 3 makes this so easy because it can log directly to JSON.
In your snort.lua, you can configure a JSON logger:
-- Add this to your main config
alert_json =
{
file = true,
filename = 'alert.json',
limit = 10,
}
This will create a /var/log/snort/alert.json file. This structured JSON file can be easily read by a tool called Filebeat (a lightweight version of Logstash) which ships it directly to your Elastic Stack.
Setting up a full ELK stack is a whole other guide. But know that this is the path. The job is: Snort -> alert.json -> Filebeat -> Elasticsearch -> Kibana
This is the stack used by thousands of Security Operations Centers (SOCs) around the world.
Beyond the Tutorial: The Real World
You’ve built the lab, installed the tool, and written the rules. You are 90% of the way there. Here’s the last 10%.
Snort vs. Suricata vs. Zeek (Bro)
You’ll hear these names. Here’s the difference.
- Snort: The OG. Single-threaded for a long time (Snort 3 is better). The lingua franca of rules. Everyone knows Snort.
- Suricata: The “new Snort.” It was built from the ground up to be multi-threaded, so it’s much faster on modern multi-core CPUs. It’s also 100% compatible with Snort’s rules. Many people are moving from Snort to Suricata for high-speed networks.
- Zeek (formerly Bro): A completely different beast.
- Snort and Suricata are Signature-Based. They look for known bad things (a
ping,OR 1=1, etc.). - Zeek is a Network Security Monitor. It’s not (primarily) an “alerting” engine. It’s a “logging” engine. It watches your network and creates transaction logs for everything.
- It creates
http.log(a log of every HTTP request),dns.log(every DNS query),ssl.log(every SSL handshake),files.log(every file sent over the network). - A SOC analyst doesn’t ask Zeek “Did an attack happen?” They use Snort for that. They use Zeek to investigate the alert.
- Snort: “Alert! SQLi from 1.2.3.4!”
- Analyst: “Okay, let me check the Zeek
http.logfor 1.2.3.4. Oh, I see. He hit/login.php, then/admin.php, then tried to downloadusers.csv. This is a real incident.”
- Snort and Suricata are Signature-Based. They look for known bad things (a
The Pro Setup: You run all three. Suricata or Snort for alerts, and Zeek for the logs.
From Project to Career: How to Use This Guide
You didn’t just “install Snort.” You did so much more.
Do not, on your resume, write:
- “Installed Snort.”
Instead, you will now write:
- “Designed and deployed a virtualized cybersecurity home lab using VirtualBox, Ubuntu Server, Kali Linux, and Metasploitable 2.”
- “Compiled, installed, and configured a Snort 3 Network Intrusion Detection System (NIDS) from source code, hardening the configuration for a virtual network.”
- “Authored a custom, high-fidelity Snort ruleset to detect network reconnaissance (Nmap), exploitation (SQLi, SSH Brute Force), and policy violations (Hacking Tools).”
- “Analyzed network traffic at the packet level using Snort and
tcpdumpto identify and validate attack signatures, tuning rules to reduce false positives.” - “Gained foundational experience in network security monitoring, packet analysis, and signature-based detection methodologies.”
That is the difference between a “hobby” and “a SOC Analyst candidate.”
Conclusion: You’re Not a Beginner Anymore
If you’ve made it this far, you’ve done the work.
You started with the pure theory of a TCP handshake. You built a virtual environment from scratch. You compiled a complex piece of C++ code from its source. You learned a new scripting language (Lua) for configuration. You learned a new, domain-specific language for writing rules. You’ve performed (and, more importantly, detected) real-world cyber attacks.
You now understand the “how” and the “why” of network defense. You’ve seen the “invisible” fight.
The world of network security is vast, but you are no longer standing at the outside, looking in. You are on the wall. You’ve built your first watchtower, you’ve armed your first guard, and you’ve seen the enemy at the gates.
Keep tuning. Keep learning. Keep building. And welcome to the 1% of people who actually understand what’s happening on their network.








