diff options
-rw-r--r-- | config/snort/snort_alerts.js | 115 | ||||
-rw-r--r-- | config/snort/snort_alerts.widget.php | 246 | ||||
-rw-r--r-- | config/snort/widget-snort.inc | 24 |
3 files changed, 385 insertions, 0 deletions
diff --git a/config/snort/snort_alerts.js b/config/snort/snort_alerts.js new file mode 100644 index 00000000..647eb1b1 --- /dev/null +++ b/config/snort/snort_alerts.js @@ -0,0 +1,115 @@ + +var snorttimer; +var snortisBusy = false; +var snortisPaused = false; + +if (typeof getURL == 'undefined') { + getURL = function(url, callback) { + if (!url) + throw 'No URL for getURL'; + try { + if (typeof callback.operationComplete == 'function') + callback = callback.operationComplete; + } catch (e) {} + if (typeof callback != 'function') + throw 'No callback function for getURL'; + var http_request = null; + if (typeof XMLHttpRequest != 'undefined') { + http_request = new XMLHttpRequest(); + } + else if (typeof ActiveXObject != 'undefined') { + try { + http_request = new ActiveXObject('Msxml2.XMLHTTP'); + } catch (e) { + try { + http_request = new ActiveXObject('Microsoft.XMLHTTP'); + } catch (e) {} + } + } + if (!http_request) + throw 'Both getURL and XMLHttpRequest are undefined'; + http_request.onreadystatechange = function() { + if (http_request.readyState == 4) { + callback( { success : true, + content : http_request.responseText, + contentType : http_request.getResponseHeader("Content-Type") } ); + } + } + http_request.open('GET', url, true); + http_request.send(null); + } +} + +function snort_alerts_fetch_new_events_callback(callback_data) { + var data_split; + var new_data_to_add = Array(); + var data = callback_data.content; + data_split = data.split("\n"); + + // Loop through rows and generate replacement HTML + for(var x=0; x<data_split.length-1; x++) { + row_split = data_split[x].split("||"); + var line = ''; + line = '<td class="' + snortWidgetColClass + '">' + row_split[0] + '<br/>' + row_split[1] + '</td>'; + line += '<td class="' + snortWidgetColClass + '" style="overflow: hidden; text-overflow: ellipsis;" nowrap>'; + line += '<div style="display:inline;" title="' + row_split[2] + '">' + row_split[2] + '</div><br/>'; + line += '<div style="display:inline;" title="' + row_split[3] + '">' + row_split[3] + '</div></td>'; + line += '<td class="' + snortWidgetColClass + '">' + 'Priority: ' + row_split[4] + ' ' + row_split[5] + '</td>'; + new_data_to_add[new_data_to_add.length] = line; + } + snort_alerts_update_div_rows(new_data_to_add); + snortisBusy = false; +} + +function snort_alerts_update_div_rows(data) { + if(snortisPaused) + return; + + var rows = $$('#snort-alert-entries>tr'); + + // Number of rows to move by + var move = rows.length + data.length - snort_nentries; + if (move < 0) + move = 0; + + for (var i = rows.length - 1; i >= move; i--) { + rows[i].innerHTML = rows[i - move].innerHTML; + } + + var tbody = $$('#snort-alert-entries'); + for (var i = data.length - 1; i >= 0; i--) { + if (i < rows.length) { + rows[i].innerHTML = data[i]; + } else { + var newRow = document.getElementById('snort-alert-entries').insertRow(0); + newRow.innerHTML = data[i]; + } + } + + // Add the even/odd class to each of the rows now + // they have all been added. + rows = $$('#snort-alert-entries>tr'); + for (var i = 0; i < rows.length; i++) { + rows[i].className = i % 2 == 0 ? snortWidgetRowOddClass : snortWidgetRowEvenClass; + } +} + +function fetch_new_snortalerts() { + if(snortisPaused) + return; + if(snortisBusy) + return; + snortisBusy = true; + getURL('/widgets/widgets/snort_alerts.widget.php?getNewAlerts=' + new Date().getTime(), snort_alerts_fetch_new_events_callback); +} + +function snort_alerts_toggle_pause() { + if(snortisPaused) { + snortisPaused = false; + fetch_new_snortalerts(); + } else { + snortisPaused = true; + } +} +/* start local AJAX engine */ +snorttimer = setInterval('fetch_new_snortalerts()', snortupdateDelay); diff --git a/config/snort/snort_alerts.widget.php b/config/snort/snort_alerts.widget.php new file mode 100644 index 00000000..0700ef2a --- /dev/null +++ b/config/snort/snort_alerts.widget.php @@ -0,0 +1,246 @@ +<?php +/* + snort_alerts.widget.php + Copyright (C) 2009 Jim Pingle + mod 24-07-2012 + mod 28-02-2014 by Bill Meeks + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are met: + + 1. Redistributions of source code must retain the above copyright notice, + this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, + INClUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY + AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, + OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. +*/ + +$nocsrf = true; + +require_once("guiconfig.inc"); +require_once("/usr/local/www/widgets/include/widget-snort.inc"); + +global $config, $g; + +/* retrieve snort variables */ +if (!is_array($config['installedpackages']['snortglobal']['rule'])) + $config['installedpackages']['snortglobal']['rule'] = array(); +$a_instance = &$config['installedpackages']['snortglobal']['rule']; + +// Test pfSense version and set different CSS class variables +// depending on version. 2.1 offers enhanced CSS styles. +$pfs_version=substr(trim(file_get_contents("/etc/version")),0,3); +if ($pfs_version > '2.0') { + $alertRowEvenClass = "listMReven"; + $alertRowOddClass = "listMRodd"; + $alertColClass = "listMRr"; +} +else { + $alertRowEvenClass = "listr"; + $alertRowOddClass = "listr"; + $alertColClass = "listr"; +} + +/* check if Snort widget alert display lines value is set */ +$snort_nentries = $config['widgets']['widget_snort_display_lines']; +if (!isset($snort_nentries) || $snort_nentries < 0) + $snort_nentries = 5; + +/* array sorting of the alerts */ +function sksort(&$array, $subkey="id", $sort_ascending=false) { + /* an empty array causes sksort to fail - this test alleviates the error */ + if(empty($array)) + return false; + if (count($array)) { + $temp_array[key($array)] = array_shift($array); + }; + foreach ($array as $key => $val){ + $offset = 0; + $found = false; + foreach ($temp_array as $tmp_key => $tmp_val) { + if (!$found and strtolower($val[$subkey]) > strtolower($tmp_val[$subkey])) { + $temp_array = array_merge((array)array_slice($temp_array,0,$offset), array($key => $val), array_slice($temp_array,$offset)); + $found = true; + }; + $offset++; + }; + if (!$found) $temp_array = array_merge($temp_array, array($key => $val)); + }; + + if ($sort_ascending) { + $array = array_reverse($temp_array); + } else $array = $temp_array; + /* below is the complement for empty array test */ + return true; +}; + +// Called by Ajax to update the "snort-alert-entries" <tbody> table element's contents +if (isset($_GET['getNewAlerts'])) { + $response = ""; + $s_alerts = snort_widget_get_alerts(); + $counter = 0; + foreach ($s_alerts as $a) { + $response .= $a['instanceid'] . " " . $a['dateonly'] . "||" . $a['timeonly'] . "||" . $a['src'] . "||"; + $response .= $a['dst'] . "||" . $a['priority'] . "||" . $a['category'] . "\n"; + $counter++; + if($counter >= $snort_nentries) + break; + } + echo $response; + return; +} + +// See if saving new display line count value +if(isset($_POST['widget_snort_display_lines'])) { + $config['widgets']['widget_snort_display_lines'] = $_POST['widget_snort_display_lines']; + write_config("Saved Snort Alerts Widget Displayed Lines Parameter via Dashboard"); + header("Location: ../../index.php"); +} + +// Read "$snort_nentries" worth of alerts from the top of the alert.log file +// of each configured interface, and then return the most recent '$snort_entries' +// alerts in a sorted array (most recent alert first). +function snort_widget_get_alerts() { + + global $config, $a_instance, $snort_nentries; + $snort_alerts = array(); + /* read log file(s) */ + $counter=0; + foreach ($a_instance as $instanceid => $instance) { + $snort_uuid = $a_instance[$instanceid]['uuid']; + $if_real = get_real_interface($a_instance[$instanceid]['interface']); + + /* make sure alert file exists, then "tail" the last '$snort_nentries' from it */ + if (file_exists("/var/log/snort/snort_{$if_real}{$snort_uuid}/alert")) { + exec("tail -{$snort_nentries} -r /var/log/snort/snort_{$if_real}{$snort_uuid}/alert > /tmp/alert_snort{$snort_uuid}"); + + if (file_exists("/tmp/alert_snort{$snort_uuid}")) { + + /* 0 1 2 3 4 5 6 7 8 9 10 11 12 */ + /* File format: timestamp,generator_id,sig_id,sig_rev,msg,proto,src,srcport,dst,dstport,id,classification,priority */ + $fd = fopen("/tmp/alert_snort{$snort_uuid}", "r"); + while (($fields = fgetcsv($fd, 1000, ',', '"')) !== FALSE) { + if(count($fields) < 13) + continue; + + // Get the Snort interface this alert was received from + $snort_alerts[$counter]['instanceid'] = strtoupper($a_instance[$instanceid]['interface']); + + // "fields[0]" is the complete timestamp in ASCII form. Convert + // to a UNIX timestamp so we can use it for various date and + // time formatting. Also extract the MM/DD/YY component and + // reverse its order to YY/MM/DD for proper sorting. + $fields[0] = trim($fields[0]); // remove trailing space before comma delimiter + $tstamp = strtotime(str_replace("-", " ", $fields[0])); // remove "-" between date and time components + $tmp = substr($fields[0],6,2) . '/' . substr($fields[0],0,2) . '/' . substr($fields[0],3,2); + $snort_alerts[$counter]['timestamp'] = str_replace(substr($fields[0],0,8),$tmp,$fields[0]); + + $snort_alerts[$counter]['timeonly'] = date("H:i:s", $tstamp); + $snort_alerts[$counter]['dateonly'] = date("M d", $tstamp); + // Add square brackets around any any IPv6 address + if (strpos($fields[6], ":") === FALSE) + $snort_alerts[$counter]['src'] = trim($fields[6]); + else + $snort_alerts[$counter]['src'] = "[" . trim($fields[6]) . "]"; + // Add the SRC PORT if not null + if (!empty($fields[7])) + $snort_alerts[$counter]['src'] .= ":" . trim($fields[7]); + // Add square brackets around any any IPv6 address + if (strpos($fields[8], ":") === FALSE) + $snort_alerts[$counter]['dst'] = trim($fields[8]); + else + $snort_alerts[$counter]['dst'] = "[" . trim($fields[8]) . "]"; + // Add the DST PORT if not null + if (!empty($fields[9])) + $snort_alerts[$counter]['dst'] .= ":" . trim($fields[9]); + $snort_alerts[$counter]['priority'] = trim($fields[12]); + $snort_alerts[$counter]['category'] = trim($fields[11]); + $counter++; + }; + fclose($fd); + @unlink("/tmp/alert_snort{$snort_uuid}"); + }; + }; + }; + + /* sort the alerts array */ + if (isset($config['syslog']['reverse'])) { + sksort($snort_alerts, 'timestamp', false); + } else { + sksort($snort_alerts, 'timestamp', true); + }; + + return $snort_alerts; +} +?> + +<input type="hidden" id="snort_alerts-config" name="snort_alerts-config" value="" /> +<div id="snort_alerts-settings" class="widgetconfigdiv" style="display:none;"> + <form action="/widgets/widgets/snort_alerts.widget.php" method="post" name="iformd"> + Enter number of recent alerts to display (default is 5)<br/> + <input type="text" size="5" name="widget_snort_display_lines" class="formfld unknown" id="widget_snort_display_lines" value="<?= $config['widgets']['widget_snort_display_lines'] ?>" /> + <input id="submitd" name="submitd" type="submit" class="formbtn" value="Save" /> + </form> +</div> + +<table id="snort-alert-tbl" width="100%" border="0" cellspacing="0" cellpadding="0" style="table-layout: fixed;"> + <colgroup> + <col style="width: 24%;" /> + <col style="width: 38%;" /> + <col style="width: 38%;" /> + </colgroup> + <thead> + <tr> + <th class="widgetsubheader"><?=gettext("IF/Date");?></th> + <th class="widgetsubheader"><?=gettext("Src/Dst Address");?></th> + <th class="widgetsubheader"><?=gettext("Classification");?></th> + </tr> + </thead> + <tbody id="snort-alert-entries"> + <?php + $snort_alerts = snort_widget_get_alerts(); + $counter=0; + if (is_array($snort_alerts)) { + foreach ($snort_alerts as $alert) { + $alertRowClass = $counter % 2 ? $alertRowEvenClass : $alertRowOddClass; + echo(" <tr class='" . $alertRowClass . "'> + <td class='" . $alertColClass . "'>" . $alert['instanceid'] . " " . $alert['dateonly'] . "<br/>" . $alert['timeonly'] . "</td> + <td class='" . $alertColClass . "' style='overflow: hidden; text-overflow: ellipsis;' nowrap><div style='display:inline;' title='" . $alert['src'] . "'>" . $alert['src'] . "</div><br/><div style='display:inline;' title='" . $alert['dst'] . "'>" . $alert['dst'] . "</div></td> + <td class='" . $alertColClass . "'>Priority: " . $alert['priority'] . " " . $alert['category'] . "</td></tr>"); + $counter++; + if($counter >= $snort_nentries) + break; + } + } + ?> + </tbody> +</table> + +<script type="text/javascript"> +//<![CDATA[ +<!-- needed in the snort_alerts.js file code --> + var snortupdateDelay = 10000; // update every 10 seconds + var snort_nentries = <?=$snort_nentries;?>; // number of alerts to display (5 is default) + var snortWidgetRowEvenClass = "<?=$alertRowEvenClass;?>"; // allows alternating background on 2.1 and higher + var snortWidgetRowOddClass = "<?=$alertRowOddClass;?>"; // allows alternating background on 2.1 and higher + var snortWidgetColClass = "<?=$alertColClass;?>"; // sets column CSS style (different on 2.1 and higher) + +<!-- needed to display the widget settings menu --> + selectIntLink = "snort_alerts-configure"; + textlink = document.getElementById(selectIntLink); + textlink.style.display = "inline"; +//]]> +</script> + diff --git a/config/snort/widget-snort.inc b/config/snort/widget-snort.inc new file mode 100644 index 00000000..3c4d9718 --- /dev/null +++ b/config/snort/widget-snort.inc @@ -0,0 +1,24 @@ +<?php +require_once("config.inc"); + +//set variables for custom title and link +$snort_alerts_title = "Snort Alerts"; +$snort_alerts_title_link = "snort/snort_alerts.php"; + +function widget_snort_uninstall() { + + global $config; + + /* Remove the Snort widget from the Dashboard display list */ + $widgets = $config['widgets']['sequence']; + if (!empty($widgets)) { + $widgetlist = explode(",", $widgets); + foreach ($widgetlist as $key => $widget) { + if (strstr($widget, "snort_alerts-container")) + unset($widgetlist[$key]); + } + $config['widgets']['sequence'] = implode(",", $widgetlist); + write_config(); + } +} +?> |