7.36. Differences From Snort
This document is intended to highlight the major differences between Suricata and Snort that apply to rules and rule writing.
Where not specified, the statements below apply to Suricata. In general, references to Snort refer to the version 2.9 branch.
7.36.1. Automatic Protocol Detection
Suricata does automatic protocol detection of the following application layer protocols:
dcerpc
dnp3
dns
http
imap (detection only by default; no parsing)
ftp
modbus (disabled by default; minimalist probe parser; can lead to false positives)
smb
smb2 (disabled internally inside the engine)
smtp
ssh
tls (SSLv2, SSLv3, TLSv1, TLSv1.1 and TLSv1.2)
In Suricata, protocol detection is port agnostic (in most cases). In Snort, in order for the
http_inspect
and other preprocessors to be applied to traffic, it has to be over a configured port.Some configurations for app-layer in the Suricata yaml can/do by default specify specific destination ports (e.g. DNS)
You can look on 'any' port without worrying about the performance impact that you would have to be concerned about with Snort.
If the traffic is detected as HTTP by Suricata, the
http_*
buffers are populated and can be used, regardless of port(s) specified in the rule.You don't have to check for the http protocol (i.e.
alert http ...
) to use thehttp_*
buffers although it is recommended.If you are trying to detect legitimate (supported) application layer protocol traffic and don't want to look on specific port(s), the rule should be written as
alert <protocol> ...
withany
in place of the usual protocol port(s). For example, when you want to detect HTTP traffic and don't want to limit detection to a particular port or list of ports, the rules should be written asalert http ...
withany
in place of$HTTP_PORTS
.You can also use
app-layer-protocol:<protocol>;
inside the rule instead.
So, instead of this Snort rule:
alert tcp $HOME_NET any -> $EXTERNAL_NET $HTTP_PORTS ...
Do this for Suricata:
alert http $HOME_NET -> $EXTERNAL_NET any ...
Or:
alert tcp $HOME_NET any -> $EXTERNAL_NET any (app-layer-protocol:http; ...
7.36.2. urilen
Keyword
Ranges given in the
urilen
keyword are inclusive for Snort but not inclusive for Suricata.Example:
urilen:2<>10
Snort interprets this as, "the URI length must be greater than or equal to 2, and less than or equal to 10".
Suricata interprets this as "the URI length must be greater than 2 and less than 10".
There is a request to have Suricata behave like Snort in future versions – https://redmine.openinfosecfoundation.org/issues/1416
Currently on hold
By default, with Suricata,
urilen
applies to the normalized bufferUse
,raw
for raw buffere.g.
urilen:>20,raw;
By default, with Snort,
urilen
applies to the raw bufferUse
,norm
for normalized buffere.g.
urilen:>20,norm;
7.36.3. http_uri
Buffer
In Snort, the
http_uri
buffer normalizes '+' characters (0x2B) to spaces (0x20).Suricata can do this as well but you have to explicitly set
query-plusspace-decode: yes
in thelibhtp
section of Suricata's yaml file.
7.36.4. http_header
Buffer
In Snort, the
http_header
buffer includes the CRLF CRLF (0x0D 0x0A 0x0D 0x0A) that separates the end of the last HTTP header from the beginning of the HTTP body. Suricata includes a CRLF after the last header in thehttp_header
buffer but not an extra one like Snort does. If you want to match the end of the buffer, use either thehttp_raw_header
buffer, a relativeisdataat
(e.g.isdataat:!1,relative
) or a PCRE (although PCRE will be worse on performance).Suricata will include CRLF CRLF at the end of the
http_raw_header
buffer like Snort does.Snort will include a leading CRLF in the
http_header
buffer of server responses (but not client requests). Suricata does not have the leading CRLF in thehttp_header
buffer of the server response or client request.In the
http_header
buffer, Suricata will normalize HTTP header lines such that there is a single space (0x20) after the colon (':') that separates the header name from the header value; this single space replaces zero or more whitespace characters (including tabs) that may be present in the raw HTTP header line immediately after the colon. If the extra whitespace (or lack thereof) is important for matching, use thehttp_raw_header
buffer instead of thehttp_header
buffer.Snort will also normalize superfluous whitespace between the header name and header value like Suricata does but only if there is at least one space character (0x20 only so not 0x90) immediately after the colon. This means that, unlike Suricata, if there is no space (or if there is a tab) immediately after the colon before the header value, the content of the header line will remain unchanged in the
http_header
buffer.When there are duplicate HTTP headers (referring to the header name only, not the value), the normalized buffer (
http_header
) will concatenate the values in the order seen (from top to bottom), with a comma and space (", ") between each of them. If this hinders detection, use thehttp_raw_header
buffer instead.Example request:
GET /test.html HTTP/1.1 Content-Length: 44 Accept: */* Content-Length: 55
The Content-Length header line becomes this in the
http_header
buffer:Content-Length: 44, 55
The HTTP 'Cookie' and 'Set-Cookie' headers are NOT included in the
http_header
buffer; instead they are extracted and put into their own buffer –http_cookie
. See the http_cookie Buffer section.The HTTP 'Cookie' and 'Set-Cookie' headers ARE included in the
http_raw_header
buffer so if you are trying to match on something like particular header ordering involving (or not involving) the HTTP Cookie headers, use thehttp_raw_header
buffer.If 'enable_cookie' is set for Snort, the HTTP Cookie header names and trailing CRLF (i.e. "Cookie: \r\n" and "Set-Cooke \r\n") are kept in the
http_header
buffer. This is not the case for Suricata which removes the entire "Cookie" or "Set-Cookie" line from thehttp_header
buffer.Other HTTP headers that have their own buffer (
http_user_agent
,http_host
) are not removed from thehttp_header
buffer like the Cookie headers are.When inspecting server responses and
file_data
is used, content matches inhttp_*
buffers should come beforefile_data
unless you usepkt_data
to reset the cursor before matching inhttp_*
buffers. Snort will not complain if you usehttp_*
buffers afterfile_data
is set.
7.36.6. New HTTP keywords
Suricata supports several HTTP keywords that Snort doesn't have.
Examples are http_user_agent
, http_host
and http_content_type
.
See HTTP Keywords for all HTTP keywords.
7.36.7. byte_extract
Keyword
Suricata supports
byte_extract
fromhttp_*
buffers, includinghttp_header
which does not always work as expected in Snort.In Suricata, variables extracted using
byte_extract
must be used in the same buffer, otherwise they will have the value "0" (zero). Snort does allow cross-buffer byte extraction and usage.Be sure to always positively and negatively test Suricata rules that use
byte_extract
andbyte_test
to verify that they work as expected.
7.36.8. byte_math
Keyword
Suricata will never match if there's a zero divisor. Division by 0 is undefined.
7.36.9. isdataat
Keyword
The
rawbytes
keyword is supported in the Suricata syntax but doesn't actually do anything.Absolute
isdataat
checks will succeed if the offset used is less than the size of the inspection buffer. This is true for Suricata and Snort.For relative
isdataat
checks, there is a 1 byte difference in the way Snort and Suricata do the comparisons.Suricata will succeed if the relative offset is less than or equal to the size of the inspection buffer. This is different from absolute
isdataat
checks.Snort will succeed if the relative offset is less than the size of the inspection buffer, just like absolute
isdataat
checks.Example - to check that there is no data in the inspection buffer after the last content match:
Snort:
isdataat:!0,relative;
Suricata:
isdataat:!1,relative;
With Snort, the "inspection buffer" used when checking an
isdataat
keyword is generally the packet/segment with some exceptions:With PAF enabled the PDU is examined instead of the packet/segment. When
file_data
orbase64_data
has been set, it is those buffers (unlessrawbytes
is set).With some preprocessors - modbus, gtp, sip, dce2, and dnp3 - the buffer can be particular portions of those protocols (unless
rawbytes
is set).With some preprocessors - rpc_decode, ftp_telnet, smtp, and dnp3 - the buffer can be particular decoded portions of those protocols (unless
rawbytes
is set).
With Suricata, the "inspection buffer" used when checking an absolute
isdataat
keyword is the packet/segment if looking at a packet (e.g.alert tcp-pkt...
) or the reassembled stream segments.In Suricata, a relative
isdataat
keyword will apply to the buffer of the previous content match. So if the previous content match is ahttp_*
buffer, the relativeisdataat
applies to that buffer, starting from the end of the previous content match in that buffer. Snort does not behave like this!For example, this Suricata rule looks for the string ".exe" at the end of the URI; to do the same thing in the normalized URI buffer in Snort you would have to use a PCRE –
pcre:"/\x2Eexe$/U";
alert http $HOME_NET any -> $EXTERNAL_NET any (msg:".EXE File Download Request"; flow:established,to_server; content:"GET"; http_method; content:".exe"; http_uri; isdataat:!1,relative; priority:3; sid:18332111;)
If you are unclear about behavior in a particular instance, you are encouraged to positively and negatively test your rules that use an
isdataat
keyword.
7.36.10. Relative PCRE
You can do relative PCRE matches in normalized/special buffers with Suricata. Example:
content:".php?sign="; http_uri; pcre:"/^[a-zA-Z0-9]{8}$/UR";
With Snort you can't combine the "relative" PCRE option ('R') with other buffer options like normalized URI ('U') – you get a syntax error.
7.36.11. tls*
Keywords
In addition to TLS protocol identification, Suricata supports the storing of certificates to disk, verifying the validity dates on certificates, matching against the calculated SHA1 fingerprint of certificates, and matching on certain TLS/SSL certificate fields including the following:
Negotiated TLS/SSL version.
Certificate Subject field.
Certificate Issuer field.
Certificate SNI Field
For details see SSL/TLS Keywords.
7.36.12. dns_query
Keyword
Sets the detection pointer to the DNS query.
Works like
file_data
does ("sticky buffer") but for a DNS request query.Use
pkt_data
to reset the detection pointer to the beginning of the packet payload.See DNS Keywords for details.
7.36.13. IP Reputation and iprep
Keyword
Snort has the "reputation" preprocessor that can be used to define whitelist and blacklist files of IPs which are used generate GID 136 alerts as well as block/drop/pass traffic from listed IPs depending on how it is configured.
Suricata also has the concept of files with IPs in them but provides the ability to assign them:
Categories
Reputation score
Suricata rules can leverage these IP lists with the
iprep
keyword that can be configured to match on:Direction
Category
Value (reputation score)
https://blog.inliniac.net/2012/11/21/ip-reputation-in-suricata/
7.36.14. Flowbits
Suricata fully supports the setting and checking of flowbits (including the same flowbit) on the same packet/stream. Snort does not always allow for this.
In Suricata,
flowbits:isset
is checked after the fast pattern match but before othercontent
matches. In Snort,flowbits:isset
is checked in the order it appears in the rule, from left to right.If there is a chain of flowbits where multiple rules set flowbits and they are dependent on each other, then the order of the rules or the
sid
values can make a difference in the rules being evaluated in the proper order and generating alerts as expected. See bug 1399 - https://redmine.openinfosecfoundation.org/issues/1399.
7.36.15. flowbits:noalert;
A common pattern in existing rules is to use flowbits:noalert;
to make
sure a rule doesn't generate an alert if it matches.
Suricata allows using just noalert;
as well. Both have an identical meaning
in Suricata.
7.36.16. Negated Content Match Special Case
For Snort, a negated content match where the starting point for searching is at or beyond the end of the inspection buffer will never return true.
For negated matches, you want it to return true if the content is not found.
This is believed to be a Snort bug rather than an engine difference but it was reported to Sourcefire and acknowledged many years ago indicating that perhaps it is by design.
This is not the case for Suricata which behaves as expected.
Example HTTP request:
POST /test.php HTTP/1.1 Content-Length: 9 user=suri
This rule snippet will never return true in Snort but will in Suricata:
content:!"snort"; offset:10; http_client_body;
7.36.17. File Extraction
Suricata has the ability to match on files from FTP, HTTP and SMTP streams and log them to disk.
Snort has the "file" preprocessor that can do something similar but it is experimental, development of it has been stagnant for years, and it is not something that should be used in a production environment.
Files can be matched on using a number of keywords including:
filename
fileext
filemagic
filesize
filemd5
filesha1
filesha256
filesize
See File Keywords for a full list.
The
filestore
keyword tells Suricata to save the file to disk.Extracted files are logged to disk with meta data that includes things like timestamp, src/dst IP, protocol, src/dst port, HTTP URI, HTTP Host, HTTP Referer, filename, file magic, md5sum, size, etc.
There are a number of configuration options and considerations (such as stream reassembly depth and libhtp body-limit) that should be understood if you want fully utilize file extraction in Suricata.
https://blog.inliniac.net/2011/11/29/file-extraction-in-suricata/
https://blog.inliniac.net/2014/11/11/smtp-file-extraction-in-suricata/
7.36.18. Lua Scripting
Suricata has the
lua
(orluajit
) keyword which allows for a rule to reference a Lua script that can access the packet, payload, HTTP buffers, etc.Provides powerful flexibility and capabilities that Snort does not have.
7.36.19. Fast Pattern
Snort's fast pattern matcher is always case insensitive; Suricata's is case sensitive unless 'nocase' is set on the content match used by the fast pattern matcher.
Snort will truncate fast pattern matches based on the
max-pattern-len
config (default no limit) unlessfast_pattern:only
is used in the rule. Suricata does not do any automatic fast pattern truncation cannot be configured to do so.Just like in Snort, in Suricata you can specify a substring of the content string to be use as the fast pattern match. e.g.
fast_pattern:5,20;
In Snort, leading NULL bytes (0x00) will be removed from content matches when determining/using the longest content match unless
fast_pattern
is explicitly set. Suricata does not truncate anything, including NULL bytes.Snort does not allow for all
http_*
buffers to be used for the fast pattern match (e.g.http_raw_*
,http_method
,http_cookie
, etc.). Suricata lets you use any 'http_*' buffer you want for the fast pattern match, includinghttp_raw_*' and ``http_cookie
buffers.Suricata supports the
fast_pattern:only
syntax but technically it is not really implemented; theonly
is silently ignored when encountered in a rule. It is still recommended that you usefast_pattern:only
where appropriate in case this gets implemented in the future and/or if the rule will be used by Snort as well.With Snort, unless
fast_pattern
is explicitly set, content matches in normalized HTTP Inspect buffers (e.g. http content modifiers suchhttp_uri
,http_header
, etc.) take precedence over non-HTTP Inspect content matches, even if they are shorter. Suricata does the same thing and gives a higher 'priority' (precedence) tohttp_*
buffers (except forhttp_method
,http_stat_code
, andhttp_stat_msg
).See Suricata Fast Pattern Determination Explained for full details on how Suricata automatically determines which content to use as the fast pattern match.
When in doubt about what is going to be use as the fast pattern match by Suricata, set
fast_pattern
explicitly in the rule and/or run Suricata with the--engine-analysis
switch and view the generated file (rules_fast_pattern.txt
).Like Snort, the fast pattern match is checked before
flowbits
in Suricata.Using Hyperscan as the MPM matcher (
mpm-algo
setting) for Suricata can greatly improve performance, especially when it comes to fast pattern matching. Hyperscan will also take in to account depth and offset when doing fast pattern matching, something the other algorithms and Snort do not do.
7.36.20. Don't Cross The Streams
Suricata will examine network traffic as individual packets and, in the
case of TCP, as part of a (reassembled) stream. However, there are
certain rule keywords that only apply to packets only (dsize
,
flags
, ttl
) and certain ones that only apply to streams
only (http_*
) and you can't mix packet and stream keywords. Rules
that use packet keywords will inspect individual packets only and
rules that use stream keywords will inspect streams only. Snort is a
little more forgiving when you mix these – for example, in Snort you can
use dsize
(a packet keyword) with http_*
(stream
keywords) and Snort will allow it although, because of dsize
, it
will only apply detection to individual packets (unless PAF is enabled
then it will apply it to the PDU).
If dsize
is in a rule that also looks for a stream-based
application layer protocol (e.g. http
), Suricata will not match on
the first application layer packet since dsize
make Suricata
evaluate the packet and protocol detection doesn't happen until after
the protocol is checked for that packet; subsequent packets in that
flow should have the application protocol set appropriately and will
match rules using dsize
and a stream-based application layer
protocol.
If you need to check sizes on a stream in a rule that uses a stream
keyword, or in a rule looking for a stream-based application layer
protocol, consider using the stream_size
keyword and/or
isdataat
.
Suricata also supports these protocol values being used in rules and Snort does not:
tcp-pkt
– example:alert tcp-pkt ...
This tells Suricata to only apply the rule to TCP packets and not the (reassembled) stream.
tcp-stream
– example:alert tcp-stream ...
This tells Suricata to inspect the (reassembled) TCP stream only.
7.36.21. Alerts
In Snort, the number of alerts generated for a packet/stream can be limited by the
event_queue
configuration.Suricata has an internal hard-coded limit of 15 alerts per packet/stream (and this cannot be configured); all rules that match on the traffic being analyzed will fire up to that limit.
Sometimes Suricata will generate what appears to be two alerts for the same TCP packet. This happens when Suricata evaluates the packet by itself and as part of a (reassembled) stream.
7.36.22. Buffer Reference Chart
Buffer |
Snort 2.9.x Support? |
Suricata Support? |
PCRE flag |
Can be used as Fast Pattern? |
Suricata Fast Pattern Priority (lower number is higher priority) |
---|---|---|---|---|---|
content (no modifier) |
YES |
YES |
<none> |
YES |
3 |
http_method |
YES |
YES |
M |
Suricata only |
3 |
http_stat_code |
YES |
YES |
S |
Suricata only |
3 |
http_stat_msg |
YES |
YES |
Y |
Suricata only |
3 |
uricontent |
YES but deprecated, use http_uri instead |
YES but deprecated, use http_uri instead |
U |
YES |
2 |
http_uri |
YES |
YES |
U |
YES |
2 |
http_raw_uri |
YES |
YES |
I |
Suricata only |
2 |
http_header |
YES |
YES |
H |
YES |
2 |
http_raw_header |
YES |
YES |
D |
Suricata only |
2 |
http_cookie |
YES |
YES |
C |
Suricata only |
2 |
http_raw_cookie |
YES |
NO (use http_raw_header instead) |
K |
NO |
n/a |
http_host |
NO |
YES |
W |
Suricata only |
2 |
http_raw_host |
NO |
YES |
Z |
Suricata only |
2 |
http_client_body |
YES |
YES |
P |
YES |
2 |
http_server_body |
NO |
YES |
Q |
Suricata only |
2 |
http_user_agent |
NO |
YES |
V |
Suricata only |
2 |
dns_query |
NO |
YES |
n/a* |
Suricata only |
2 |
tls_sni |
NO |
YES |
n/a* |
Suricata only |
2 |
tls_cert_issuer |
NO |
YES |
n/a* |
Suricata only |
2 |
tls_cert_subject |
NO |
YES |
n/a* |
Suricata only |
2 |
file_data |
YES |
YES |
n/a* |
YES |
2 |
* Sticky buffer