Introduction
Snort is a powerful, open-source Network Intrusion Detection System (NIDS). One of its most defining features is its flexible rule-based language, which allows security professionals to define signatures for malicious network activity.
Rules are the bridge between theory and detection. A security idea such as "port scans are suspicious" only becomes operationally useful when you express it in a form the engine can evaluate against real traffic. Learning rule syntax therefore teaches more than Snort itself. It teaches how defenders translate behavior into machine-readable logic.
In this lab, you will learn the core syntax and anatomy of custom Snort rules. You will write foundational rules defining Actions, Protocols, IP addresses, Ports, and Options to specifically detect and alert on targeted ICMP pings and anomalous TCP traffic patterns. By the end of this lab, you will understand how to construct, test, and validate your own Snort rules.
Understand Rule Syntax and Header
In this step, you will learn the basic structure of a Snort rule and create a file to store your custom rules.
The header is really a scope definition. It decides which traffic is even worth evaluating further. That matters because efficient detection begins by narrowing the candidate traffic set as much as possible before deeper content checks are applied. Broad headers are easier to write, but they can also produce more noise.
A Snort rule is divided into two main logical sections: the Rule Header and the Rule Options.
The Rule Header contains the rule's action, protocol, source and destination IP addresses, and source and destination ports. It dictates who is talking to whom and what protocol they are using. The basic syntax looks like this:
[Action] [Protocol] [Source IP] [Source Port] -> [Destination IP] [Destination Port] (Options)
Here is a breakdown of the header components:
- Action: What Snort should do when it finds a packet that matches the rule criteria (e.g.,
alert,log,drop). - Protocol: The protocol of the traffic (e.g.,
tcp,udp,icmp,ip). - IP Addresses: The source and destination IP addresses. You can use
anyto match all IP addresses. - Ports: The source and destination network ports. You can use
anyto match all ports. - Direction Operator: The
->symbol indicates the direction of the traffic (from source to destination). You can also use<>for bidirectional traffic.
To begin writing our own rules, we need a dedicated file. Ensure you are in your default working directory (~/project) and create a new file named local.rules.
Use the touch command to create an empty file:
touch ~/project/local.rules
You can verify that the file was created successfully by listing the contents of your directory:
ls -l ~/project/local.rules
You should see an output similar to this, confirming the file exists and is currently empty:
-rw-r--r-- 1 labex labex 0 Jul 25 10:00 /home/labex/project/local.rules
Write an ICMP Detection Rule
In this step, you will write your first Snort rule to detect ICMP traffic. ICMP (Internet Control Message Protocol) is commonly used by network utilities like ping to check connectivity.
ICMP is a good teaching example because it is simple and easy to recognize, but it also illustrates a real operational point: not every detection means an attack. Many networks legitimately use ping. The job of the analyst is to combine what the rule matched with environmental context before deciding whether the event is benign or suspicious.
We will write a rule that triggers an alert whenever any ICMP packet travels from any source to any destination.
Open your local.rules file using the nano text editor:
nano ~/project/local.rules
Type the following rule into the editor:
alert icmp any any -> any any (msg:"ICMP Ping Detected"; sid:1000001; rev:1;)
Let's break down what this rule means:
alert: The action to take. Snort will generate an alert.icmp: The protocol we are monitoring.any any -> any any: The traffic can originate from any IP and any port, and go to any IP and any port.(msg:"ICMP Ping Detected"; sid:1000001; rev:1;): These are the rule options.msgis the alert message,sidis a unique Snort ID (custom rules must have an ID of 1,000,000 or higher), andrevis the revision number of the rule.
After typing the rule, save the file and exit nano by pressing Ctrl+O, Enter to confirm the filename, and then Ctrl+X to exit.
Now, let's test if Snort understands our rule file. Snort has a test mode (-T) that checks the configuration and rules for syntax errors without actually starting the detection engine.
Run the following command to test your rule file:
sudo snort -T -c ~/project/local.rules
You will see a lot of output as Snort initializes. Look near the bottom of the output for a success message indicating that Snort successfully validated the configuration:
Snort successfully validated the configuration!
Snort exiting
If you see this message, your ICMP rule is syntactically correct.
Write a TCP Port Alert Rule
In this step, you will write a rule to detect specific TCP traffic. While ICMP doesn't use ports, TCP and UDP do. This allows us to write rules that target specific services, such as HTTP (port 80) or SSH (port 22).
Ports give you a rough application context. They do not tell the whole story, but they are often the first approximation defenders use to separate service types. A rule that keys off destination port 80 is essentially saying, "I care about traffic that is probably aimed at a web service."
We will write a rule that alerts us whenever someone attempts to connect to a web server on port 80.
Open your local.rules file again using nano:
nano ~/project/local.rules
Add a new line below your existing ICMP rule and type the following TCP rule:
alert tcp any any -> any 80 (msg:"HTTP Traffic to Port 80 Detected"; sid:1000002; rev:1;)
Let's analyze the header of this new rule:
alert tcp: We are generating an alert for the TCP protocol.any any: The source can be any IP address and any port.->: The traffic is flowing towards the destination.any 80: The destination can be any IP address, but the destination port must be 80.
Notice that we incremented the sid to 1000002. Every Snort rule must have a unique Snort ID.
Save the file (Ctrl+O, Enter) and exit nano (Ctrl+X).
Once again, it is a good practice to test your rule syntax to ensure there are no typos. Run the Snort test command:
sudo snort -T -c ~/project/local.rules
Scroll to the bottom of the output to confirm that Snort successfully validated the configuration. You should now have two rules loaded successfully.
Include Rule Options (Msg, SID, Rev)
In this step, we will dive deeper into the Rule Options section. The options section is enclosed in parentheses () and contains keyword/value pairs separated by semicolons ;.
Rule options are where a rough traffic category becomes a meaningful alert. A clean msg helps a human understand the event. A unique sid lets systems track which rule fired. A rev value lets teams manage detection content over time. These fields support operations, not just syntax.
You have already used the three most fundamental options. The first is msg, which is the message that will be printed in the alert logs and should be descriptive. The second is sid, which stands for Snort ID; rules written by users should have a SID greater than 1,000,000. The third is rev, representing the revision number; every time you modify a rule, you should increment this number to keep track of versions.
Let's write a rule to detect SSH connection attempts (port 22) to practice using these options.
Open your local.rules file:
nano ~/project/local.rules
Add the following rule to the end of the file:
alert tcp any any -> any 22 (msg:"SSH Connection Attempt"; sid:1000003; rev:1;)
In this rule, we set a basic msg and assigned it a new unique SID (1000003).
Suppose we later decide to update the message of this rule to be more specific. We would change the msg and increment the rev to 2. Let's do that now. Modify the SSH rule you just wrote at the bottom of the file to look like this:
alert tcp any any -> any 22 (msg:"Possible SSH Brute Force Attempt"; sid:1000003; rev:2;)
Save the file (Ctrl+O, Enter) and exit nano (Ctrl+X).
Finally, run the syntax check one last time to ensure all three of your rules are perfectly formatted:
sudo snort -T -c ~/project/local.rules
Look for the validation success message. You have now successfully written and structured multiple custom Snort rules using headers and options.
Summary
In this lab, you learned the foundational skills required to write custom Snort rules. You explored the anatomy of a rule, dividing it into the Rule Header and Rule Options. You successfully wrote rules to detect general ICMP traffic and specific TCP port traffic. Furthermore, you learned how to utilize essential rule options like msg, sid, and rev to make your alerts descriptive and uniquely identifiable. These skills form the basis for creating advanced network intrusion detection signatures.



