From 6c0d365bdb5f4e4fdc2bf57561178573be5a36cc Mon Sep 17 00:00:00 2001 From: bmeeks8 Date: Tue, 26 Aug 2014 21:39:21 -0400 Subject: Upgrade Suricata to 2.0.3 and GUI package to v2.0 --- config/suricata/suricata_alerts.php | 445 +++++++++++++++++++++++++++++------- 1 file changed, 363 insertions(+), 82 deletions(-) (limited to 'config/suricata/suricata_alerts.php') diff --git a/config/suricata/suricata_alerts.php b/config/suricata/suricata_alerts.php index 2f0f114f..60a506ae 100644 --- a/config/suricata/suricata_alerts.php +++ b/config/suricata/suricata_alerts.php @@ -11,6 +11,7 @@ * Copyright (C) 2006 Scott Ullrich * Copyright (C) 2009 Robert Zelaya Sr. Developer * Copyright (C) 2012 Ermal Luci + * Copyright (C) 2014 Jim Pingle jim@pingle.org * All rights reserved. * * Adapted for Suricata by: @@ -44,6 +45,7 @@ require_once("/usr/local/pkg/suricata/suricata.inc"); $supplist = array(); $suri_pf_table = SURICATA_PF_TABLE; +$filterlogentries = FALSE; function suricata_is_alert_globally_suppressed($list, $gid, $sid) { @@ -132,6 +134,31 @@ function suricata_add_supplist_entry($suppress) { return false; } +function suricata_escape_filter_regex($filtertext) { + /* If the caller (user) has not already put a backslash before a slash, to escape it in the regex, */ + /* then this will do it. Take out any "\/" already there, then turn all ordinary "/" into "\/". */ + return str_replace('/', '\/', str_replace('\/', '/', $filtertext)); +} + +function suricata_match_filter_field($flent, $fields) { + foreach ($fields as $key => $field) { + if ($field == null) + continue; + if ((strpos($field, '!') === 0)) { + $field = substr($field, 1); + $field_regex = suricata_escape_filter_regex($field); + if (@preg_match("/{$field_regex}/i", $flent[$key])) + return false; + } + else { + $field_regex = suricata_escape_filter_regex($field); + if (!@preg_match("/{$field_regex}/i", $flent[$key])) + return false; + } + } + return true; +} + if (isset($_POST['instance']) && is_numericint($_POST['instance'])) $instanceid = $_POST['instance']; // This is for the auto-refresh so we can stay on the same interface @@ -164,6 +191,49 @@ if (empty($pconfig['arefresh'])) $pconfig['arefresh'] = 'off'; $anentries = $pconfig['alertnumber']; +# --- AJAX REVERSE DNS RESOLVE Start --- +if (isset($_POST['resolve'])) { + $ip = strtolower($_POST['resolve']); + $res = (is_ipaddr($ip) ? gethostbyaddr($ip) : ''); + + if ($res && $res != $ip) + $response = array('resolve_ip' => $ip, 'resolve_text' => $res); + else + $response = array('resolve_ip' => $ip, 'resolve_text' => gettext("Cannot resolve")); + + echo json_encode(str_replace("\\","\\\\", $response)); // single escape chars can break JSON decode + exit; +} +# --- AJAX REVERSE DNS RESOLVE End --- + +if ($_POST['filterlogentries_submit']) { + // Set flag for filtering alert entries + $filterlogentries = TRUE; + + // -- IMPORTANT -- + // Note the order of these fields must match the order decoded from the alerts log + $filterfieldsarray = array(); + $filterfieldsarray['time'] = $_POST['filterlogentries_time'] ? $_POST['filterlogentries_time'] : null; + $filterfieldsarray['action'] = null; + $filterfieldsarray['gid'] = $_POST['filterlogentries_gid'] ? $_POST['filterlogentries_gid'] : null; + $filterfieldsarray['sid'] = $_POST['filterlogentries_sid'] ? $_POST['filterlogentries_sid'] : null; + $filterfieldsarray['rev'] = null; + $filterfieldsarray['msg'] = $_POST['filterlogentries_description'] ? $_POST['filterlogentries_description'] : null; + $filterfieldsarray['class'] = $_POST['filterlogentries_classification'] ? $_POST['filterlogentries_classification'] : null; + $filterfieldsarray['priority'] = $_POST['filterlogentries_priority'] ? $_POST['filterlogentries_priority'] : null; + $filterfieldsarray['proto'] = $_POST['filterlogentries_protocol'] ? $_POST['filterlogentries_protocol'] : null; + // Remove any zero-length spaces added to the IP address that could creep in from a copy-paste operation + $filterfieldsarray['src'] = $_POST['filterlogentries_sourceipaddress'] ? str_replace("\xE2\x80\x8B", "", $_POST['filterlogentries_sourceipaddress']) : null; + $filterfieldsarray['sport'] = $_POST['filterlogentries_sourceport'] ? $_POST['filterlogentries_sourceport'] : null; + // Remove any zero-length spaces added to the IP address that could creep in from a copy-paste operation + $filterfieldsarray['dst'] = $_POST['filterlogentries_destinationipaddress'] ? str_replace("\xE2\x80\x8B", "", $_POST['filterlogentries_destinationipaddress']) : null; + $filterfieldsarray['dport'] = $_POST['filterlogentries_destinationport'] ? $_POST['filterlogentries_destinationport'] : null; +} + +if ($_POST['filterlogentries_clear']) { + $filterfieldsarray = array(); +} + if ($_POST['save']) { if (!is_array($config['installedpackages']['suricata']['alertsblocks'])) $config['installedpackages']['suricata']['alertsblocks'] = array(); @@ -277,7 +347,9 @@ if ($_POST['togglesid'] && is_numeric($_POST['sidid']) && is_numeric($_POST['gen /* rules for this interface. */ /*************************************************/ $rebuild_rules = true; + conf_mount_rw(); suricata_generate_yaml($a_instance[$instanceid]); + conf_mount_ro(); $rebuild_rules = false; /* Signal Suricata to live-load the new rules */ @@ -334,7 +406,6 @@ include_once("head.inc"); ?> - + - +
+ @@ -416,6 +491,87 @@ if ($savemsg) {  ', '', '', ''); ?> + + + + "> + + + + "> + + @@ -436,7 +592,7 @@ if ($savemsg) { - + @@ -445,7 +601,7 @@ if ($savemsg) { - + @@ -458,95 +614,175 @@ if (file_exists("/var/log/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.lo if (file_exists("/tmp/alerts_suricata{$suricata_uuid}")) { $tmpblocked = array_flip(suricata_get_blocked_ips()); $counter = 0; - /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ - /* File format timestamp,action,sig_generator,sig_id,sig_rev,msg,classification,priority,proto,src,srcport,dst,dstport */ + + /*************** FORMAT without CSV patch -- ALERT -- ***********************************************************************************/ + /* Line format: timestamp action[**] [gid:sid:rev] msg [**] [Classification: class] [Priority: pri] {proto} src:srcport -> dst:dstport */ + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ + /****************************************************************************************************************************************/ + + /**************** FORMAT without CSV patch -- DECODER EVENT -- **************************************************************************/ + /* Line format: timestamp action[**] [gid:sid:rev] msg [**] [Classification: class] [Priority: pri] [**] [Raw pkt: ...] */ + /* 0 1 2 3 4 5 6 7 */ + /************** *************************************************************************************************************************/ + $fd = fopen("/tmp/alerts_suricata{$suricata_uuid}", "r"); - while (($fields = fgetcsv($fd, 1000, ',', '"')) !== FALSE) { - if(count($fields) < 13) - continue; + $buf = ""; + while (($buf = fgets($fd)) !== FALSE) { + $fields = array(); + $tmp = array(); + $decoder_event = FALSE; + + /**************************************************************/ + /* Parse alert log entry to find the parts we want to display */ + /**************************************************************/ + + // Field 0 is the event timestamp + $fields['time'] = substr($buf, 0, strpos($buf, ' ')); + + // Field 1 is currently not used, so set to NULL + $fields['action'] = null; + + // The regular expression match below returns an array as follows: + // [2] => GID, [3] => SID, [4] => REV, [5] => MSG, [6] => CLASSIFICATION, [7] = PRIORITY + preg_match('/\[\*{2}\]\s\[((\d+):(\d+):(\d+))\]\s(.*)\[\*{2}\]\s\[Classification:\s(.*)\]\s\[Priority:\s(\d+)\]\s/', $buf, $tmp); + $fields['gid'] = trim($tmp[2]); + $fields['sid'] = trim($tmp[3]); + $fields['rev'] = trim($tmp[4]); + $fields['msg'] = trim($tmp[5]); + $fields['class'] = trim($tmp[6]); + $fields['priority'] = trim($tmp[7]); + + // The regular expression match below looks for the PROTO, SRC and DST fields + // and returns an array as follows: + // [1] = PROTO, [2] => SRC:SPORT [3] => DST:DPORT + if (preg_match('/\{(.*)\}\s(.*)\s->\s(.*)/', $buf, $tmp)) { + // Get PROTO + $fields['proto'] = trim($tmp[1]); + + // Get SRC + $fields['src'] = trim(substr($tmp[2], 0, strrpos($tmp[2], ':'))); + if (is_ipaddrv6($fields['src'])) + $fields['src'] = inet_ntop(inet_pton($fields['src'])); + + // Get SPORT + $fields['sport'] = trim(substr($tmp[2], strrpos($tmp[2], ':') + 1)); + + // Get DST + $fields['dst'] = trim(substr($tmp[3], 0, strrpos($tmp[3], ':'))); + if (is_ipaddrv6($fields['dst'])) + $fields['dst'] = inet_ntop(inet_pton($fields['dst'])); + + // Get DPORT + $fields['dport'] = trim(substr($tmp[3], strrpos($tmp[3], ':') + 1)); + } + else { + // If no PROTO nor IP ADDR, then this is a DECODER EVENT + $decoder_event = TRUE; + $fields['proto'] = gettext("n/a"); + $fields['sport'] = gettext("n/a"); + $fields['dport'] = gettext("n/a"); + } // Create a DateTime object from the event timestamp that // we can use to easily manipulate output formats. - $event_tm = date_create_from_format("m/d/Y-H:i:s.u", $fields[0]); + $event_tm = date_create_from_format("m/d/Y-H:i:s.u", $fields['time']); // Check the 'CATEGORY' field for the text "(null)" and // substitute "Not Assigned". - if ($fields[6] == "(null)") - $fields[6] = "Not Assigned"; + if ($fields['class'] == "(null)") + $fields['class'] = gettext("Not Assigned"); + + $fields['time'] = date_format($event_tm, "m/d/Y") . " " . date_format($event_tm, "H:i:s"); + if ($filterlogentries && !suricata_match_filter_field($fields, $filterfieldsarray)) { + continue; + } /* Time */ $alert_time = date_format($event_tm, "H:i:s"); /* Date */ $alert_date = date_format($event_tm, "m/d/Y"); /* Description */ - $alert_descr = $fields[5]; - $alert_descr_url = urlencode($fields[5]); + $alert_descr = $fields['msg']; + $alert_descr_url = urlencode($fields['msg']); /* Priority */ - $alert_priority = $fields[7]; + $alert_priority = $fields['priority']; /* Protocol */ - $alert_proto = $fields[8]; + $alert_proto = $fields['proto']; + /* IP SRC */ - $alert_ip_src = $fields[9]; - /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ - $alert_ip_src = str_replace(":", ":​", $alert_ip_src); - /* Add Reverse DNS lookup icons */ - $alert_ip_src .= "
"; - $alert_ip_src .= " "; - $alert_ip_src .= ""; - $alert_ip_src .= ""; - /* Add icons for auto-adding to Suppress List if appropriate */ - if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3]) && - !isset($supplist[$fields[2]][$fields[3]]['by_src'][$fields[9]])) { - $alert_ip_src .= "  "; - } - elseif (isset($supplist[$fields[2]][$fields[3]]['by_src'][$fields[9]])) { - $alert_ip_src .= "  "; + if ($decoder_event == FALSE) { + $alert_ip_src = $fields['src']; + /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ + $alert_ip_src = str_replace(":", ":​", $alert_ip_src); + /* Add Reverse DNS lookup icon */ + $alert_ip_src .= "
\"Icon"; + /* Add icons for auto-adding to Suppress List if appropriate */ + if (!suricata_is_alert_globally_suppressed($supplist, $fields['gid'], $fields['sid']) && + !isset($supplist[$fields['gid']][$fields['sid']]['by_src'][$fields['src']])) { + $alert_ip_src .= "  "; + } + elseif (isset($supplist[$fields['gid']][$fields['sid']]['by_src'][$fields['src']])) { + $alert_ip_src .= "  "; + } + /* Add icon for auto-removing from Blocked Table if required */ + if (isset($tmpblocked[$fields['src']])) { + $alert_ip_src .= " "; + } } - /* Add icon for auto-removing from Blocked Table if required */ - if (isset($tmpblocked[$fields[9]])) { - $alert_ip_src .= " "; + else { + if (preg_match('/\s\[Raw pkt:(.*)\]/', $buf, $tmp)) + $alert_ip_src = "
" . gettext("Decoder Event") . "
"; + else + $alert_ip_src = gettext("Decoder Event"); } + /* IP SRC Port */ - $alert_src_p = $fields[10]; - /* IP Destination */ - $alert_ip_dst = $fields[11]; - /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ - $alert_ip_dst = str_replace(":", ":​", $alert_ip_dst); - /* Add Reverse DNS lookup icons */ - $alert_ip_dst .= "
"; - $alert_ip_dst .= " "; - $alert_ip_dst .= ""; - $alert_ip_dst .= ""; - /* Add icons for auto-adding to Suppress List if appropriate */ - if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3]) && - !isset($supplist[$fields[2]][$fields[3]]['by_dst'][$fields[11]])) { - $alert_ip_dst .= "  "; - } - elseif (isset($supplist[$fields[2]][$fields[3]]['by_dst'][$fields[11]])) { - $alert_ip_dst .= "  "; + $alert_src_p = $fields['sport']; + + /* IP DST */ + if ($decoder_event == FALSE) { + $alert_ip_dst = $fields['dst']; + /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ + $alert_ip_dst = str_replace(":", ":​", $alert_ip_dst); + /* Add Reverse DNS lookup icons */ + $alert_ip_dst .= "
\"Icon"; + /* Add icons for auto-adding to Suppress List if appropriate */ + if (!suricata_is_alert_globally_suppressed($supplist, $fields['gid'], $fields['sid']) && + !isset($supplist[$fields['gid']][$fields['sid']]['by_dst'][$fields['dst']])) { + $alert_ip_dst .= "  "; + } + elseif (isset($supplist[$fields['gid']][$fields['sid']]['by_dst'][$fields['dst']])) { + $alert_ip_dst .= "  "; + } + + /* Add icon for auto-removing from Blocked Table if required */ + if (isset($tmpblocked[$fields['dst']])) { + $alert_ip_dst .= " "; + } } - /* Add icon for auto-removing from Blocked Table if required */ - if (isset($tmpblocked[$fields[11]])) { - $alert_ip_dst .= " "; + else { + $alert_ip_dst = gettext("n/a"); } + /* IP DST Port */ - $alert_dst_p = $fields[12]; + $alert_dst_p = $fields['dport']; + /* SID */ - $alert_sid_str = "{$fields[2]}:{$fields[3]}"; - if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3])) { - $sidsupplink = ""; } @@ -555,34 +791,35 @@ if (file_exists("/var/log/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.lo $sidsupplink .= "title='" . gettext("This alert is already in the Suppress List") . "'/>"; } /* Add icon for toggling rule state */ - if (isset($disablesid[$fields[2]][$fields[3]])) { - $sid_dsbl_link = ""; } else { - $sid_dsbl_link = ""; } /* DESCRIPTION */ - $alert_class = $fields[6]; + $alert_class = $fields['class']; echo " - + - + - + \n"; $counter++; } + unset($fields, $buf, $tmp); fclose($fd); @unlink("/tmp/alerts_suricata{$suricata_uuid}"); } @@ -591,10 +828,10 @@ if (file_exists("/var/log/suricata/suricata_{$if_real}{$suricata_uuid}/alerts.lo
+ " onclick="enable_showFilter();" /> +    +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
" title="" /> +    " title="" /> +    " onclick="enable_hideFilter();" title="" />
+
+  ', '');?>   +    +
+
  
{$alert_date}
{$alert_time}
{$alert_priority} {$alert_proto} {$alert_class}{$alert_ip_src}{$alert_ip_src} {$alert_src_p}{$alert_ip_dst}{$alert_ip_dst} {$alert_dst_p}{$alert_sid_str}
{$sidsupplink}  {$sid_dsbl_link}
{$alert_sid_str}
{$sidsupplink}  {$sid_dsbl_link}
{$alert_descr}
- + + + + + + -- cgit v1.2.3