An IDS, such as Snort, is practically useless without a strong and up-to-date set of rules of signatures. It is the same thing as running an antivirus with outdated virus signatures. You just think you are protected. I tried to understand what is rule and what is it composed of.
A rule or signature is basically a piece of text/code that describes a state and then an action that is to be performed if that state is true.
Pseudocode rule: If WebServerX is accessed on port 443 by an IP from our internal network, then generate an alert.
Actual rule: alert tcp $HOME_NW any -> $WebServerX 443
The anatomy of a rule
I’m going to use the same example as in the book and that is:
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS (msg:”WEB-IIS
CodeRed v2 root.exe access”; flow:to_server,established;
uricontent:”/root.exe”; nocase; reference:url,www.cert.org/advisories/CA-2001-19.html; classtype:web-application-attack; sid:1256; rev:8;)
Snort rules are made of 3 key components:
- the rule header – or the preamble of the rule – everything you can see until the paranthesis
- the rule options – or the body of the rule – everything in the paranthesis
- the rule metadata – or the footer/informative part of the rule – which is also located in the paranthesis but it is usualy placed at the ending and it differenciate itself from the body of the rule by having an informative role.
alert tcp $EXTERNAL_NET any -> $HTTP_SERVERS $HTTP_PORTS
Here we have 5 elements which define what kind of action the rule should take and in which network circumstance this should be done.
Action – in our example, we have “alert”. This means that if Snort detects that certain state defined in our rule it will take the “alert” action, and that is to generate an event. The “alert” and “pass” actions are the most common, but they are others (including “drop”, “reject” and “sdrop” if Snort is deployed inline – i think you can recognize the naming from a firewall/iptables point of view).
Protocol – the most common are TCP, UDP from the transport layer of the OSI model or it can be ICMP (internet layer). We can also use the IP option which can be either one of them. We have the posibility of using any known protocol (for the system) – if you are not sure which exactly are they check /etc/protocols
IP matching – it only supports normal IPs (e.g. 10.165.1.5) and CIDR notation (e.g. 10.165.1.0/24) . Ranges are NOT supported.
Variables – just like in any kind of programming we can define variables in the Snort configuration file so that we can reuse IP addresses and ports easily. This file is read from top to bottom so yes, we can redefine variables. They are defined like so:
var <variable name> <value>
var HOME_NET 10.165.1.0/24
var HOME_NET !10.165.1.0/24
var HOME_NET [10.165.0.0/24,10.165.1.0/24]
Port matching – can be used for the source or destination ports. These can be defined as
- a single port (25)
- range of ports (25:443)
- all ports except X (!25)
Lists or broken ranges of ports are not supported. This means that we have to generate separate rules if we want to use broken ranges or lists of ports.
msg:”WEB-IIS CodeRed v2 root.exe access”; flow:to_server,established; uricontent:”/root.exe”; nocase;
Options are like commands – it’s a way to customize our rule so that it disects a packet a packet as we wish. There are also subsets of options that have other roles ( meta data options, payload detection option, nonpayload detection option, post detection option).
The order of the actions ca be any (although there are some best practices which recommend placing some options before others) but it is also important for performance and accuracy.
- Every option must be followed by a colon (:) if it has an argument.
- All colons, if not used as that part of an option, must be escaped with a backslash ().
- All options must end in a semicolon ( ; )
- Some options take multiple arguments. These are generally separated by commas or spaces.
Options are many but i’ll just cover the most common.
Rule title – msg which stands for message. This is plain-text that is inserted in logs to describe the rule, but does not identify the rule in plugins/databases. This title must be as descriptive as posible, although there are some rules that have the same title. It must be enclosed in quotes.
Flow – this options tell Snort where to look in a stream (flow) of data. Flow arguments are:
- to_server or from_client – they are synonims
- from_server or to_client – they are synonims
- established or stateless – these are oposite. Established tells the engine to look in streams started by a 3-way handshake (therefore its used for TCP) and that has data flowing. (the “established” state from netstat probably rings a bell). Stateless is telling the detection engine to look for packets that are not in data flows (it is used for UDP). Flow can take multiple or single arguments, but it can’t take 2 oposite arguments.
- flow:to_server,established; – is correct
- flow:from_server,to_server; is incorrect
Content – the base of the Snort rule language. Very few rules don’t have content or uricontent(very similar to content) matching. It is a simple match in the payload of a packet (it also includes full packet headers). You can specify a text to match or even binary/hex data.
content:”this is test”;content:”|00 23 71 88|”;
content:”|00 |some text|73 82 00|”;
Uricontent -similar to content, but it takes only the web URL (not full packet headers) and normalizes them (changing all content to ASCII and removes unreadable data such as ../../../) . It is faster and uses less procesing power .
Depth – specifies where in the packet to look for a match. It looks in the first X bytes of the packet. Does NOT include packet headers
Offset – ignores the first X bytes of the packet and searches in the rest. Some kind of oposite to depth.
Depth and Offset are a pair of options and can be used at the same time. The order between them doesn’t matter. Snort will be looking in the first X bytes (depth) in the packet but starting from the offset point.
Within – finds the second specified content in the first X bytes after the first specified content. Example:
content: “this” ; content:”a test” ; within: 50;
this maybe is a test
this is a test
this is probably a test
If the second content (“a test”) is to be found in the first 50 bytes after the first content (“this”) than our rule will take action.
Distance – the opposite of within ; ignores the first X bytes after the first specified content
reference:url,www.cert.org/advisories/CA-2001-19.html; classtype:web-application-attack; sid:1256; rev:8;
The rule metadata is a subset of options and it is a part of the body of the rule. The reason why i’m mentioning it separately is because of its informative role. It is not rule match related, it only gives the analyst or creator some related information.
- Reference – quick rule referencing
- Classtype – classification tool. It is used to prioritize events based on the defined type. Types available can be found in classification.config . To create a new classification type we have to use the following format : config classification: <name>, <description>, <priority>
- Sid – (security/snort identifier) or rule id . Each rule must have its own id . It’s not necesary but it’s better to use a unique sid so that you won’t tamper with snort plugins and database regulations . Sids 1,000,001–1,999,999 are reserved for local use these will never be used in a public repository.
- Rev – rule revision number ; after modifying/tweaking a rule it is a best practice to note the revision number for rule identification purposes.
The options presented in this posts are the most common. Of course there are dozens if not hundreds of other options. so if you ever need a more in-depth approach to this consult the Snort manual.