E
Eric Hansen
Guest
In the previous installment, we configured Suricata and successfully tested it via a simple rule that alerts on ICMP/ping packets being detected. In this part we will cover some aspects about rules. While this will mostly be a quick and dirty overview, it should help you on your way to making Suricata more fit for your network and your personal needs.
First lets look at the rule we created last time:
Rule Action
We’ll break this down into parts:
alert - This is the action we want to perform on the rule. suricata.yaml goes over the actions (called “Action Order”), but here’s a short description of options:
What this is stating is from top-to-bottom, which has precedence if multiple rules exist. If you have two of the same rules, for example, but one action was “pass” and the other was “alert”, then the “pass” action would be what processes the packet, ignoring the “alert” one.
Protocol
Next, there’s the protocol that we want our rule to keep an eye out for. Again I’ll explain the options.
Now we start to get into the more complex stuff involving rules: source and destination information. If you want to make this easier on yourself, go back to part 2 where we specify the HOME_NET and EXTERNAL_NET to declare variables. However, you will still find this helpful as well.
In our rule, we use any any for both source and destination IPs and ports. This is the lazy-man’s way of setting up rules and I highly suggest not doing it. You can specify multiple IPs, ports and variables in both the IP and port portions, and here’s the basic guidelines:
Between the IP and ports is the direction of packet flow, in our case ->. There’s two options for this:
This is the most complex part of writing your own rules and there are just way too many options to cover so I will just link you to the documents for this, but the last part is the rule options (everything you see between the ()). Since ours is extremely basic I will cover what we have in ours, then I’ll provide the links to the rest.
Our rule options look like this:
These are the 3 most basic options you really need to make the rule parsable and usable in Suricata.
As always, if you have any questions feel free to leave a comment and I’ll be glad to assist.
First lets look at the rule we created last time:
Code:
alert ip any any -> any any (msg:"ICMP detected"; sid:2; rev:1;)
We’ll break this down into parts:
alert - This is the action we want to perform on the rule. suricata.yaml goes over the actions (called “Action Order”), but here’s a short description of options:
- pass - This can be compared to “ACCEPT” in iptables, in that if the packet matches this rule it’ll be accepted through. From my standpoint this is mostly useful if you suspect a rule is causing an issue but you don’t want to disable the rule altogether.
- drop - The packet doesn’t get processed any further down the chain and the sender isn’t notified. This is akin to the “DROP” target in iptables, where it will silently remove the packet from the network stack. The documents also say that an alert is generated as well. This also only works for IPS mode (which if you followed this guide, yours is in).
- reject - This acts the same as drop but will also notify the sender that the packet has been removed from the stack. Personally I don’t use this one unless I’m troubleshooting a rule so I at least know its hitting it, but your network might like this functionality.
- alert - This is the one we used in our rule, and it basically just notifies you of any packets that have matched rules. This is great for first testing out rules because the packets will still flow through the stack, but you will know its being detected, and then you can either change the action to drop/reject/pass or keep it as is.
Code:
action-order:
- pass
- drop
- reject
- alert
What this is stating is from top-to-bottom, which has precedence if multiple rules exist. If you have two of the same rules, for example, but one action was “pass” and the other was “alert”, then the “pass” action would be what processes the packet, ignoring the “alert” one.
Protocol
Next, there’s the protocol that we want our rule to keep an eye out for. Again I’ll explain the options.
- ip - This is the protocol that our rule will match. When ip is specified it will watch for all or any packets on the network involving the adapter. That’s why if you were to test our rule by doing anything at all to that machine, the rule would match.
- tcp - When you want to match a rule against TCP traffic, set the protocol to this. If reject action was set for the rule, the sender would be notified via RST flag set.
- udp - Similar to tcp but for UDP packets instead. Like everything else involving UDP, if reject action was set for the rule, then the sender may not be notified, since there is no checking in this protocol.
- icm - For ICMP packets (i.e.: ping). If reject is the action for the rule, ICMP-error is sent back as a response (as is with UDP).
- Suricata also allows you to specify layer 7 protocols as well which are HTTP (http), SSL and TLS (tls for both), FTP (ftp) and SMB (smb).
Now we start to get into the more complex stuff involving rules: source and destination information. If you want to make this easier on yourself, go back to part 2 where we specify the HOME_NET and EXTERNAL_NET to declare variables. However, you will still find this helpful as well.
In our rule, we use any any for both source and destination IPs and ports. This is the lazy-man’s way of setting up rules and I highly suggest not doing it. You can specify multiple IPs, ports and variables in both the IP and port portions, and here’s the basic guidelines:
- ! - An exclamation mark specifies “not”, so “! 10.0.1.0/8” means any IP not in the 10.0.1.0 subnet.
- [] - This is how you specify multiple IPs and ports. They go inside the brackets and are comma-separated. You can also mix-and-match with the ! as well. For example, if you wanted the rule to match IP 192.168.0.5 but not 192.168.1.0/24, you would do “[! 192.168.1.0/24, 192.168.0.5]”. The value will be matched in the order you pass it.
- You can also throw in variables as well, like so: [$EXTERNAL_NET, !$HOME_NET] or if you want to exclude only two IP blocks from the rule: ![192.168.1.0/24,192.168.0.0/24] (this will match everything but IPs in the 192.168.1.0/24 and 192.168.0.0/24 ranges.
- : - Specifies a range of ports (i.e.: [80:82] will match ports 80-82). If you want a non-specific range (i.e.: only a maximum or minimum port number), you can do this: [:1024] (matches everything from 0-1024) or [1024:] (matches from 1024 to the highest [typically 65535]).
Between the IP and ports is the direction of packet flow, in our case ->. There’s two options for this:
- -> - This is the most common and means only check if the source IP and port are coming in to the destination IP and port. Essentially this is Suricata’s version of the INPUT chain in iptables.
- <> - This will match packet flow in either direction, as if you were to add the rule to both the INPUT and OUTPUT chains in iptables. Typically not used as much but does serve some purposes.
This is the most complex part of writing your own rules and there are just way too many options to cover so I will just link you to the documents for this, but the last part is the rule options (everything you see between the ()). Since ours is extremely basic I will cover what we have in ours, then I’ll provide the links to the rest.
Our rule options look like this:
Code:
msg:"ICMP detected"; sid:2; rev:1;
These are the 3 most basic options you really need to make the rule parsable and usable in Suricata.
- msg - What will be prompted in our alert (unless you’re using pass as the action, set this regardless). If you remember from part 2, our alerts displayed the following text: “07/24/2013-21:38:17.547119 [**] [1:2:1] ICMP detected [**] [Classification: (null)] [Priority: 3] {ICMP} 10.0.3.1:8 -> 10.0.3.10:0” (at least mine did, yours will probably be different). Notice the “ICMP detected” part? That’s our message from the rule itself.
- sid - This is a unique ID for the rule. If multiple rules have the same sid Suricata will let you know, and not be nice about it. Typically you should pick a really high number (> 10,000) if you are going to write your own.
- rev - Revision number/ID. From my experience the program would hiccup or not load the rule properly if this wasn’t set, or handled properly (incremented by 1 every time the rule was changed). However, your mileage may vary.
As always, if you have any questions feel free to leave a comment and I’ll be glad to assist.