The first tutorial in this series explained how to install and configure Suricata. If you followed that tutorial, you also learned how to download and update Suricata rulesets, and how to examine logs for alerts about suspicious activity. However, the rules that you downloaded in that tutorial are numerous, and cover many different protocols, applications, and attack vectors that may not be relevant to your network and servers.
In this tutorial you’ll learn how Suricata signatures are structured, and some important options that are commonly used in most rules. Once you are familiar with how to understand the structure and fields in a signature, you’ll be able to write your own signatures that you can combine with a firewall to alert you about most suspicious traffic to your servers, without needing to use other external rulesets.
This approach to writing and managing rules means that you can use Suricata more efficiently, since it only needs to process the specific rules that you write. Once you have a ruleset that describes the majority of the legitimate and suspicious traffic that you expect to encounter in your network, you can start to selectively drop invalid traffic using Suricata in its active Intrusion Prevention (IPS) mode. The next tutorial in this series will explain how to enable Suricata’s IPS functionality.
For the purposes of this tutorial, you can run Suricata on any system, since signatures generally do not require any particular operating system. If you are following this tutorial series, then you should already have:
suricata-update
command, and included in your Suricata signatures.Suricata signatures can appear complex at first, but once you learn how they are structured, and how Suricata processes them, you’ll be able to create your own rules to suit your network’s requirements.
At a high level, Suricata signatures consist of three parts:
sid
), log message, regular expressions that match the contents of packets, classification type, and other modifiers that can help narrow identify legitimate and suspicious traffic.The general structure of a signature is the following:
ACTION HEADER OPTIONS
The header and options portions of a signature have multiple sections. For example, in the previous tutorial, you tested Suricata using the rule with sid
2100498. Here is the complete rule for reference:
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)
The alert
portion of the signature is the action, the ip any any -> any any
section is the header, and the rest of the signature starting with (msg:GPL ATTACK_RESPONSE...
contains the rule’s options.
In the following sections you’ll examine each part of a Suricata rule in detail.
The first part of the sid:2100498
signature is the action, in this case alert
. The action portion of a Suricata signature specifies the action to take when a packet matches the rule. An action can be one of the following depending on whether Suricata is operating in IDS or IPS mode:
Each Suricata signature has a header section that describes the network protocol, source and destination IP addresses, ports, and direction of traffic. Referring to the example sid:2100498
signature, the header section of the rule is the highlighted ip any any -> any any
portion:
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)
The general format of a rule’s header section is:
<PROTOCOL> <SOURCE IP> <SOURCE PORT> -> <DESTINATION IP> <DESTINATION PORT>
The Protocol can be one of the following:
The Source and Destination fields can be IP addresses or network ranges, or the special value any
, which will match all IP addresses and networks. The ->
arrow indicates the direction of traffic.
Note: Signatures can also use a non-directional marker <>
that will match traffic in both directions. However, the Suricata documentation about directional markers notes that most rules will use the ->
right matching arrow.
If you wanted to alert on malicious outbound traffic (that is traffic leaving your network), then the Source field would be the IP address or network range of your system. The Destination could be a remote system’s IP or network, or the special any
value.
Conversely, if you wanted to generate an alert for malicious incoming traffic, the Source field could be set to any
, and the Destination to your system’s IP address or network range.
You can also specify the TCP or UDP port to examine using the Port fields. Generally, traffic originating from a system is assigned a random port, so the any
value is appropriate for the left side of the ->
indicator. The destination port can also be any
if you plan to examine the contents of every incoming packet, or you can limit a signature to only scan packets on individual ports, like 22 for SSH traffic, or 443 for HTTPS.
The ip any any -> any any
header from sid:2100498
is a generic header that will match all traffic, regardless of protocol, source or destination IPs, or ports. This kind of catch all header is useful when you want to ensure inbound and outbound traffic is checked for suspicious content.
Note that the Source, Destination, and Port fields can also use the special !
negation operator, which will process traffic that does not match the value of the field.
For example, the following signature would make Suricata alert on all incoming SSH packets from any
network that are destined for your network (represented by the 203.0.113.0/24
IP block), that are not destined for port 22:
alert ssh any any -> 203.0.113.0/24 !22 (sid:1000000;)
This alert would not be that useful, since it does not contain any message about the packet, or a classification type. To add extra information to an alert, as well as match on more specific criteria, Suricata rules have an Options section where you can specify a number of additional settings for a signature.
The arguments inside the parenthesis (. . .)
in a Suricata signature contain various options and keyword modifiers that you can use to match on specific parts of a packet, classify a rule, or log custom messages. Whereas a rule’s header arguments operate on packet headers at the IP, port, and protocol level, options match on the data contained inside a packet.
Options in a Suricata rule must be separated by a ;
semicolon, and generally use a key:value format. Some options do not have any settings and only the name needs to be specified in a rule.
Using the example signature from the previous section, you could add the msg
option with a value of SSH traffic detected on non-SSH port
explaining what the alert is about:
alert ssh any any -> 203.0.113.0/24 !22 (msg:"SSH TRAFFIC on non-SSH port"; sid:1000000;)
A full explanation of how you can use each option in a Suricata rule is beyond the scope of this tutorial. The Suricata rules documentation beginning in Section 6.2 describes each keyword option in detail.
However, there are some core options like the content
keyword and various Meta keywords that are used in most signatures, which we’ll examine in the following sections.
Content
KeywordOne of the most important options for any rule is the content
keyword. Recall the example sid:2100498
signature:
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)
The highlighted content:"uid=0|28|root|29|";
portion contains the content
keyword, and the value that Suricata will look for inside a packet. In the case of this example signature, all packets from any IP address on any port will be checked to ensure they do not contain the string value uid=0|28|root|29|
(which in the previous tutorial was used as an example indicating a compromised host).
The content
keyword can be used with most other keywords in Suricata. You can create very specific signatures using combinations of headers, and options that target specific application protocols, and then check packet contents for individual bytes, strings, or matches using regular expressions.
For example, the following signature examines DNS traffic looking for any packet with the contents your_domain.com
and generates an alert:
alert dns any any -> any any (msg:"DNS LOOKUP for your_domain.com"; dns.query; content:"your_domain.com"; sid:1000001;)
However, this rule would not match if the DNS query used the domain YOUR_DOMAIN.COM
, since Suricata defaults to case-sensitive content matching. To make content matches insensitive to case, add the nocase;
keyword to the rule:
alert dns any any -> any any (msg:"DNS LOOKUP for your_domain.com"; dns.query; content:"your_domain.com"; nocase; sid:1000001;)
Now any combination of lower or uppercase letters will still match the content
keyword.
msg
KeywordThe example signatures in this tutorial have all contained msg
keywords with information about a signature. While the msg
option is not required, leaving it blank makes it difficult to understand why an alert or drop action has occurred when examining Suricata’s logs.
A msg
option is designed to be a human-readable text description of an alert. It should be descriptive and add context to an alert so that you or someone else who is analyzing logs understand why the alert was triggered. In the [reference
Keyword](reference
Keyword) section of this tutorial you will learn about the reference
option that you can use to link to more information about a signature and the issue it is designed to detect.
sid
and rev
KeywordsEvery Suricata signature needs a unique Signature ID (sid
). If two rules have the same sid
(in the following example output it is sid:10000000
), Suricata will not start and will instead generate an error like the following:
Example Duplicate sid Error. . .
19/11/2021 -- 01:17:40 - <Error> - [ERRCODE: SC_ERR_DUPLICATE_SIG(176)] - Duplicate signature "drop ssh any any -> 127.0.0.0/8 !22 (msg:"blocked invalid ssh"; sid:10000000;)"
. . .
When you create your own signatures, the range 1000000-1999999 is reserved for custom rules. Suricata’s built-in rules are in the range from 2200000-2299999. Other sid
ranges are documented on the Emerging Threats SID Allocation page.
The sid
option is usually the last part of a Suricata rule. However, if there have been multiple versions of a signature with changes over time, there is a rev
option that is used to specify the version of a rule. For example, the SSH alert from earlier in this tutorial could be changed to only scan for SSH traffic on port 2022:
alert ssh any any -> 203.0.113.0/24 2022 (msg:"SSH TRAFFIC on non-SSH port"; sid:1000000; rev:2;)
The updated signature now includes the rev:2
option, indicating it has been updated from a previous version.
reference
KeywordThe reference
keyword is used in signatures to describe where to find more information about the attack or issue that a rule is meant to detect. For example, if a signature is designed to detect a new kind of exploit or attack method, the reference field can be used to link to a security researcher or company’s website that documents the issue.
The Heartbleed vulnerability in OpenSSL is an example of a widely publicized and researched bug. Suricata comes with signature that is designed to check for incorrect TLS packets and includes a reference to the main Heartbleed CVE entry :
alert tls any any -> any any (msg:"SURICATA TLS invalid heartbeat encountered, possible exploit attempt (heartbleed)"; flow:established; app-layer-event:tls.invalid_heartbeat_message; flowint:tls.anomaly.count,+,1; classtype:protocol-command-decode; reference:cve,2014-0160; sid:2230013; rev:1;)
Note the highlighted reference:cve,2014-0160;
portion of the signature. This reference option tells you or the analyst who is examining alerts from Suricata where to find more information about the particular issue.
The reference option can use any of the prefixes from the /etc/suricata/reference.config
file. For example, url
could be used in place of cve
in the preceding example, with a link directly to the Heartbleed site in place of the 2014-0160
CVE identifier.
classtype
KeywordSuricata can classify traffic according to a preconfigured set of categories that are included when you install the Suricata package with your Linux distribution’s package manager. The default classification file is usually found in /etc/suricata/classification.config
and contains entries like the following:
#
# config classification:shortname,short description,priority
#
config classification: not-suspicious,Not Suspicious Traffic,3
config classification: unknown,Unknown Traffic,3
config classification: bad-unknown,Potentially Bad Traffic, 2
. . .
As indicated by the file header, each classification entry has three fields:
not-suspicious
, unknown
, and bad-unknown
respectively.Not Suspicious Traffic
.In the example sid:2100498
signature, the classtype is classtype:bad-unknown;
, which is highlighted in the following example:
alert ip any any -> any any (msg:"GPL ATTACK_RESPONSE id check returned root"; content:"uid=0|28|root|29|"; classtype:bad-unknown; sid:2100498; rev:7; metadata:created_at 2010_09_23, updated_at 2010_09_23;)
The implicit priority for the signature is 2, since that is the value that is assigned to the bad-unknown
classtype in /etc/suricata/classification.config
. If you would like to override the default priority for a classtype, you can add a priority:n
option to a signature, where n
is a value from 1 to 255.
target
KeywordAnother useful option in Suricata signatures is the target
option. It can be set to one of two values: src_ip
and dest_ip
. The purpose of this option is to correctly identify the source
and target
hosts in Suricata’s alert logs.
For example, the SSH signature from earlier in this tutorial can be enhanced with the target:dest_ip;
option:
alert ssh any any -> 203.0.113.0/24 2022 (msg:"SSH TRAFFIC on non-SSH port"; target:dest_ip; sid:1000000; rev:3;)
This example uses dest_ip
because the rule is designed to check for SSH traffic coming into our example network, so it is the destination. Adding the target
oiption to a rule will result in the following extra fields in the alert
portion of an eve.json
log entry.
. . .
"source": {
"ip": "127.0.0.1",
"port": 35272
},
"target": {
"ip": "203.0.113.1",
"port": 2022
}
. . .
With these entries in Suricata’s logs, they can be sent to a Security Information and Event Management (SIEM) tool to make it easier to search for alerts that might be originating from a common host, or attacks that are directed to a specific target on your network.
In this tutorial you examined each of the main sections that make a complete Suricata signature. Each of the Actions, Header, and Options sections in a rule have multiple options and support scanning packets using many different protocols. While this tutorial did not explore any of the sections in great depth, the structure of rule, and the important fields in the examples should be enough to get started writing your own rules.
If you want to explore complete signatures that include many more options than the ones described in this tutorial, explore the files in the /etc/suricata/rules
directory. If there is a field in a rule that you would like to know more about, the Suricata Rules Documentation is the authoritative resource on what each option and its possible values mean.
Once you are comfortable reading and testing signatures, you can proceed to the next tutorial in this series. In it you will learn how to enable Suricata’s IPS mode, which is used to drop suspicious traffic as opposed to the default IDS mode that only generates alerts.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
Suricata is a flexible, high performance Network Security Monitoring (NSM) tool that can detect and block attacks against your network.
This series will explore how to install Suricata on various operating systems, how to understand and write your own signatures to detect malicious or unknown traffic, and how to configure Suricata in both Intrusion Detection (IDS) and Intrusion Prevention (IPS) modes.
Once you have Suricata configured and running on your network, you’ll learn how to build your own Security Information and Event Management (SIEM) tool on top of the data that Suricata collects.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!