Writing Suricata Rules
Brief notes on writing suricata rules.
Rules work by looking for known malicious patterns (ex. strings, bytes, regex, and field values) or suspicious behavior, such as downloading a PE file when requesting an image, or uncommon port for a given protocol.
Principles
Read documentation.
Use fast_pattern
Avoid rules containing only regex.
Do simple checks first (flow, dsize, flowbits, ...)
Write generic rules first, then tune them.
Test rules on a collection of clean traffic.
Location of default rules are stored in the "suricata.yaml" configuration file.
default-rule-path: /etc/suricata/rules/
rule-files:
- backdoor.rules
- http.rules
- custom.rules
- ...Environment variables can be used in rules.
vars:
address-groups:
HOME_NET: "[192.168.0.0/16,172.16.0.0/12,10.0.0.0/8]"
EXTERNAL_NET: any
HTTP_SERVERS: "$HOME_NET"
SQL_SERVERS: "$HOME_NET"
DNS_SERVERS: "$HOME_NET"Rules are written line by line or can span multiple lines by using a backslash at the end of each line, excluding the last. Comments can be inserted using a hashtag.
# Rule using single line:
alert http $HOME_NET -> $EXTERNAL_NET $HTTP_PORTS (msg:"Login Check"; classtype:malicious-activity; sid:10000001)
# Rule using multiple lines:
alert http \
$HOME_NET -> $EXTERNAL_NET $HTTP_PORTS \
(msg:"Login Check"; classtype:malicious-activity; sid:10000001)Rule Breakdown
# Rule on a single line
alert http $HOME_NET any -> $EXTERNAL_NET 88 (msg:"Suspicious activity"; flow:to_server,established; content:"POST"; http_method; reference:url,threats.sec.lab/New.Worm; classtype:malicious-activity; sid:10000001; rev:1;)
# Rule using multiple lines
alert http $HOME_NET any -> $EXTERNAL_NET 88 \
(msg:"Suspicious activity"; \
flow:to_server,established; \
content:"POST"; \
http_method; \
reference:url,threats.sec.lab/New.Worm; \
classtype:malicious-activity; \
sid:10000001; \
rev:1;)alert: Rule actionhttp: ProtocolBasic: (snort compatible) tcp, udp, icmp, ip.
App Layer: http, ftp, tls, smb, dns, smtp, etc...
$HOME_NET: Source IP/range.any: Source port number; any port.->: Direction (both ways: <>).$EXTERNAL_NET: Destination IP/range.88: Destination port number.msg:"Suspicious activity": Meta-setting containing information about the alert.flow:to_server,established: Optional. Specifies direction of traffic and if connection has been established or not.content:"POST": Content - matches on bytes. Printable characters, hexadecimal notation...http_method: Content modifier. Instructs suricata on the type of content.Other keyword modifiers include:
nocase: Makes content case-insensitive.fast_pattern: specifies the which content to check first.startswith: matches start of a buffer.endswith: matches end of a buffer.depth:1: number of bytes from the beginning of the payload to check.offset:2: from which byte to start checking.distance:3: from which byte to start checking after the previous match.within:4: how many bytes will be checked after the previous match.dsize:5; (dsize:>6; dsize:7<>8;): size of the packet payload.pcre:"/^[a-z0-9{9}\.js$/U/": regular expression.threshold: type <threshold|limit|both>, track <by_src|by_dst>, count <N>, seconds <T>: alert frequency.
reference:url,threats.sec.lab/New.Worm: Optional. url, md5, cve, etc./etc/suricata/reference.configclasstype:malicious-activity: Information about the threat classification./etc/suricata/classification.configsid:10000001: Signature IDSID allocation:
1000000-1999999 reserved for local use.
2000000-2099999 Emerging Threats open rulesets
2100000-2103999 forked ET Versions of the Original Snort GPL Signatures
http://sidallocation.org/
rev:1: Rule revision, starts from 1.
Writing good rules
Read the documentation!
https://docs.suricata.io/en/latest/rules/index.html
Use keywords and modifiers to specify location and order of malicious parts, packet size, IP/port ranges, etc.
Avoid using very common patters or only regex.
Avoid using very exact patterns that can easily be changed. (ie: host name, full URI, parameter values)
Indicators to look for:
Look for suspicious field values.
A lot of requests of the same type.
Sensitive data sent from client.
Commands received from the server.
Analyzing alerts
Obtain artifacts.
Check IP/domain reputation.
Check alert frequency.
If false positive - add exclusion to the rule.
Fixing false positives
Compare malware and clean traffic
Exclude a host:
content:!"example.com"; http_host;
Find fields that do not exist in malicious traffic:
content:!"User-Agent:"; http_header;
Add more conditions: request format, data length, field order, etc.
Troubleshooting rules
Incorrect variable declarations in config.
SID is not unique.
Problems with traffic.
Remove options one-by-one.
Check suricata log eve.json.
Potential Issues
Generic rules may produce false positives.
Easy to circumvent precise rules.
Make rules as generic as possible to prevent false positives.
For botnets it is not very easy for attacks to significantly change protocol in each bot version.
Many attacks just don't care.
Easy to circumvent rules from open rulesets, but not paid feeds or self-written rules.
Not all encrypted traffic can be detected.
Poor performance of rules with lots of regex.
Last updated