The information in this guide is very old and likely no longer applicable to current versions of Graylog. Please take that into account when reading the following content.
This guide describes how to send structured Snort IDS alert logs into Graylog.
A blog post with use-cases can be found on the Graylog Blog: Visualize and Correlate IDS Alerts with Open Source Tools
First, instruct Snort to write all alerts to the local syslog daemon:
# snort.conf
output alert_syslog: LOG_LOCAL5 LOG_ALERT
Next, configure the local syslog daemon to forward logs to Graylog. If you are using rsyslog, it would look like the following:
$template GRAYLOGRFC5424,"<%PRI%>%PROTOCOL-VERSION% %TIMESTAMP:::date-rfc3339% %HOSTNAME% %APP-NAME% %PROCID% %MSGID% %STRUCTURED-DATA% %msg%\n"
local5.alert @graylog.example.org:514;GRAYLOGRFC5424
In Graylog, set up a UDP syslog input at the port and network interface you configured in rsyslog earlier and confirm that messages are arriving. For examples, you could enable ICMP IDS rules and ping a host you are monitoring with Snort to trigger an alert to arrive in Graylog.
You’ll notice that the alert information is not parsed by Graylog yet. We will set up a Graylog Processing Pipeline to identify snort logs and parse the alert into a message with extracted fields.
Below is the rule we are using:
rule "Extract Snort alert fields"
when
has_field("message")
then
let m = regex("let m = regex("^\\s?\\[(\\d+):(\\d+):(\\d+)\\] (.+?) \\[Classification: (.+?)\\] \\[Priority: (\\d+)] \\{(.+?)\\} ((?:\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(?:(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])))(:(\\d{1,5}))? -> ((?:\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3})|(?:(?:[0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,7}:|(?:[0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|(?:[0-9a-fA-F]{1,4}:){1,5}(?::[0-9a-fA-F]{1,4}){1,2}|(?:[0-9a-fA-F]{1,4}:){1,4}(?::[0-9a-fA-F]{1,4}){1,3}|(?:[0-9a-fA-F]{1,4}:){1,3}(?::[0-9a-fA-F]{1,4}){1,4}|(?:[0-9a-fA-F]{1,4}:){1,2}(?::[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:(?:(?::[0-9a-fA-F]{1,4}){1,6})|:(?:(?::[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(?::[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(?:ffff(?::0{1,4}){0,1}:){0,1}(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])|(?:[0-9a-fA-F]{1,4}:){1,4}:(?:(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(?:25[0-5]|(?:2[0-4]|1{0,1}[0-9]){0,1}[0-9])))(:(\\d{1,5}))?\\R?", to_string($message.message));", to_string($message.message));
set_field("snort_alert", true);
set_field("generator_id", m["0"]);
set_field("signature_id", m["1"]);
set_field("signature_revision_id", m["2"]);
set_field("description", m["3"]);
set_field("classification", m["4"]);
set_field("priority", to_long(m["5"]));
set_field("protocol", m["6"]);
set_field("src_addr", m["7"]);
set_field("src_port", to_long(m["9"]));
set_field("dst_addr", m["10"]);
set_field("dst_port", to_long(m["12"]));
end
Then, connect this pipeline to a stream with the following rules to apply to all snort messages:
# Stream "Snort Alerts"
# Rule 1:
message must match regular expression ^\s?\[\d+:\d+:\d+].*
# Rule 2:
application_name must match exactly snort
Now all Snort alerts should arrive in Graylog with nicely parsed and extracted fields:

