doc/userguide/rules/differences-from-snort.rst
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.
Suricata does automatic protocol detection of the following application layer protocols:
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.
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 the http_* 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> ... with any 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 as
alert http ... with any in place of
$HTTP_PORTS.
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; ...
urilen KeywordRanges 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 <https://redmine.openinfosecfoundation.org/issues/1416>_
By default, with Suricata, urilen applies to the
normalized buffer
,raw for raw bufferurilen:>20,raw;By default, with Snort, urilen applies to the raw
buffer
,norm for normalized bufferurilen:>20,norm;http_uri BufferIn Snort, the http_uri buffer normalizes '+' characters
(0x2B) to spaces (0x20).
query-plusspace-decode: yes in the libhtp section of Suricata's yaml file.https://redmine.openinfosecfoundation.org/issues/1035 <https://redmine.openinfosecfoundation.org/issues/1035>_
https://github.com/inliniac/suricata/pull/620 <https://github.com/inliniac/suricata/pull/620>_
http_header BufferIn 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 the http_header buffer but not an extra one
like Snort does. If you want to match the end of the buffer, use
either the http_raw_header buffer, a relative
isdataat (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 the http_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
the http_raw_header buffer instead of the http_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 the http_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 the http_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
the http_header buffer.
Other HTTP headers that have their own buffer
(http_user_agent, http_host) are not removed from the
http_header buffer like the Cookie headers are.
When inspecting server responses and file_data is used,
content matches in http_* buffers should come before
file_data unless you use pkt_data to reset the cursor
before matching in http_* buffers. Snort will not complain if
you use http_* buffers after file_data is set.
http_cookie BufferThe http_cookie buffer will NOT include the header name,
colon, or leading whitespace. i.e. it will not include "Cookie: " or "Set-Cookie: ".
The http_cookie buffer does not include a CRLF (0x0D 0x0A) at
the end. If you want to match the end of the buffer, use a relative
isdataat or a PCRE (although PCRE will be worse on
performance).
There is no http_raw_cookie buffer in Suricata. Use
http_raw_header instead.
You do not have to configure anything special to use the
'http_cookie' buffer in Suricata. This is different from Snort
where you have to set enable_cookie in the
http_inspect_server preprocessor config in order to have the
http_cookie buffer treated separate from the
http_header buffer.
If Snort has 'enable_cookie' set and multiple "Cookie" or "Set-Cookie" headers are seen, it will concatenate them together (with no separator between them) in the order seen from top to bottom.
If a request contains multiple "Cookie" or "Set-Cookie" headers, the
values will be concatenated in the Suricata http_cookie
buffer, in the order seen from top to bottom, with a comma and space
(", ") between each of them.
Example request::
GET /test.html HTTP/1.1
Cookie: monster
Accept: */*
Cookie: elmo
Suricata http_cookie buffer contents::
monster, elmo
Snort http_cookie buffer contents::
monsterelmo
Corresponding PCRE modifier: C (same as Snort)
Suricata supports several HTTP keywords that Snort doesn't have.
Examples are http_user_agent, http_host and http_content_type.
See :doc:http-keywords for all HTTP keywords.
byte_extract KeywordSuricata supports
byte_extract from http_* buffers, including
http_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 and byte_test to verify that they
work as expected.
byte_jump Keywordbyte_extract or
byte_math to be specified for the nbytes value. The
value of nbytes must adhere to the same constraints
as if it were supplied directly in the rule.byte_math KeywordSuricata accepts dce as an endian value or as a separate keyword.
endian dce or dce are equivalent.
Suricata's rule parser rejects rules that repeat keywords in a single
rule. E.g., byte_math: endian big, endian little.
Suricata's rule parser accepts rvalue values of 0 to the maximum
uint32 value. Snort rejects rvalue values of 0 and requires
values to be between [1..max-uint32 value].
Suricata will never match if there's a zero divisor. Division by 0 is undefined.
byte_test KeywordSuricata allows a variable name from byte_extract or byte_math
to be specified for the nbytes value. The value of nbytes must adhere
to the same constraints as though a value was directly supplied by the rule.
Suricata allows a variable name from byte_extract to be specified for
the nbytes value. The value of nbytes must adhere to the same constraints
as if it were supplied directly in the rule.
isdataat KeywordThe 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:
isdataat:!0,relative;isdataat:!1,relative;With Snort, the "inspection buffer" used when checking an
isdataat keyword is generally the packet/segment with some
exceptions:
file_data or base64_data has
been set, it is those buffers (unless rawbytes is set).rawbytes is set).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 a http_* buffer, the relative isdataat
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.
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.
tls* KeywordsIn 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:
For details see :doc:tls-keywords.
dns_query KeywordSets 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 :doc:dns-keywords for details.
iprep KeywordSnort 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:
Suricata rules can leverage these IP lists with the iprep
keyword that can be configured to match on:
:doc:../reputation/index
:doc:../reputation/ipreputation/ip-reputation-config
:doc:ip-reputation-rules
:doc:../reputation/ipreputation/ip-reputation-format
https://blog.inliniac.net/2012/11/21/ip-reputation-in-suricata/ <https://blog.inliniac.net/2012/11/21/ip-reputation-in-suricata/>_
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 other content 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 <https://redmine.openinfosecfoundation.org/issues/1399>_.
:doc:flow-keywords
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.
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.
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;
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:
filenamefileextfilemagicfilesizefilemd5filesha1filesha256filesizefile-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.
:doc:file-keywords
:doc:../file-extraction/file-extraction
https://blog.inliniac.net/2011/11/29/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/ <https://blog.inliniac.net/2014/11/11/smtp-file-extraction-in-suricata/>_
lua keyword which allows for a
rule to reference a Lua script that can access the packet, payload,
HTTP buffers, etc.lua-detectionSnort'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) unless
fast_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, including
http_raw_*' and http_cookie`` buffers.
Suricata supports the fast_pattern:only syntax but
technically it is not really implemented; the only is
silently ignored when encountered in a rule. It is still recommended
that you use fast_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 such http_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) to http_* buffers (except for http_method,
http_stat_code, and http_stat_msg).
See :doc:fast-pattern-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 into account depth and offset
when doing fast pattern matching, something the other algorithms and
Snort do not do.
:ref:rules-keyword-fast_pattern
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 ...tcp-stream – example:
alert tcp-stream ...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.
+-----------------------+------------------------------------------+-------------------------------------------+--------+----------------+------------------+ | Buffer | Snort 2.9.x | Suricata | PCRE | Can be used as | Suricata Fast | | | Support? | Support? | flag | Fast Pattern? | 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