Writing Snort Rules

Writing Snort Rules

A Snort rule must be a single line of text. It further consists of two major parts : the rule header and the rule options. The rule header specifies the action, the protocol, the source and destination IP addresses, netmasks , and ports. The rule options follow the header on the same line and are enclosed in parentheses. A rule option is not required. Let's first go over the rule header, then we'll cover options in greater depth.

The Rule Header

The general form of a rule header is:

 action protocol sourceAddress sourcePort direction destAddress destPort 

None of these entries is literal text. Here's a description of each, with examples.

Action

Action

Description

alert

Generate an alert when this rule is matched. Snort is capable of generating multiple alert types. Default behavior is to write the alert to /var/log/snort, into a subdirectory whose name is the source IP address of the IP packet that matched the rule. A file describing the alert is created in that directory. That file's name is the protocol, followed by the source port, followed by the destination port. For example, 44.94.17.30/TCP:62077-80 is one such alert file capture generated when I ran an nmap stealth scan against one of my Linux PCs that was running Snort. I chose "full" logging, so this file's contents look like this:

 [**] SCAN nmap TCP [**] 
 04/25-22:49:26.071117 44.94.17.30:62077 -> 44.94.17.26:80 
 TCP TTL:43 TOS:0x0 ID:19504 IpLen:20 DgmLen:40 
 ***A**** Seq: 0x47100003 Ack: 0x0 Win: 0x1000 TcpLen: 20 
 =+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+=+ 

So what is this telling us? This tells us that on April 25 at 10:49 PM (and 26.071117 seconds) an nmap TCP scan from 44.94.17.30, port 62077, was made against my machine (44.94.17.26) port 80 (the Web server port). It then gives me some additional detail about the structure of the IP datagram and TCP envelope. An nmap scan is a very common first sign of reconnaissance.

log

The packet is written to the packet log. By default, this is a human-readable decode of the packet. You can have the log written in the "standard" tcpdump format by specifying the -b switch when you run Snort.

pass

Ignore the packet.

activate

Generate an alert, then turn on another dynamic rule. This is useful for adding detailed alerting or triggering detailed logging when a known attack profile start is seen. This way, Snort can turn on rules that would normally generate many false positives when a trigger condition is met. It also allows Snort to be running a relatively small ruleset, increasing its capacity in normal operation.

dynamic

Idle until switched on by an activate rule. It then acts like a log rule.

By using an advanced feature (which we will not cover here), you can create your own action types and associate output plug-ins with them. Snort is another of those tools that can fill a book of its own. We won't cover output plug-ins here.

Protocol

One of tcp, udp, or icmp. At the moment, these are all of the protocols that Snort will examine. The Snort rules documentation from www.snort.org does, however, say that there may be support for additional protocols coming. It mentions arp, igrp, gre, ospf, rip, and ipx. The routing protocols would be of particular interest to any site with multiple subnets. The average home user does not have to worry about these, since in almost all cases routing is done exclusively with default routes. But if you actually use routers, it would be nice to explictly trigger on those protocols.

Don't think, however, that this means Snort can't alert on things like route spoofing. It can. You just have to use rule options to do it. We'll show you the rudiments later in the Rules Options section.

sourceAddress, sourcePort, destAddress, destPort

These are all of similar format, so we cover them together. All four of these may be lists, with list items separated by commas. White space is not allowed. So, for example, your sourceAddress might be:

 192.168.0.0/16,10.0.0.0/24 

The address lists specify one or more addresses that will have to match in order for the rule to be triggered. Note in this example that the netmask bits specification is allowed to name a block of contiguous addresses.

Snort will never use the Domain Naming System (DNS), so you cannot use host names in rules. Why? Several reasons actually. DNS resolution takes time and generates network traffic. Since Snort is looking at every single packet, this can get very expensive. DNS queries generally block for a considerable period of time if the DNS server is not available. DNS is also quite easily spoofed. What good would an intrusion-detection system be if it could be blocked for minutes at a time merely by doing a DoS (denial-of-service) attack on your DNS server? It will annoy you at times when you are writing rules, but remember, names are unavailable for good reasons.

