doc: add configuration
@ -0,0 +1,119 @@
|
||||
Global-Thresholds
|
||||
=================
|
||||
|
||||
Thresholds can be configured in the rules themselves, see
|
||||
:doc:`../rules/thresholding`. They are often set by rule writers based on
|
||||
their intel for creating a rule combined with a judgement on how often
|
||||
a rule will alert.
|
||||
|
||||
Next to these settings, thresholding can be configured on the sensor
|
||||
using the threshold.config.
|
||||
|
||||
threshold/event_filter
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Syntax:
|
||||
|
||||
::
|
||||
|
||||
threshold gen_id <gid>, sig_id <sid>, type <threshold|limit|both>, track <by_src|by_dst>, count <N>, seconds <T>
|
||||
|
||||
rate_filter
|
||||
~~~~~~~~~~~
|
||||
|
||||
TODO
|
||||
|
||||
suppress
|
||||
~~~~~~~~
|
||||
|
||||
Suppressions can be used to suppress alerts for a rule or a
|
||||
host/network. Actions performed when a rule matches, such as setting a
|
||||
flowbit, are still performed.
|
||||
|
||||
Syntax:
|
||||
|
||||
::
|
||||
|
||||
suppress gen_id <gid>, sig_id <sid>
|
||||
suppress gen_id <gid>, sig_id <sid>, track <by_src|by_dst>, ip <ip|subnet>
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
suppress gen_id 1, sig_id 2002087, track by_src, ip 209.132.180.67
|
||||
|
||||
This will make sure the signature 2002087 will never match for src
|
||||
host 209.132.180.67.
|
||||
|
||||
.. _global-thresholds-vs-rule-thresholds:
|
||||
|
||||
Global thresholds vs rule thresholds
|
||||
------------------------------------
|
||||
|
||||
**Note: this section applies to 1.4+ In 1.3 and before mixing rule and
|
||||
global thresholds is not supported.**
|
||||
|
||||
When a rule has a threshold/detection_filter set a rule can still be
|
||||
affected by the global threshold file.
|
||||
|
||||
The rule below will only fire if 10 or more emails are being
|
||||
delivered/sent from a host within 60 seconds.
|
||||
|
||||
::
|
||||
|
||||
alert tcp any any -> any 25 (msg:"ET POLICY Inbound Frequent Emails - Possible Spambot Inbound"; \
|
||||
flow:established; content:"mail from|3a|"; nocase; \
|
||||
threshold: type threshold, track by_src, count 10, seconds 60; \
|
||||
reference:url,doc.emergingthreats.net/2002087; classtype:misc-activity; sid:2002087; rev:10;)
|
||||
|
||||
Next, we'll see how global settings affect this rule.
|
||||
|
||||
Suppress
|
||||
~~~~~~~~
|
||||
|
||||
Suppressions can be combined with rules with
|
||||
thresholds/detection_filters with no exceptions.
|
||||
|
||||
::
|
||||
|
||||
suppress gen_id 1, sig_id 2002087, track by_src, ip 209.132.180.67
|
||||
suppress gen_id 0, sig_id 0, track by_src, ip 209.132.180.67
|
||||
suppress gen_id 1, sig_id 0, track by_src, ip 209.132.180.67
|
||||
|
||||
Each of the rules above will make sure 2002087 doesn't alert when the
|
||||
source of the emails is 209.132.180.67. It **will** alert for all other
|
||||
hosts.
|
||||
|
||||
::
|
||||
|
||||
suppress gen_id 1, sig_id 2002087
|
||||
|
||||
This suppression will simply convert the rule to "noalert", meaning it
|
||||
will never alert in any case. If the rule sets a flowbit, that will
|
||||
still happen.
|
||||
|
||||
Threshold/event_filter
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
When applied to a specific signature, thresholds and event_filters
|
||||
(threshold from now on) will override the signature setting. This can
|
||||
be useful for when the default in a signature doesn't suit your
|
||||
evironment.
|
||||
|
||||
::
|
||||
|
||||
threshold gen_id 1, sig_id 2002087, type both, track by_src, count 3, seconds 5
|
||||
threshold gen_id 1, sig_id 2002087, type threshold, track by_src, count 10, seconds 60
|
||||
threshold gen_id 1, sig_id 2002087, type limit, track by_src, count 1, seconds 15
|
||||
|
||||
Each of these will replace the threshold setting for 2002087 by the
|
||||
new threshold setting.
|
||||
|
||||
**Note:** overriding all gids or sids (by using gen_id 0 or sig_id 0)
|
||||
is not supported. Bug #425.
|
||||
|
||||
Rate_filter
|
||||
~~~~~~~~~~~
|
||||
|
||||
TODO
|
@ -0,0 +1,11 @@
|
||||
Configuration
|
||||
=============
|
||||
|
||||
.. toctree::
|
||||
|
||||
suricata-yaml
|
||||
global-thresholds
|
||||
snort-to-suricata
|
||||
log-rotation
|
||||
lua-output
|
||||
multi-tenant
|
@ -0,0 +1,31 @@
|
||||
Log Rotation
|
||||
============
|
||||
|
||||
Starting with Suricata version 2.0.2 (#1200), log rotation is made a
|
||||
lot easier. A HUP signal sent to Suricata will force it to reopen the
|
||||
logfiles.
|
||||
|
||||
Example logrotate file:
|
||||
|
||||
::
|
||||
|
||||
/var/log/suricata/*.log /var/log/suricata/*.json
|
||||
{
|
||||
rotate 3
|
||||
missingok
|
||||
nocompress
|
||||
create
|
||||
sharedscripts
|
||||
postrotate
|
||||
/bin/kill -HUP $(cat /var/run/suricata.pid)
|
||||
endscript
|
||||
}
|
||||
|
||||
newsyslog based log rotation (e.g. on OpenBSD) /etc/newsyslog.conf:
|
||||
|
||||
::
|
||||
|
||||
/var/log/suricata/eve.json root:wheel 640 1 * 24 B /var/run/suricata.pid SIGHUP
|
||||
|
||||
The above rotates every 24h; the 'B' prevents a rotation logmessage in
|
||||
eve.json. Fieldseperator is a TAB.
|
@ -0,0 +1,656 @@
|
||||
Lua Output
|
||||
==========
|
||||
|
||||
Note: this page new Lua scripting available for outputs. It will be
|
||||
available in 2.1.
|
||||
|
||||
Script structure
|
||||
----------------
|
||||
|
||||
A script defines 4 functions: init, setup, log, deinit
|
||||
|
||||
* init -- registers where the script hooks into the output engine
|
||||
* setup -- does per output thread setup
|
||||
* log -- logging function
|
||||
* deinit -- clean up function
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["protocol"] = "http"
|
||||
return needs
|
||||
end
|
||||
|
||||
function setup (args)
|
||||
filename = SCLogPath() .. "/" .. name
|
||||
file = assert(io.open(filename, "a"))
|
||||
SCLogInfo("HTTP Log Filename " .. filename)
|
||||
http = 0
|
||||
end
|
||||
|
||||
function log(args)
|
||||
http_uri = HttpGetRequestUriRaw()
|
||||
if http_uri == nil then
|
||||
http_uri = "<unknown>"
|
||||
end
|
||||
http_uri = string.gsub(http_uri, "%c", ".")
|
||||
|
||||
http_host = HttpGetRequestHost()
|
||||
if http_host == nil then
|
||||
http_host = "<hostname unknown>"
|
||||
end
|
||||
http_host = string.gsub(http_host, "%c", ".")
|
||||
|
||||
http_ua = HttpGetRequestHeader("User-Agent")
|
||||
if http_ua == nil then
|
||||
http_ua = "<useragent unknown>"
|
||||
end
|
||||
http_ua = string.gsub(http_ua, "%g", ".")
|
||||
|
||||
ts = SCPacketTimeString()
|
||||
ipver, srcip, dstip, proto, sp, dp = SCFlowTuple()
|
||||
|
||||
file:write (ts .. " " .. http_host .. " [**] " .. http_uri .. " [**] " ..
|
||||
http_ua .. " [**] " .. srcip .. ":" .. sp .. " -> " ..
|
||||
dstip .. ":" .. dp .. "\n")
|
||||
file:flush()
|
||||
|
||||
http = http + 1
|
||||
end
|
||||
|
||||
function deinit (args)
|
||||
SCLogInfo ("HTTP transactions logged: " .. http);
|
||||
file:close(file)
|
||||
end
|
||||
|
||||
YAML
|
||||
----
|
||||
|
||||
To enable the lua output, add the 'lua' output and add one or more
|
||||
scripts like so:
|
||||
|
||||
::
|
||||
|
||||
outputs:
|
||||
- lua:
|
||||
enabled: yes
|
||||
scripts-dir: /etc/suricata/lua-output/
|
||||
scripts:
|
||||
- tcp-data.lua
|
||||
- flow.lua
|
||||
|
||||
The scripts-dir option is optional. It makes Suricata load the scripts
|
||||
from this directory. Otherwise scripts will be loaded from the current
|
||||
workdir.
|
||||
|
||||
packet
|
||||
------
|
||||
|
||||
Initialize with:
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["type"] = "packet"
|
||||
return needs
|
||||
end
|
||||
|
||||
SCPacketTimeString
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Add SCPacketTimeString to get the packets time string in the format:
|
||||
11/24/2009-18:57:25.179869
|
||||
|
||||
::
|
||||
|
||||
function log(args)
|
||||
ts = SCPacketTimeString()
|
||||
|
||||
SCPacketTuple
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
ipver, srcip, dstip, proto, sp, dp = SCPacketTuple()
|
||||
|
||||
SCPacketPayload
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
p = SCPacketPayload()
|
||||
|
||||
flow
|
||||
----
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["type"] = "flow"
|
||||
return needs
|
||||
end
|
||||
|
||||
SCFlowTimeString
|
||||
~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
startts = SCFlowTimeString()
|
||||
|
||||
SCFlowTuple
|
||||
~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
ipver, srcip, dstip, proto, sp, dp = SCFlowTuple()
|
||||
|
||||
SCFlowAppLayerProto
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Get alproto as string from the flow. If alproto is not (yet) known, it
|
||||
returns "unknown".
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
function log(args)
|
||||
alproto = SCFlowAppLayerProto()
|
||||
if alproto ~= nil then
|
||||
print (alproto)
|
||||
end
|
||||
end
|
||||
|
||||
SCFlowStats
|
||||
~~~~~~~~~~~
|
||||
|
||||
Gets the packet and byte counts per flow.
|
||||
|
||||
::
|
||||
|
||||
tscnt, tsbytes, tccnt, tcbytes = SCFlowStats()
|
||||
|
||||
http
|
||||
----
|
||||
|
||||
Init with:
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["protocol"] = "http"
|
||||
return needs
|
||||
end
|
||||
|
||||
HttpGetRequestBody and HttpGetResponseBody.
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Make normalized body data available to the script through
|
||||
HttpGetRequestBody and HttpGetResponseBody.
|
||||
|
||||
There no guarantees that all of the body will be availble.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
function log(args)
|
||||
a, o, e = HttpGetResponseBody();
|
||||
--print("offset " .. o .. " end " .. e)
|
||||
for n, v in ipairs(a) do
|
||||
print(v)
|
||||
end
|
||||
end
|
||||
|
||||
HttpGetRequestHost
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Get the host from libhtp's tx->request_hostname, which can either be
|
||||
the host portion of the url or the host portion of the Host header.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
http_host = HttpGetRequestHost()
|
||||
if http_host == nil then
|
||||
http_host = "<hostname unknown>"
|
||||
end
|
||||
|
||||
HttpGetRequestHeader
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
http_ua = HttpGetRequestHeader("User-Agent")
|
||||
if http_ua == nil then
|
||||
http_ua = "<useragent unknown>"
|
||||
end
|
||||
|
||||
HttpGetResponseHeader
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
server = HttpGetResponseHeader("Server");
|
||||
print ("Server: " .. server);
|
||||
|
||||
HttpGetRequestLine
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
rl = HttpGetRequestLine();
|
||||
print ("Request Line: " .. rl);
|
||||
|
||||
HttpGetResponseLine
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
rsl = HttpGetResponseLine();
|
||||
print ("Response Line: " .. rsl);
|
||||
|
||||
HttpGetRawRequestHeaders
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
rh = HttpGetRawRequestHeaders();
|
||||
print ("Raw Request Headers: " .. rh);
|
||||
|
||||
HttpGetRawResponseHeaders
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
rh = HttpGetRawResponseHeaders();
|
||||
print ("Raw Response Headers: " .. rh);
|
||||
|
||||
HttpGetRequestUriRaw
|
||||
~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
http_uri = HttpGetRequestUriRaw()
|
||||
if http_uri == nil then
|
||||
http_uri = "<unknown>"
|
||||
end
|
||||
|
||||
HttpGetRequestUriNormalized
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
http_uri = HttpGetRequestUriNormalized()
|
||||
if http_uri == nil then
|
||||
http_uri = "<unknown>"
|
||||
end
|
||||
|
||||
HttpGetRequestHeaders
|
||||
~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
a = HttpGetRequestHeaders();
|
||||
for n, v in pairs(a) do
|
||||
print(n,v)
|
||||
end
|
||||
|
||||
HttpGetResponseHeaders
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
a = HttpGetResponseHeaders();
|
||||
for n, v in pairs(a) do
|
||||
print(n,v)
|
||||
end
|
||||
|
||||
DNS
|
||||
---
|
||||
|
||||
DnsGetQueries
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
dns_query = DnsGetQueries();
|
||||
if dns_query ~= nil then
|
||||
for n, t in pairs(dns_query) do
|
||||
rrname = t["rrname"]
|
||||
rrtype = t["type"]
|
||||
|
||||
print ("QUERY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " ..
|
||||
"TODO" .. " [**] " .. srcip .. ":" .. sp .. " -> " ..
|
||||
dstip .. ":" .. dp)
|
||||
end
|
||||
end
|
||||
|
||||
returns a table of tables
|
||||
|
||||
DnsGetAnswers
|
||||
~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
dns_answers = DnsGetAnswers();
|
||||
if dns_answers ~= nil then
|
||||
for n, t in pairs(dns_answers) do
|
||||
rrname = t["rrname"]
|
||||
rrtype = t["type"]
|
||||
ttl = t["ttl"]
|
||||
|
||||
print ("ANSWER: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " ..
|
||||
ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " ..
|
||||
dstip .. ":" .. dp)
|
||||
end
|
||||
end
|
||||
|
||||
returns a table of tables
|
||||
|
||||
DnsGetAuthorities
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
dns_auth = DnsGetAuthorities();
|
||||
if dns_auth ~= nil then
|
||||
for n, t in pairs(dns_auth) do
|
||||
rrname = t["rrname"]
|
||||
rrtype = t["type"]
|
||||
ttl = t["ttl"]
|
||||
|
||||
print ("AUTHORITY: " .. ts .. " " .. rrname .. " [**] " .. rrtype .. " [**] " ..
|
||||
ttl .. " [**] " .. srcip .. ":" .. sp .. " -> " ..
|
||||
dstip .. ":" .. dp)
|
||||
end
|
||||
end
|
||||
|
||||
returns a table of tables
|
||||
|
||||
DnsGetRcode
|
||||
~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
rcode = DnsGetRcode();
|
||||
if rcode == nil then
|
||||
return 0
|
||||
end
|
||||
print (rcode)
|
||||
|
||||
returns a lua string with the error message, or nil
|
||||
|
||||
DnsGetRecursionDesired
|
||||
~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
if DnsGetRecursionDesired() == true then
|
||||
print ("RECURSION DESIRED")
|
||||
end
|
||||
|
||||
returns a bool
|
||||
|
||||
TLS
|
||||
---
|
||||
|
||||
Initialize with:
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["protocol"] = "tls"
|
||||
return needs
|
||||
end
|
||||
|
||||
TlsGetCertInfo
|
||||
~~~~~~~~~~~~~~
|
||||
|
||||
Make certificate information available to the script through TlsGetCertInfo.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
function log (args)
|
||||
version, subject, issuer, fingerprint = TlsGetCertInfo()
|
||||
if version == nil then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
SSH
|
||||
---
|
||||
|
||||
Initialize with:
|
||||
|
||||
::
|
||||
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["protocol"] = "ssh"
|
||||
return needs
|
||||
end
|
||||
|
||||
SshGetServerProtoVersion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Get SSH protocol version used by the server through SshGetServerProtoVersion.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
function log (args)
|
||||
version = SshGetServerProtoVersion()
|
||||
if version == nil then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
SshGetServerSoftwareVersion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Get SSH software used by the server through SshGetServerSoftwareVersion.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
|
||||
function log (args)
|
||||
software = SshGetServerSoftwareVersion()
|
||||
if software == nil then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
SshGetClientProtoVersion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Get SSH protocol version used by the client through SshGetClientProtoVersion.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
function log (args)
|
||||
version = SshGetClientProtoVersion()
|
||||
if version == nil then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
SshGetClientSoftwareVersion
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Get SSH software used by the client through SshGetClientSoftwareVersion.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
function log (args)
|
||||
software = SshGetClientSoftwareVersion()
|
||||
if software == nil then
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
Files
|
||||
-----
|
||||
|
||||
To use the file logging API, the script's init() function needs to look like:
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs['type'] = 'file'
|
||||
return needs
|
||||
end
|
||||
|
||||
SCFileInfo
|
||||
~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
|
||||
fileid, txid, name, size, magic, md5 = SCFileInfo()
|
||||
|
||||
returns fileid (number), txid (number), name (string), size (number),
|
||||
magic (string), md5 in hex (string)
|
||||
|
||||
SCFileState
|
||||
~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
state, stored = SCFileState()
|
||||
|
||||
returns state (string), stored (bool)
|
||||
|
||||
Alerts
|
||||
------
|
||||
|
||||
Alerts are a subset of the 'packet' logger:
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["type"] = "packet"
|
||||
needs["filter"] = "alerts"
|
||||
return needs
|
||||
end
|
||||
|
||||
SCRuleIds
|
||||
~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
sid, rev, gid = SCRuleIds()
|
||||
|
||||
SCRuleMsg
|
||||
~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
msg = SCRuleMsg()
|
||||
|
||||
SCRuleClass
|
||||
~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
|
||||
class, prio = SCRuleClass()
|
||||
|
||||
Streaming Data
|
||||
--------------
|
||||
|
||||
Streaming data can currently log out reassembled TCP data and
|
||||
normalized HTTP data. The script will be invoked for each consecutive
|
||||
data chunk.
|
||||
|
||||
In case of TCP reassembled data, all possible overlaps are removed
|
||||
according to the host OS settings.
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["type"] = "streaming"
|
||||
needs["filter"] = "tcp"
|
||||
return needs
|
||||
end
|
||||
|
||||
In case of HTTP body data, the bodies are unzipped and dechunked if applicable.
|
||||
|
||||
::
|
||||
|
||||
function init (args)
|
||||
local needs = {}
|
||||
needs["type"] = "streaming"
|
||||
needs["protocol"] = "http"
|
||||
return needs
|
||||
end
|
||||
|
||||
SCStreamingBuffer
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
function log(args)
|
||||
data = SCStreamingBuffer()
|
||||
hex_dump(data)
|
||||
end
|
||||
|
||||
Misc
|
||||
----
|
||||
|
||||
SCThreadInfo
|
||||
~~~~~~~~~~~~
|
||||
|
||||
::
|
||||
|
||||
tid, tname, tgroup = SCThreadInfo()
|
||||
|
||||
It gives: tid (integer), tname (string), tgroup (string)
|
||||
|
||||
SCLogError, SCLogWarning, SCLogNotice, SCLogInfo, SCLogDebug
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Print a message. It will go into the outputs defined in the
|
||||
yaml. Whether it will be printed depends on the log level.
|
||||
|
||||
Example:
|
||||
|
||||
::
|
||||
|
||||
SCLogError("some error message")
|
||||
|
||||
SCLogPath
|
||||
~~~~~~~~~
|
||||
|
||||
Expose the log path.
|
||||
|
||||
::
|
||||
|
||||
|
||||
name = "fast_lua.log"
|
||||
function setup (args)
|
||||
filename = SCLogPath() .. "/" .. name
|
||||
file = assert(io.open(filename, "a"))
|
||||
end
|
@ -0,0 +1,167 @@
|
||||
Multi Tenancy
|
||||
=============
|
||||
|
||||
**Work In Progress**
|
||||
|
||||
This is part of Suricata 3.0RC1.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Multi tenancy support allows for different rule sets with different
|
||||
rule vars.
|
||||
|
||||
YAML
|
||||
----
|
||||
|
||||
In the main ("master") YAML, the suricata.yaml, a new section called
|
||||
"multi-detect" should be added.
|
||||
|
||||
Settings:
|
||||
|
||||
* enabled: yes/no -> is multi-tenancy support enable
|
||||
* default: yes/no -> is the normal detect config a default 'fall back' tenant?
|
||||
* selector: direct (for unix socket pcap processing, see below) or vlan
|
||||
* loaders: number of 'loader' threads, for parallel tenant loading at startup
|
||||
* tenants: list of tenants
|
||||
|
||||
* id: tenant id
|
||||
* yaml: separate yaml file with the tenant specific settings
|
||||
|
||||
* mappings:
|
||||
|
||||
* vlan id
|
||||
* tenant id: tenant to associate with the vlan id
|
||||
|
||||
::
|
||||
|
||||
multi-detect:
|
||||
enabled: yes
|
||||
#selector: direct # direct or vlan
|
||||
selector: vlan
|
||||
loaders: 3
|
||||
|
||||
tenants:
|
||||
- id: 1
|
||||
yaml: tenant-1.yaml
|
||||
- id: 2
|
||||
yaml: tenant-2.yaml
|
||||
- id: 3
|
||||
yaml: tenant-3.yaml
|
||||
|
||||
mappings:
|
||||
- vlan-id: 1000
|
||||
tenant-id: 1
|
||||
- vlan-id: 2000
|
||||
tenant-id: 2
|
||||
- vlan-id: 1112
|
||||
tenant-id: 3
|
||||
|
||||
The tenant-1.yaml, tenant-2.yaml, tenant-3.yaml each contain a partial
|
||||
configuration:
|
||||
|
||||
::
|
||||
|
||||
# Set the default rule path here to search for the files.
|
||||
# if not set, it will look at the current working dir
|
||||
default-rule-path: /etc/suricata/rules
|
||||
rule-files:
|
||||
- rules1
|
||||
|
||||
# You can specify a threshold config file by setting "threshold-file"
|
||||
# to the path of the threshold config file:
|
||||
# threshold-file: /etc/suricata/threshold.config
|
||||
|
||||
classification-file: /etc/suricata/classification.config
|
||||
reference-config-file: /etc/suricata/reference.config
|
||||
|
||||
# Holds variables that would be used by the engine.
|
||||
vars:
|
||||
|
||||
# Holds the address group vars that would be passed in a Signature.
|
||||
# These would be retrieved during the Signature address parsing stage.
|
||||
address-groups:
|
||||
|
||||
HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"
|
||||
|
||||
EXTERNAL_NET: "!$HOME_NET"
|
||||
|
||||
...
|
||||
|
||||
port-groups:
|
||||
|
||||
HTTP_PORTS: "80"
|
||||
|
||||
SHELLCODE_PORTS: "!80"
|
||||
|
||||
...
|
||||
|
||||
Unix Socket
|
||||
-----------
|
||||
|
||||
Registration
|
||||
~~~~~~~~~~~~
|
||||
|
||||
register-tenant <id> <yaml>
|
||||
|
||||
Examples:
|
||||
|
||||
::
|
||||
|
||||
register-tenant 1 tenant-1.yaml
|
||||
register-tenant 2 tenant-2.yaml
|
||||
register-tenant 3 tenant-3.yaml
|
||||
register-tenant 5 tenant-5.yaml
|
||||
register-tenant 7 tenant-7.yaml
|
||||
|
||||
unregister-tenant <id>
|
||||
|
||||
::
|
||||
|
||||
unregister-tenant 2
|
||||
unregister-tenant 1
|
||||
|
||||
Unix socket runmode (pcap processing)
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The Unix Socket "pcap-file" command can be used to select the tenant
|
||||
to inspect the pcap against:
|
||||
|
||||
::
|
||||
|
||||
pcap-file traffic1.pcap /logs1/ 1
|
||||
pcap-file traffic2.pcap /logs2/ 2
|
||||
pcap-file traffic3.pcap /logs3/ 3
|
||||
pcap-file traffic4.pcap /logs5/ 5
|
||||
pcap-file traffic5.pcap /logs7/ 7
|
||||
|
||||
This runs the traffic1.pcap against tenant 1 and it logs into /logs1/,
|
||||
traffic2.pcap against tenant 2 and logs to /logs2/ and so on.
|
||||
|
||||
Live traffic mode
|
||||
~~~~~~~~~~~~~~~~~
|
||||
|
||||
For live traffic currently only a vlan based multi-tenancy is supported.
|
||||
|
||||
The master yaml needs to have the selector set to "vlan".
|
||||
|
||||
Registration
|
||||
~~~~~~~~~~~~
|
||||
|
||||
Tenants can be mapped to vlan id's.
|
||||
|
||||
register-tenant-handler <tenant id> vlan <vlan id>
|
||||
|
||||
::
|
||||
|
||||
register-tenant-handler 1 vlan 1000
|
||||
|
||||
unregister-tenant-handler <tenant id> vlan <vlan id>
|
||||
|
||||
::
|
||||
|
||||
unregister-tenant-handler 4 vlan 1111
|
||||
unregister-tenant-handler 1 vlan 1000
|
||||
|
||||
The registration of tenant and tenant handlers can be done on a
|
||||
running engine.
|
@ -0,0 +1,276 @@
|
||||
Snort.conf to Suricata.yaml
|
||||
===========================
|
||||
|
||||
This guide is meant for those who are familiar with Snort and the
|
||||
snort.conf configuration format. This guide will provide a 1:1 mapping
|
||||
between Snort and Suricata configuration wherever possible.
|
||||
|
||||
Variables
|
||||
---------
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
ipvar HOME_NET any
|
||||
ipvar EXTERNAL_NET any
|
||||
...
|
||||
|
||||
portvar HTTP_PORTS [80,81,311,591,593,901,1220,1414,1741,1830,2301,2381,2809,3128,3702,4343,4848,5250,7001,7145,7510,7777,7779,8000,8008,8014,8028,8080,8088,8090,8118,8123,8180,8181,8243,8280,8800,8888,8899,9000,9080,9090,9091,9443,9999,11371,55555]
|
||||
portvar SHELLCODE_PORTS !80
|
||||
...
|
||||
|
||||
suricata.yaml
|
||||
|
||||
::
|
||||
|
||||
|
||||
vars:
|
||||
address-groups:
|
||||
|
||||
HOME_NET: "[192.168.0.0/16,10.0.0.0/8,172.16.0.0/12]"
|
||||
EXTERNAL_NET: "!$HOME_NET"
|
||||
|
||||
port-groups:
|
||||
HTTP_PORTS: "80"
|
||||
SHELLCODE_PORTS: "!80"
|
||||
|
||||
Note that Suricata can automatically detect HTTP traffic regardless of
|
||||
the port it uses. So the HTTP_PORTS variable is not nearly as
|
||||
important as it is with Snort, **if** you use a Suricata enabled
|
||||
ruleset.
|
||||
|
||||
Decoder alerts
|
||||
--------------
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
# Stop generic decode events:
|
||||
config disable_decode_alerts
|
||||
|
||||
# Stop Alerts on experimental TCP options
|
||||
config disable_tcpopt_experimental_alerts
|
||||
|
||||
# Stop Alerts on obsolete TCP options
|
||||
config disable_tcpopt_obsolete_alerts
|
||||
|
||||
# Stop Alerts on T/TCP alerts
|
||||
config disable_tcpopt_ttcp_alerts
|
||||
|
||||
# Stop Alerts on all other TCPOption type events:
|
||||
config disable_tcpopt_alerts
|
||||
|
||||
# Stop Alerts on invalid ip options
|
||||
config disable_ipopt_alerts
|
||||
|
||||
suricata.yaml
|
||||
|
||||
Suricata has no specific decoder options. All decoder related alerts
|
||||
are controlled by rules. See #Rules below.
|
||||
|
||||
Checksum handling
|
||||
-----------------
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
config checksum_mode: all
|
||||
|
||||
suricata.yaml
|
||||
|
||||
Suricata's checksum handling works _on-demand_. The stream engine
|
||||
checks TCP and IP checksum by default:
|
||||
|
||||
::
|
||||
|
||||
stream:
|
||||
checksum-validation: yes # reject wrong csums
|
||||
|
||||
Alerting on bad checksums can be done with normal rules. See #Rules,
|
||||
decoder-events.rules specifically.
|
||||
|
||||
Various configs
|
||||
---------------
|
||||
|
||||
Active response
|
||||
~~~~~~~~~~~~~~~
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
# Configure active response for non inline operation. For more information, see REAMDE.active
|
||||
# config response: eth0 attempts 2
|
||||
|
||||
suricata.yaml
|
||||
|
||||
Active responses are handled automatically w/o config if rules with
|
||||
the "reject" action are used.
|
||||
|
||||
Dropping privileges
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
|
||||
# Configure specific UID and GID to run snort as after dropping privs. For more information see snort -h command line options
|
||||
#
|
||||
# config set_gid:
|
||||
# config set_uid:
|
||||
|
||||
Suricata
|
||||
|
||||
To set the user and group use the --user <username> and --group
|
||||
<groupname> commandline options.
|
||||
|
||||
Snaplen
|
||||
~~~~~~~
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
# Configure default snaplen. Snort defaults to MTU of in use interface. For more information see README
|
||||
#
|
||||
# config snaplen:
|
||||
#
|
||||
|
||||
Suricata always works at full snap length to provide full traffic visibility.
|
||||
|
||||
Bpf
|
||||
~~~
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
# Configure default bpf_file to use for filtering what traffic reaches snort. For more information see snort -h command line options (-F)
|
||||
#
|
||||
# config bpf_file:
|
||||
#
|
||||
|
||||
suricata.yaml
|
||||
|
||||
BPF filters can be set per packet acquisition method, with the "bpf-filter: <file>" yaml option and in a file using the -F command line option.
|
||||
|
||||
For example:
|
||||
|
||||
::
|
||||
|
||||
pcap:
|
||||
- interface: eth0
|
||||
#buffer-size: 16777216
|
||||
#bpf-filter: "tcp and port 25"
|
||||
#checksum-checks: auto
|
||||
#threads: 16
|
||||
#promisc: no
|
||||
#snaplen: 1518
|
||||
|
||||
Log directory
|
||||
-------------
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
# Configure default log directory for snort to log to. For more information see snort -h command line options (-l)
|
||||
#
|
||||
# config logdir:
|
||||
|
||||
suricata.yaml
|
||||
|
||||
::
|
||||
|
||||
default-log-dir: /var/log/suricata/
|
||||
|
||||
This value is overridden by the -l commandline option.
|
||||
|
||||
Packet acquisition
|
||||
------------------
|
||||
|
||||
snort.conf
|
||||
|
||||
::
|
||||
|
||||
# Configure DAQ related options for inline operation. For more information, see README.daq
|
||||
#
|
||||
# config daq: <type>
|
||||
# config daq_dir: <dir>
|
||||
# config daq_mode: <mode>
|
||||
# config daq_var: <var>
|
||||
#
|
||||
# <type> ::= pcap | afpacket | dump | nfq | ipq | ipfw
|
||||
# <mode> ::= read-file | passive | inline
|
||||
# <var> ::= arbitrary <name>=<value passed to DAQ
|
||||
# <dir> ::= path as to where to look for DAQ module so's
|
||||
|
||||
suricata.yaml
|
||||
|
||||
Suricata has all packet acquisition support built-in. It's
|
||||
configuration format is very verbose.
|
||||
|
||||
::
|
||||
|
||||
pcap:
|
||||
- interface: eth0
|
||||
#buffer-size: 16777216
|
||||
#bpf-filter: "tcp and port 25"
|
||||
#checksum-checks: auto
|
||||
#threads: 16
|
||||
#promisc: no
|
||||
#snaplen: 1518
|
||||
pfring:
|
||||
afpacket:
|
||||
nfq:
|
||||
ipfw:
|
||||
|
||||
Passive vs inline vs reading files is determined by how Suricata is
|
||||
invoked on the command line.
|
||||
|
||||
Rules
|
||||
-----
|
||||
|
||||
snort.conf:
|
||||
|
||||
In snort.conf a RULE_PATH variable is set, as well as variables for
|
||||
shared object (SO) rules and preprocessor rules.
|
||||
|
||||
::
|
||||
|
||||
var RULE_PATH ../rules
|
||||
var SO_RULE_PATH ../so_rules
|
||||
var PREPROC_RULE_PATH ../preproc_rules
|
||||
|
||||
include $RULE_PATH/local.rules
|
||||
include $RULE_PATH/emerging-activex.rules
|
||||
...
|
||||
|
||||
suricata.yaml:
|
||||
|
||||
In the suricata.yaml the default rule path is set followed by a list
|
||||
of rule files. Suricata does not have a concept of shared object rules
|
||||
or preprocessor rules. Instead of preprocessor rules, Suricata has
|
||||
several rule files for events set by the decoders, stream engine, http
|
||||
parser etc.
|
||||
|
||||
::
|
||||
|
||||
default-rule-path: /etc/suricata/rules
|
||||
rule-files:
|
||||
- local.rules
|
||||
- emerging-activex.rules
|
||||
|
||||
The equivalent of preprocessor rules are loaded like normal rule files:
|
||||
|
||||
::
|
||||
|
||||
rule-files:
|
||||
- decoder-events.rules
|
||||
- stream-events.rules
|
||||
- http-events.rules
|
||||
- smtp-events.rules
|
After Width: | Height: | Size: 23 KiB |
After Width: | Height: | Size: 21 KiB |
After Width: | Height: | Size: 8.4 KiB |
After Width: | Height: | Size: 34 KiB |
After Width: | Height: | Size: 19 KiB |
After Width: | Height: | Size: 20 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 11 KiB |
After Width: | Height: | Size: 28 KiB |
After Width: | Height: | Size: 16 KiB |
After Width: | Height: | Size: 26 KiB |
After Width: | Height: | Size: 61 KiB |
After Width: | Height: | Size: 15 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 8.2 KiB |
After Width: | Height: | Size: 27 KiB |
After Width: | Height: | Size: 22 KiB |
After Width: | Height: | Size: 17 KiB |