You can also use the wildcard keyword any in any of these lists. It means what you would think: The rule will match "any" source address, port, whichever one of the fields you put any into.

The port lists may be comma-separated explicit lists, the any wildcard, or ranges specified in this format:

 min:max 

So if you wanted to alert on any attempt to connect to a port below 1024 on any machine from any machine, the rule would be:

 alert tcp any any -> any 1:1024 

(We haven't explained the arrow yet. It is important. We cover it in the next subsection.)

You can reverse the sense of any address or range with the "!" operator. So you could modify the preceding rule to exclude your local network as a source ( assuming your local network is 192.168.0.0/16) like this:

 alert tcp !192.168.0.0/16 any -> any 1:1024 
Direction

The direction operator may be one of "->", "<-", or "<>". Earlier we suggested that the source address and port lists came first, followed by the destination address and port lists. This is true if the direction operator is "->". If the direction operator is "<-", then this is reversed . The "<>" direction operator means "bidirectional." In this case the source and destination of the packet are each considered against both address/port lists in the rule. This is useful for logging both sides of a bidirectional protocol like Telnet.

Rule Options

Rule options modify the Snort rule. The basic format of an option is:

 keyword: arguments; 

One or more options appear after a rule header, all enclosed in parentheses.

Rule options are very powerful, but their use is a bit muddy. Some of them just set values. Some of them further narrow whether the current packed is logged or an alert generated. Some of them alter the data in the packet. We'll mention all of the options here, but we will not fully document them. Some descriptions will be complete, and some will be full of bona fide hand waving. Be patient. We're honest, and we won't leave you wondering which is which.

Option

Description

msg

Add a descriptive message to the alert or log. The message is enclosed in double quotes. You must escape colons, quotes, and semicolons with a backslash.

Example:

 alert tcp any any -> 10.0.0.0/24 22 (msg: "Attempt to access SSH port";) 

ttl, tos, id

These three options allow you set conditions on triggering the rule based on attributes of the IP datagram. The ttl option will trigger the rule if the datagram matches the specified time-to-live exactly. This can be used to try to detect traceroutes.

The tos lets you match on a specific type-of-service value. The TOS field is often ignored by many IP protocol stacks and thus can be a handy subchannel for carrying pure evil! (NB: pure evil is my "technical" term for data sent to a system with malicious intent.)

The id option lets you match on a fragment ID value. Some hacking tools (and let's not open the "hacker" versus "cracker" debate) set this field to particular values, such as 31337 (supposed to suggest "elite," apparently to someone who cannot spell).

Examples:

 alert tcp any any -> 192.168.0.0/16 any (ttl: "1"; msg: "Traceroute detect";) 
 alert tcp any any -> 192.168.0.0/16 any (id: 31337; msg: "Stupid ELEET cracker";) 
 log tcp any any -> 192.168.0.0/16 any (tos: 8;) 

ipopts

This allows you to condition triggering of the rule by the options portion of the IP datagram. Valid arguments are:

·                 eol: end of list

·                 lsrr: loose source routing

·                 nop: no operation

·                 satid: stream identifier

·                 sec: IP security option

·                 ssrr: strict source routing

·                 ts: timestamp

·                 rr: record route

Only one option may be specified per rule. For details on IP options, consult a book like Comer's, or see RFC [*] 791, section 3.2.

logto

This lets you specify that any packets matching this rule be logged to a special, separate output log file. This can be useful when you want to log all activity of a certain type to a single place for special analysis.

Example:

 alert tcp any any -> any any (ttl: "1"; logto: "/var/log/traceroute.snort";) 

fragbits

This option allows you to test the fragmentation bits in the IP datagram. There are three frgamentation bits. The Reserved bit, the Don't Frgament bit, and the More Fragments bit. You may test if these are set by using the letters R, D, and F, respectively. Whichever bit or bits you test, you may append any of the following characters to condition the meaning of the bits specified:

·                 +, match if all specified bits are set, ignoring other bits. Without this character, having unspecified bits set is considered not to match.

·                 *, match if any of the specified bits are set.

·                 !, match if the specified bits are not set.

dsize

This option lets you trigger on the data size of the datagram.

flags

This option allows you to test the TCP flags for a match. Snort supports testing for eight flags.

·                 F: FIN

·                 S: SYN

·                 R: RST

·                 P: PSH

·                 A: ACK

·                 U: URG

·                 1: Reserved bit 1

·                 2: Reserved bit 2

content

This is the heart of Snort's most powerful features. The content option lets you search for specific bytes or text in a datagram and trigger rules based on that content. This gives you nearly infinite flexibility in detecting attacks (and, alas, in generating false positives).

The content option may contain text to match, or it may contain binary data to match. Binary data is generally included by putting the pipe character (, the vertical bar) followed by the binary data in ASCII-encoded hexidecimal, and ending with another pipe character. The test is case sensitive. There are a number of additional options that have meaning only in conjunction with the content option.

·                 offset: This sets the start position for the content search. Content searches are expensive (they take a lot of time compared to the other tests Snort does), so if you can limit the content search it is wise to do so. Of course, you must try to avoid limiting the search so much that you miss an attack.

·                 depth: This sets the maximum position in the datagram that will be searched by a content option.

·                 nocase: This makes a content search case insensitive.

content-list

This option is like the content option and may take the same modifier options. The argument to content-list is a file name. That file contains one or more content specifiers, just like the ones for the content option. Each physical line of the file is taken as one content specifier . A line beginning with a pound sign is ignored.

Example:

 log tcp any any <> $EXTERNAL_NET 80 (content-list: "/etc/snort/badweb.content";) 

seq

This tests whether the TCP datagram has a sequence number set. According to the Snort documentation, this is pretty much useless and "was included for the sake of completeness."

ack

Most of the time this would be as useless as the preceding option. However, one of the most popular network reconnaissance tools, nmap, does a little trick to see if a host is active. It sets the TCP header's ack field (which is the stream position being acknowledged ) to zero and then sends a packet with the TCP ACK flag set. Any working TCP stack will respond to such a packet. So this otherwise -useless option, which checks for a nonzero ack field, becomes quite useful for quickly and efficiently detecting basic nmap network scans .

itype

This option triggers on the ICMP packet type field.

icode

This option triggers on the ICMP code field.

icmp_id

This one is pretty simple on its face, but it is part of a tool for checking for some of the sneakiest network attacks. Every ICMP echo request and reply has an ID field. Normally, this is a monotonically increasing integer designed to distinguish one ping packet from another when the replies come back, since these may definitely arrive out of sequence.

Very crafty network attackers have, however, realized that they can put data in ICMP datagrams and use an invariant value in this field to make it like a TCP or User Datagram Protocol (UDP) port number. If ICMP Echo requests and replies are allowed through your firewall (and the RFCs say they should be, but it really isn't absolutely necessary), then this becomes a "stealth channel" for any old data an attacker wants to pass in and out. A number of naughty people have used this. Usually, a user on the attacked network is tricked into running a program (a Trojan horse) that will open a server that listens for ICMP packets with a particular ID. This opens the channel for any data to move in and out of your network, probably undetected.

For some examples, grep -i for "stacheldraht" in the Snort rules library files.

rpc

This option lets you match for hits on a Remote Procedure Call (RPC) to a given application, procedure, and version. Each of these three is expressed as a number. You must match on the application number exactly, but you may use an asterisk (*) as a wildcard for the procedure and version numbers . A tutorial on RPC is well beyond our scope here. Be aware, however, that RPC lies at the heart of a very important protocol in [*] nix networks: NFS. So, if you are not familiar with at least the rudiments of the Remote Procedure Call protocol, it is worth your study.

session

The session option lets you log the contents of an entire TCP session using a single rule. This is a very expensive operation and, when Snort is watching a busy high-speed interface, may lead Snort to miss packets. It is better to use this option when running Snort against a binary log file. That said, if you are on a low-speed connection or on a DSL or cable modem and have a very fast machine, this can be very useful.

This takes one of two arguments: printable or all. When you use printable, only printable ASCII characters are logged from the stream. When you specify all, nonprintable characters are logged as ASCII-encoded hexidecimal.

Example:

 log tcp any any <> 216.17.15.13/24 23 (session: printable;) 

resp

Now we get to something really cool. We've talked about Snort as a more or less passive process, monitoring for intrusion attempts across a network. Snort is also, in its most recent versions, able to act as an instrument of policy enforcement.

The resp option allows Snort to take action when a rule is matched. The actions that may be taken are:

·                 rst_snd: Send TCP RST packets to the sending socket. This is like the receiving socket closing the connection.

·                 rst_rcv: Send TCP RST packets to the receiving socket. This is like the sender closing the connection.

·                 rst_all: Combine both of the preceding actions.

·                 icmp_net: Send an Internet Control Message Protocol (ICMP) Network Unreachable packet to the sender.

·                 icmp_host: Send an ICMP Host Unreachable packet to the sender

·                 icmp_port: Send an ICMP Port Unreachable packet to the sender.

·                 icmp_all: Send all of the preceding ICMP packets to the sender.

Multiple actions may be specified in the option. Separate them with commas.

Example:

 alert any any -> any 23 (msg: "Telnet access forbidden"; resp: rst_all,icmp_all;) 

This feature will work best if Snort is running on the firewall box, because then it has the best chance of sending its RST/ICMP packets before the original packets are seen by the local host. It will still close a connection even if it is running on just an internal machine, but the internal target could conceivably respond first and exchange some data before Snort closes it.

react

This is another fun one (although I have certain reservations about the implementation, which I will enumerate shortly). This works similarly to the resp option, except it is intended specifically for blocking Web accesses . The arguments to this option are:

·                 block: Close the connection and send a message to the browser.

·                 warn: Send a message to the browser.

·                 msg: Include the text from the msg option in the visible message to the browser.

·                 proxy: Send the message to the proxy port specified.

This option allows you not only to close the connection, but to put up a readable notice on the Web browser attempting access that explains that this is an inaccessible site or service. If you use this option in conjunction with the content option, you can try to block all access to sites whose content contains certain keywords, for example.

I have a few problems with the implementation of this feature. First, the HTML of the text returned is hard coded in the sp_react.c file in Snort. It contains a hard-coded mailto: anchor tag that will send mail to someone in Poland, which I'm guessing you do not want to do. It only sends its HTML content if the traffic is bound for port 80. It is, of course, possible to make HTTP connections to other ports. The HTML code as shipped in sp_react.c includes JavaScript. Not every Web browser supports JavaScript, and JavaScript has some painful variations between browser products.

If you want to use this feature, I strongly advise you to get the Snort source code and customize the HTML embedded in sp_react.c. The port 80 limitation is another thing to bear in mind. Your users could find their way around it.

[*] Request For Comments. These are the documents that exhaustively detail proposed Internet standards. Every Internet standard began life as an RFC. RFCs are relentlessly technical. You have to really want to know everything to enjoy reading them.

There are a couple more things you can put in a Snort rules file. For one, you will use some of the same network address specifications over and over again. Instead of typing 10.0.0.0/24 all over the place, you may create a variable:

  var INTERNAL_NET 10.0.0.0/24  

The other thing you can do is to "bring in" rules from other files with the include directive:

  include: "/var/lib/snort.rules"  

 



Multitool Linux. Practical Uses for Open Source Software
Multitool Linux: Practical Uses for Open Source Software
ISBN: 0201734206
EAN: 2147483647
Year: 2002
Pages: 257

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net