From 10cab278e653f00bd8ec0ee0e82d30e5c7798042 Mon Sep 17 00:00:00 2001 From: bmeeks8 Date: Wed, 19 Feb 2014 14:08:14 -0500 Subject: BETA version of Suricata 1.4.6 IDS package v0.1 for pfSense. --- config/suricata/README.md | 6 + config/suricata/suricata.inc | 2110 ++++++++++++++++++++ config/suricata/suricata.priv.inc | 46 + config/suricata/suricata.xml | 241 +++ config/suricata/suricata_alerts.php | 578 ++++++ config/suricata/suricata_app_parsers.php | 340 ++++ config/suricata/suricata_barnyard.php | 503 +++++ config/suricata/suricata_check_cron_misc.inc | 109 + .../suricata/suricata_check_for_rule_updates.php | 683 +++++++ config/suricata/suricata_define_vars.php | 290 +++ config/suricata/suricata_download_rules.php | 97 + config/suricata/suricata_download_updates.php | 241 +++ config/suricata/suricata_flow_stream.php | 680 +++++++ config/suricata/suricata_generate_yaml.php | 515 +++++ config/suricata/suricata_global.php | 456 +++++ config/suricata/suricata_import_aliases.php | 272 +++ config/suricata/suricata_interfaces.php | 474 +++++ config/suricata/suricata_interfaces_edit.php | 911 +++++++++ config/suricata/suricata_libhtp_policy_engine.php | 329 +++ config/suricata/suricata_list_view.php | 100 + config/suricata/suricata_log_view.php | 86 + config/suricata/suricata_logs_browser.php | 217 ++ config/suricata/suricata_os_policy_engine.php | 275 +++ config/suricata/suricata_post_install.php | 139 ++ config/suricata/suricata_rules.php | 790 ++++++++ config/suricata/suricata_rules_edit.php | 154 ++ config/suricata/suricata_rules_flowbits.php | 306 +++ config/suricata/suricata_rulesets.php | 596 ++++++ config/suricata/suricata_select_alias.php | 226 +++ config/suricata/suricata_suppress.php | 172 ++ config/suricata/suricata_suppress_edit.php | 213 ++ config/suricata/suricata_uninstall.php | 133 ++ config/suricata/suricata_yaml_template.inc | 302 +++ 33 files changed, 12590 insertions(+) create mode 100644 config/suricata/README.md create mode 100644 config/suricata/suricata.inc create mode 100644 config/suricata/suricata.priv.inc create mode 100644 config/suricata/suricata.xml create mode 100644 config/suricata/suricata_alerts.php create mode 100644 config/suricata/suricata_app_parsers.php create mode 100644 config/suricata/suricata_barnyard.php create mode 100644 config/suricata/suricata_check_cron_misc.inc create mode 100644 config/suricata/suricata_check_for_rule_updates.php create mode 100644 config/suricata/suricata_define_vars.php create mode 100644 config/suricata/suricata_download_rules.php create mode 100644 config/suricata/suricata_download_updates.php create mode 100644 config/suricata/suricata_flow_stream.php create mode 100644 config/suricata/suricata_generate_yaml.php create mode 100644 config/suricata/suricata_global.php create mode 100644 config/suricata/suricata_import_aliases.php create mode 100644 config/suricata/suricata_interfaces.php create mode 100644 config/suricata/suricata_interfaces_edit.php create mode 100644 config/suricata/suricata_libhtp_policy_engine.php create mode 100644 config/suricata/suricata_list_view.php create mode 100644 config/suricata/suricata_log_view.php create mode 100644 config/suricata/suricata_logs_browser.php create mode 100644 config/suricata/suricata_os_policy_engine.php create mode 100644 config/suricata/suricata_post_install.php create mode 100644 config/suricata/suricata_rules.php create mode 100644 config/suricata/suricata_rules_edit.php create mode 100644 config/suricata/suricata_rules_flowbits.php create mode 100644 config/suricata/suricata_rulesets.php create mode 100644 config/suricata/suricata_select_alias.php create mode 100644 config/suricata/suricata_suppress.php create mode 100644 config/suricata/suricata_suppress_edit.php create mode 100644 config/suricata/suricata_uninstall.php create mode 100644 config/suricata/suricata_yaml_template.inc diff --git a/config/suricata/README.md b/config/suricata/README.md new file mode 100644 index 00000000..2ec1d9a3 --- /dev/null +++ b/config/suricata/README.md @@ -0,0 +1,6 @@ +pfsense-suricata +================ + +Suricata package port for pfSense + +This is a port of the Suricata package for pfSense 2.1 and higher. It is currently under development and is still considered BETA software. Use on production systems is not recommended. diff --git a/config/suricata/suricata.inc b/config/suricata/suricata.inc new file mode 100644 index 00000000..95b95711 --- /dev/null +++ b/config/suricata/suricata.inc @@ -0,0 +1,2110 @@ +&1 &"); + } +} + +function suricata_barnyard_reload_config($suricatacfg, $signal="HUP") { + + /**************************************************************/ + /* This function sends the passed SIGNAL to the Barnyard2 */ + /* instance on the passed interface to cause Barnyard to */ + /* reload and parse the running configuration without */ + /* impacting packet processing. It also executes the reload */ + /* as a background process and returns control immediately */ + /* to the caller. */ + /* */ + /* $signal = HUP (default) parses and reloads config. */ + /**************************************************************/ + global $config, $g; + + $suricatadir = SURICATADIR; + $suricata_uuid = $suricatacfg['uuid']; + $if_real = suricata_get_real_interface($suricatacfg['interface']); + + /******************************************************/ + /* Only send the SIGHUP if Barnyard2 is running and */ + /* we can find a valid PID for the process. */ + /******************************************************/ + if (file_exists("{$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid") && isvalidpid("{$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid")) { + log_error("[Suricata] Barnyard2 CONFIG RELOAD initiated for {$suricatacfg['descr']} ({$if_real})..."); + exec("/bin/pkill -{$signal} -F {$g['varrun_path']}/barnyard2_{$if_real}{$suricata_uuid}.pid 2>&1 &"); + } +} + +function suricata_get_friendly_interface($interface) { + + if (function_exists('convert_friendly_interface_to_friendly_descr')) + $iface = convert_friendly_interface_to_friendly_descr($interface); + else { + if (!$interface || ($interface == "wan")) + $iface = "WAN"; + else if(strtolower($interface) == "lan") + $iface = "LAN"; + else if(strtolower($interface) == "pppoe") + $iface = "PPPoE"; + else if(strtolower($interface) == "pptp") + $iface = "PPTP"; + else + $iface = strtoupper($interface); + } + + return $iface; +} + +function suricata_get_real_interface($interface) { + global $config; + + $lc_interface = strtolower($interface); + if (function_exists('get_real_interface')) + return get_real_interface($lc_interface); + else { + if ($lc_interface == "lan") { + if ($config['inerfaces']['lan']) + return $config['interfaces']['lan']['if']; + return $interface; + } + if ($lc_interface == "wan") + return $config['interfaces']['wan']['if']; + $ifdescrs = array(); + for ($j = 1; isset($config['interfaces']['opt' . $j]); $j++) { + $ifname = "opt{$j}"; + if(strtolower($ifname) == $lc_interface) + return $config['interfaces'][$ifname]['if']; + if(isset($config['interfaces'][$ifname]['descr']) && (strtolower($config['interfaces'][$ifname]['descr']) == $lc_interface)) + return $config['interfaces'][$ifname]['if']; + } + } + + return $interface; +} + +function suricata_get_blocked_ips() { + + return array(); + +} + +/* func builds custom white lists */ +function suricata_find_list($find_name, $type = 'whitelist') { + global $config; + + $suricataglob = $config['installedpackages']['suricata']; + if (!is_array($suricataglob[$type])) + return ""; + if (!is_array($suricataglob[$type]['item'])) + return ""; + + foreach ($suricataglob[$type]['item'] as $value) { + if ($value['name'] == $find_name) + return $value; + } + + return array(); +} + +function suricata_build_list($suricatacfg, $listname = "", $whitelist = false) { + + /***********************************************************/ + /* The default is to build a HOME_NET variable unless */ + /* '$whitelist' is set to 'true' when calling. */ + /***********************************************************/ + + global $config, $g, $aliastable, $filterdns; + $home_net = array(); + + if ($listname == 'default' || empty($listname)) { + $localnet = 'yes'; $wanip = 'yes'; $wangw = 'yes'; $wandns = 'yes'; $vips = 'yes'; $vpns = 'yes'; + } else { + $list = suricata_find_list($listname); + if (empty($list)) + return $list; + $localnet = $list['localnets']; + $wanip = $list['wanips']; + $wangw = $list['wangateips']; + $wandns = $list['wandnsips']; + $vips = $list['vips']; + $vpns = $list['vpnips']; + if (!empty($list['address']) && is_alias($list['address'])) + $home_net = explode(" ", trim(filter_expand_alias($list['address']))); + } + + // Always add loopback to HOME_NET and whitelist (ftphelper) + if (!in_array("127.0.0.1", $home_net)) + $home_net[] = "127.0.0.1"; + + /********************************************************************/ + /* Always put the interface running Suricata in HOME_NET and */ + /* whitelist unless it's the WAN. WAN options are handled further */ + /* down. If the user specifically chose not to include LOCAL_NETS */ + /* in the WHITELIST, then do not include the Suricata interface */ + /* subnet in the WHITELIST. We do include the actual LAN interface */ + /* IP for Suricata, though, to prevent locking out the firewall. */ + /********************************************************************/ + $suricataip = get_interface_ip($suricatacfg['interface']); + if (!$whitelist || $localnet == 'yes' || empty($localnet)) { + if (is_ipaddr($suricataip)) { + if ($suricatacfg['interface'] <> "wan") { + $sn = get_interface_subnet($suricatacfg['interface']); + $ip = gen_subnet($suricataip, $sn) . "/{$sn}"; + if (!in_array($ip, $home_net)) + $home_net[] = $ip; + } + } + } + else { + if (is_ipaddr($suricataip)) { + if (!in_array($suricataip, $home_net)) + $home_net[] = $suricataip; + } + } + + $suricataip = get_interface_ipv6($suricatacfg['interface']); + if (!$whitelist || $localnet == 'yes' || empty($localnet)) { + if (is_ipaddrv6($suricataip)) { + if ($suricatacfg['interface'] <> "wan") { + $sn = get_interface_subnetv6($suricatacfg['interface']); + $ip = gen_subnetv6($suricataip, $sn). "/{$sn}"; + if (!in_array($ip, $home_net)) + $home_net[] = $ip; + } + } + } + else { + if (is_ipaddrv6($suricataip)) { + if (!in_array($suricataip, $home_net)) + $home_net[] = $suricataip; + } + } + + if (!$whitelist || $localnet == 'yes' || empty($localnet)) { + /*************************************************************************/ + /* Iterate through the interface list and write out whitelist items and */ + /* also compile a HOME_NET list of all the local interfaces for suricata. */ + /* Skip the WAN interface as we do not typically want that whole subnet */ + /* whitelisted (just the i/f IP itself which was handled earlier). */ + /*************************************************************************/ + $int_array = get_configured_interface_list(); + foreach ($int_array as $int) { + if ($int == "wan") + continue; + $subnet = get_interface_ip($int); + if (is_ipaddr($subnet)) { + $sn = get_interface_subnet($int); + $ip = gen_subnet($subnet, $sn) . "/{$sn}"; + if (!in_array($ip, $home_net)) + $home_net[] = $ip; + } + if ($int == "wan") + continue; + $subnet = get_interface_ipv6($int); + if (is_ipaddrv6($subnet)) { + $sn = get_interface_subnetv6($int); + $ip = gen_subnetv6($subnet, $sn). "/{$sn}"; + if (!in_array($ip, $home_net)) + $home_net[] = $ip; + } + } + } + + if ($wanip == 'yes') { + $ip = get_interface_ip("wan"); + if (is_ipaddr($ip)) { + if (!in_array($ip, $home_net)) + $home_net[] = $ip; + } + $ip = get_interface_ipv6("wan"); + if (is_ipaddrv6($ip)) { + if (!in_array($ip, $home_net)) + $home_net[] = $ip; + } + } + + if ($wangw == 'yes') { + // Grab the default gateway if set + $default_gw = exec("/sbin/route -n get default |grep 'gateway:' | /usr/bin/awk '{ print $2 }'"); + if (is_ipaddr($default_gw) && !in_array($default_gw, $home_net)) + $home_net[] = $default_gw; + if (is_ipaddrv6($default_gw) && !in_array($default_gw, $home_net)) + $home_net[] = $default_gw; + + // Get any other interface gateway and put in $HOME_NET if not there already + $gw = get_interface_gateway($suricatacfg['interface']); + if (is_ipaddr($gw) && !in_array($gw, $home_net)) + $home_net[] = $gw; + $gw = get_interface_gateway_v6($suricatacfg['interface']); + if (is_ipaddrv6($gw) && !in_array($gw, $home_net)) + $home_net[] = $gw; + } + + if ($wandns == 'yes') { + // Add DNS server for WAN interface to whitelist + $dns_servers = get_dns_servers(); + foreach ($dns_servers as $dns) { + if ($dns && !in_array($dns, $home_net)) + $home_net[] = $dns; + } + } + + if($vips == 'yes') { + // iterate all vips and add to whitelist + if (is_array($config['virtualip']) && is_array($config['virtualip']['vip'])) { + foreach($config['virtualip']['vip'] as $vip) { + if ($vip['subnet'] && $vip['mode'] != 'proxyarp') { + if (!in_array("{$vip['subnet']}/{$vip['subnet_bits']}", $home_net)) + $home_net[] = "{$vip['subnet']}/{$vip['subnet_bits']}"; + } + } + } + } + + // grab a list of vpns and whitelist if user desires + if ($vpns == 'yes') { + $vpns_list = filter_get_vpns_list(); + if (!empty($vpns_list)) { + // Convert the returned space-delimited string to an array + // and then add each VPN address to our HOME_NET array. + $vpns = explode(" ", $vpns_list); + foreach ($vpns as $vpn) + $home_net[] = trim($vpn); + unset($vpns, $vpns_list); + } + } + + $valresult = array(); + foreach ($home_net as $vald) { + if (empty($vald)) + continue; + $vald = trim($vald); + if (empty($valresult[$vald])) + $valresult[$vald] = $vald; + } + + // Release memory no longer required + unset($home_net); + + // Sort the list and return it + natsort($valresult); + return $valresult; +} + +function suricata_rules_up_install_cron($should_install) { + global $config, $g; + + if(!$config['cron']['item']) + $config['cron']['item'] = array(); + + $x=0; + $is_installed = false; + foreach($config['cron']['item'] as $item) { + if (strstr($item['command'], "suricata_check_for_rule_updates.php")) { + $is_installed = true; + break; + } + $x++; + } + $suricata_rules_up_info_ck = $config['installedpackages']['suricata']['config'][0]['autoruleupdate']; + + // See if a customized start time has been set for rule file updates + if (!empty($config['installedpackages']['suricata']['config'][0]['autoruleupdatetime'])) + $suricata_rules_upd_time = $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime']; + else + $suricata_rules_upd_time = "00:03"; + + if ($suricata_rules_up_info_ck == "6h_up") { + $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2)); + $hour = intval(substr($suricata_rules_upd_time, 0, 2)); + $suricata_rules_up_hr = strval($hour); + for ($i=0; $i<3; $i++) { + $hour += 6; + if ($hour > 24) + $hour -= 24; + $suricata_rules_up_hr .= "," . strval($hour); + } + $suricata_rules_up_mday = "*"; + $suricata_rules_up_month = "*"; + $suricata_rules_up_wday = "*"; + } + if ($suricata_rules_up_info_ck == "12h_up") { + $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2)); + $hour = intval(substr($suricata_rules_upd_time, 0, 2)); + $suricata_rules_up_hr = strval($hour) . ","; + $hour += 12; + if ($hour > 24) + $hour -= 24; + $suricata_rules_up_hr .= strval($hour); + $suricata_rules_up_mday = "*"; + $suricata_rules_up_month = "*"; + $suricata_rules_up_wday = "*"; + } + if ($suricata_rules_up_info_ck == "1d_up") { + $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2)); + $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2)); + $suricata_rules_up_mday = "*/1"; + $suricata_rules_up_month = "*"; + $suricata_rules_up_wday = "*"; + } + if ($suricata_rules_up_info_ck == "4d_up") { + $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2)); + $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2)); + $suricata_rules_up_mday = "*/4"; + $suricata_rules_up_month = "*"; + $suricata_rules_up_wday = "*"; + } + if ($suricata_rules_up_info_ck == "7d_up") { + $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2)); + $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2)); + $suricata_rules_up_mday = "*/7"; + $suricata_rules_up_month = "*"; + $suricata_rules_up_wday = "*"; + } + if ($suricata_rules_up_info_ck == "28d_up") { + $suricata_rules_up_min = intval(substr($suricata_rules_upd_time, -2)); + $suricata_rules_up_hr = intval(substr($suricata_rules_upd_time, 0, 2)); + $suricata_rules_up_mday = "*/28"; + $suricata_rules_up_month = "*"; + $suricata_rules_up_wday = "*"; + } + switch($should_install) { + case true: + $cron_item = array(); + $cron_item['minute'] = $suricata_rules_up_min; + $cron_item['hour'] = $suricata_rules_up_hr; + $cron_item['mday'] = $suricata_rules_up_mday; + $cron_item['month'] = $suricata_rules_up_month; + $cron_item['wday'] = $suricata_rules_up_wday; + $cron_item['who'] = "root"; + $cron_item['command'] = "/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/www/suricata/suricata_check_for_rule_updates.php"; + + // Add cron job if not already installed, else just update the existing one + if (!$is_installed) + $config['cron']['item'][] = $cron_item; + elseif ($is_installed) + $config['cron']['item'][$x] = $cron_item; + break; + case false: + if($is_installed == true) + unset($config['cron']['item'][$x]); + break; + } +} + +function suricata_loglimit_install_cron($should_install) { + global $config, $g; + + if (!is_array($config['cron']['item'])) + $config['cron']['item'] = array(); + + $x=0; + $is_installed = false; + foreach($config['cron']['item'] as $item) { + if (strstr($item['command'], 'suricata_check_cron_misc.inc')) { + $is_installed = true; + break; + } + $x++; + } + + switch($should_install) { + case true: + if(!$is_installed) { + $cron_item = array(); + $cron_item['minute'] = "*/5"; + $cron_item['hour'] = "*"; + $cron_item['mday'] = "*"; + $cron_item['month'] = "*"; + $cron_item['wday'] = "*"; + $cron_item['who'] = "root"; + $cron_item['command'] = "/usr/bin/nice -n20 /usr/local/bin/php -f /usr/local/pkg/suricata/suricata_check_cron_misc.inc"; + $config['cron']['item'][] = $cron_item; + } + break; + case false: + if($is_installed == true) + unset($config['cron']['item'][$x]); + break; + } +} + +function sync_suricata_package_config() { + global $config, $g; + + $suricatadir = SURICATADIR; + $rcdir = RCFILEPREFIX; + + conf_mount_rw(); + + // Do not start config build if there are no Suricata-configured interfaces + if (!is_array($config['installedpackages']['suricata']) || !is_array($config['installedpackages']['suricata']['rule'])) { + @unlink("{$rcdir}/suricata.sh"); + conf_mount_ro(); + return; + } + + $suricataconf = $config['installedpackages']['suricata']['rule']; + foreach ($suricataconf as $value) { + $if_real = suricata_get_real_interface($value['interface']); + + // create a suricata.yaml file for interface + suricata_generate_yaml($value); + + // create barnyard2.conf file for interface + if ($value['barnyard_enable'] == 'on') + suricata_generate_barnyard2_conf($value, $if_real); + } + + // create suricata bootup file suricata.sh + suricata_create_rc(); + + $suricataglob = $config['installedpackages']['suricata']['config'][0]; + + suricata_loglimit_install_cron($suricataglob['suricataloglimit'] == 'on' ? true : false); + + // set the suricata block hosts time IMPORTANT +// suricata_rm_blocked_install_cron($suricataglob['rm_blocked'] != "never_b" ? true : false); + + // set the suricata rules update time + suricata_rules_up_install_cron($suricataglob['autoruleupdate'] != "never_up" ? true : false); + + write_config(); + configure_cron(); + + // Do not attempt package sync if reinstalling package or booting +// if (!$g['suricata_postinstall'] && !$g['booting']) +// suricata_sync_on_changes(); + + conf_mount_ro(); +} + +function suricata_load_suppress_sigs($suricatacfg, $track_by=false) { + + global $config; + + /**********************************************************/ + /* This function loads the GEN_ID and SIG_ID for all the */ + /* suppressed alert entries from the Suppression List of */ + /* the passed Suricata interface. The results are */ + /* returned in an array with GEN_ID and SIG_ID as the */ + /* primary keys. Any "track by_src" or "track by_dst" */ + /* entries in the Suppression List are tacked on as */ + /* additional keys in the array along with the IP address */ + /* in either IPv4 or IPv6 format when $track_by is passed */ + /* as true. */ + /* */ + /* Sample returned array: */ + /* $suppress[1][2069] = "suppress" */ + /* $suppress[1][2070]['by_src']['10.1.1.5'] = "suppress" */ + /* $suppress[1][2070]['by_dst']['10.1.1.6'] = "suppress" */ + /* */ + /**********************************************************/ + + $suppress = array(); + + if (!is_array($config['installedpackages']['suricata'])) + return; + if (!is_array($config['installedpackages']['suricata']['suppress'])) + return; + if (!is_array($config['installedpackages']['suricata']['suppress']['item'])) + return; + $a_suppress = $config['installedpackages']['suricata']['suppress']['item']; + + foreach ($a_suppress as $a_id => $alist) { + if ($alist['name'] == $suricatacfg['suppresslistname']) { + if (!empty($alist['suppresspassthru'])) { + $tmplist = str_replace("\r", "", base64_decode($alist['suppresspassthru'])); + $tmp = explode("\n", $tmplist); + foreach ($tmp as $line) { + // Skip any blank lines + if (trim($line, " \n") == "") + continue; + // Skip any comment lines + if (preg_match('/^\s*#/', $line)) + continue; + /* See if entry suppresses GID:SID for all hosts */ + if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+)\s*$/i', $line, $matches)) { + $genid = $matches[1]; + $sigid = $matches[2]; + if (!empty($genid) && !empty($sigid)) { + if (!is_array($suppress[$genid])) + $suppress[$genid] = array(); + if (!is_array($suppress[$genid][$sigid])) + $suppress[$genid][$sigid] = array(); + $suppress[$genid][$sigid] = "suppress"; + } + } + + /* Get "track by IP" entries if requested */ + if ($track_by) { + /* See if entry suppresses only by SRC or DST IPv4 address */ + if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+),\s*track\s*(by_src|by_dst),\s*ip\s*(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\s*$/i', $line, $matches)) { + $genid = $matches[1]; + $sigid = $matches[2]; + $whichip = trim($matches[3]); + $ip = $matches[4]; + if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip)) { + if (!is_array($suppress[$genid])) + $suppress[$genid] = array(); + if (!is_array($suppress[$genid][$sigid])) + $suppress[$genid][$sigid] = array(); + if (!is_array($suppress[$genid][$sigid][$whichip])) + $suppress[$genid][$sigid][$whichip] = array(); + if (!is_array($suppress[$genid][$sigid][$whichip][$ip])) + $suppress[$genid][$sigid][$whichip][$ip] = array(); + $suppress[$genid][$sigid][$whichip][$ip] = "suppress"; + } + } + /* See if entry suppresses only by SRC or DST IPv6 address */ + if (preg_match('/\s*suppress\s*gen_id\b\s*(\d+),\s*sig_id\b\s*(\d+),\s*track\s*(by_src|by_dst),\s*ip\s*([0-9a-f\.:]+)\s*$/i', $line, $matches)) { + $genid = $matches[1]; + $sigid = $matches[2]; + $whichip = trim($matches[3]); + $ip = trim($matches[4]); + if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip)) { + if (!is_array($suppress[$genid])) + $suppress[$genid] = array(); + if (!is_array($suppress[$genid][$sigid])) + $suppress[$genid][$sigid] = array(); + if (!is_array($suppress[$genid][$sigid][$whichip])) + $suppress[$genid][$sigid][$whichip] = array(); + if (!is_array($suppress[$genid][$sigid][$whichip][$ip])) + $suppress[$genid][$sigid][$whichip][$ip] = array(); + $suppress[$genid][$sigid][$whichip][$ip] = "suppress"; + } + } + } + } + unset($tmp); + } + break; + } + } + unset($alist); + return $suppress; +} + +function suricata_post_delete_logs($suricata_uuid = 0) { + + /***********************************************/ + /* This function cleans up related log files */ + /* for the passed instance. These include */ + /* Barnyard2 unified2 logs and pcap logs. */ + /***********************************************/ + + global $config, $g; + + // do nothing if no Suricata interfaces active + if (!is_array($config['installedpackages']['suricata']['rule'])) + return; + + foreach ($config['installedpackages']['suricata']['rule'] as $value) { + if ($value['uuid'] != $suricata_uuid) + continue; + $if_real = suricata_get_real_interface($value['interface']); + $suricata_log_dir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}"; + + if ($if_real != '') { + /* Clean-up Barnyard2 files if any exist */ + $filelist = glob("{$suricata_log_dir}/unified2.alert.*"); + // Keep most recent file + unset($filelist[count($filelist) - 1]); + foreach ($filelist as $file) + @unlink($file); + + /* Clean-up Barnyard2 archived files if any exist */ + $filelist = glob("{$suricata_log_dir}/barnyard2/archive/unified2.alert.*"); + foreach ($filelist as $file) + @unlink($file); + + /* Clean-up packet capture files if any exist */ + $filelist = glob("{$suricata_log_dir}/log.pcap.*"); + // Keep most recent file + unset($filelist[count($filelist) - 1]); + foreach ($filelist as $file) + @unlink($file); + } + } +} + +/* This returns size of passed directory or file in 1024-byte blocks */ +function suricata_Getdirsize($node) { + if(!is_readable($node)) + return false; + + $blah = exec( "/usr/bin/du -kdc $node" ); + return substr( $blah, 0, strpos($blah, 9) ); +} + +function suricata_build_sid_msg_map($rules_path, $sid_file) { + + /*************************************************************/ + /* This function reads all the rules file in the passed */ + /* $rules_path variable and produces a properly formatted */ + /* sid-msg.map file for use by Suricata and/or barnyard2. */ + /*************************************************************/ + + $sidMap = array(); + $rule_files = array(); + + // First check if we were passed a directory, a single file + // or an array of filenames to read. Set our $rule_files + // variable accordingly. If we can't figure it out, return + // and don't write a sid_msg_map file. + if (is_string($rules_path)) { + if (is_dir($rules_path)) + $rule_files = glob($rules_path . "*.rules"); + elseif (is_file($rules_path)) + $rule_files = (array)$rules_path; + } + elseif (is_array($rules_path)) + $rule_files = $rules_path; + else + return; + + // Read the rule files into an array, then iterate the list + foreach ($rule_files as $file) { + + // Don't process files with "deleted" in the filename + if (stristr($file, "deleted")) + continue; + + // Read the file into an array, skipping missing files. + if (!file_exists($file)) + continue; + + $rules_array = file($file, FILE_SKIP_EMPTY_LINES); + $record = ""; + $b_Multiline = false; + + // Read and process each line from the rules in the current file + foreach ($rules_array as $rule) { + + // Skip any non-rule lines unless we're in multiline mode. + if (!preg_match('/^\s*#*\s*(alert|drop|pass)/i', $rule) && !$b_Multiline) + continue; + + // Test for a multi-line rule, and reassemble the + // pieces back into a single line. + if (preg_match('/\\\\s*[\n]$/m', $rule)) { + $rule = substr($rule, 0, strrpos($rule, '\\')); + $record .= $rule; + $b_Multiline = true; + continue; + } + // If the last segment of a multiline rule, then + // append it onto the previous parts to form a + // single-line rule for further processing below. + elseif (!preg_match('/\\\\s*[\n]$/m', $rule) && $b_Multiline) { + $record .= $rule; + $rule = $record; + } + $b_Multiline = false; + $record = ""; + + // Parse the rule to find sid and any references. + $sid = ''; + $msg = ''; + $matches = ''; + $sidEntry = ''; + if (preg_match('/\bmsg\s*:\s*"(.+?)"\s*;/i', $rule, $matches)) + $msg = trim($matches[1]); + if (preg_match('/\bsid\s*:\s*(\d+)\s*;/i', $rule, $matches)) + $sid = trim($matches[1]); + if (!empty($sid) && !empty($msg)) { + $sidEntry = $sid . ' || ' . $msg; + preg_match_all('/\breference\s*:\s*([^\;]+)/i', $rule, $matches); + foreach ($matches[1] as $ref) + $sidEntry .= " || " . trim($ref); + $sidEntry .= "\n"; + if (!is_array($sidMap[$sid])) + $sidMap[$sid] = array(); + $sidMap[$sid] = $sidEntry; + } + } + } + // Sort the generated sid-msg map by sid + ksort($sidMap); + + // Now print the result to the supplied file + @file_put_contents($sid_file, array_values($sidMap)); +} + +function suricata_merge_reference_configs($cfg_in, $cfg_out) { + + /***********************************************************/ + /* This function takes a list of "reference.config" files */ + /* in the $cfg_in array and merges them into a single */ + /* file specified by $cfg_out. The merging is done so */ + /* no duplication of lines occurs in the output file. */ + /***********************************************************/ + + $outMap = array(); + foreach ($cfg_in as $file) { + if (!file_exists($file)) + continue; + $in = file($file, FILE_SKIP_EMPTY_LINES); + foreach ($in as $line) { + /* Skip comment lines */ + if (preg_match('/^\s*#/', $line)) + continue; + if (preg_match('/(\:)\s*(\w+)\s*(.*)/', $line, $matches)) { + if (!empty($matches[2]) && !empty($matches[3])) { + $matches[2] = trim($matches[2]); + if (!array_key_exists($matches[2], $outMap)) { + if (!is_array($outMap[$matches[2]])) + $outMap[$matches[2]] = array(); + $outMap[$matches[2]] = trim($matches[3]); + } + } + } + } + } + // Sort the new reference map. + uksort($outMap,'strnatcasecmp'); + + // Do NOT write an empty references.config file, just + // exit instead. + if (empty($outMap)) + return false; + + // Format and write it to the supplied output file. + $format = "config reference: %-12s %s\n"; + foreach ($outMap as $key=>$value) + $outMap[$key] = sprintf($format, $key, $value); + @file_put_contents($cfg_out, array_values($outMap)); + return true; +} + +function suricata_merge_classification_configs($cfg_in, $cfg_out) { + + /************************************************************/ + /* This function takes a list of "classification.config" */ + /* files in the $cfg_in array and merges them into a */ + /* single file specified by $cfg_out. The merging is done */ + /* so no duplication of lines occurs in the output file. */ + /************************************************************/ + + $outMap = array(); + foreach ($cfg_in as $file) { + if (!file_exists($file)) + continue; + $in = file($file, FILE_SKIP_EMPTY_LINES); + foreach ($in as $line) { + if (preg_match('/(.*:)(\s*.*),(.*),(.*)/', $line, $matches)) { + /* Skip comment lines */ + if (preg_match('/^\s*#/', $line)) + continue; + if (!empty($matches[2]) && !empty($matches[3]) && !empty($matches[4])) { + $matches[2] = trim($matches[2]); + if (!array_key_exists($matches[2], $outMap)) { + if (!is_array($outMap[$matches[2]])) + $outMap[$matches[2]] = array(); + $outMap[$matches[2]] = trim($matches[3]) . "," . trim($matches[4]); + } + } + } + } + } + // Sort the new classification map. + uksort($outMap,'strnatcasecmp'); + + // Do NOT write an empty classification.config file, just + // exit instead. + if (empty($outMap)) + return false; + + // Format and write it to the supplied output file. + $format = "config classification: %s,%s\n"; + foreach ($outMap as $key=>$value) + $outMap[$key] = sprintf($format, $key, $value); + @file_put_contents($cfg_out, array_values($outMap)); + return true; +} + +function suricata_load_rules_map($rules_path) { + + /***************************************************************/ + /* This function loads and returns an array with all the rules */ + /* found in the *.rules files in the passed rules path. */ + /* */ + /* $rules_path can be: */ + /* a directory (assumed to contain *.rules files) */ + /* a filename (identifying a specific *.rules file) */ + /* an array of filenames (identifying *.rules files) */ + /***************************************************************/ + + $map_ref = array(); + $rule_files = array(); + + if (empty($rules_path)) + return $map_ref; + + /*************************************************************** + * Read all the rules into the map array. + * The structure of the map array is: + * + * map[gid][sid]['rule']['category']['disabled']['flowbits'] + * + * where: + * gid = Generator ID from rule, or 1 if general text + * rule + * sid = Signature ID from rule + * rule = Complete rule text + * category = File name of file containing the rule + * action = alert, drop, reject or pass + * disabled = 1 if rule is disabled (commented out), 0 if + * rule is enabled + * flowbits = Array of applicable flowbits if rule contains + * flowbits options + ***************************************************************/ + + // First check if we were passed a directory, a single file + // or an array of filenames to read. Set our $rule_files + // variable accordingly. If we can't figure it out, return + // an empty rules map array. + if (is_string($rules_path)) { + if (is_dir($rules_path)) + $rule_files = glob($rules_path . "*.rules"); + elseif (is_file($rules_path)) + $rule_files = (array)$rules_path; + } + elseif (is_array($rules_path)) + $rule_files = $rules_path; + else + return $map_ref; + + // Read the rule files into an array, then iterate the list + // to process the rules from the files one-by-one. + foreach ($rule_files as $file) { + + // Don't process files with "deleted" in the filename. + if (stristr($file, "deleted")) + continue; + + // Read the file contents into an array, skipping + // missing files. + if (!file_exists($file)) + continue; + + $rules_array = file($file, FILE_SKIP_EMPTY_LINES); + $record = ""; + $b_Multiline = false; + + // Read and process each line from the rules in the + // current file into an array. + foreach ($rules_array as $rule) { + + // Skip any lines that may be just spaces. + if (trim($rule, " \n") == "") + continue; + + // Skip any non-rule lines unless we're in + // multiline mode. + if (!preg_match('/^\s*#*\s*(alert|drop|pass|reject)/i', $rule) && !$b_Multiline) + continue; + + // Test for a multi-line rule; loop and reassemble + // the pieces back into a single line. + if (preg_match('/\\\\s*[\n]$/m', $rule)) { + $rule = substr($rule, 0, strrpos($rule, '\\')); + $record .= $rule; + $b_Multiline = true; + continue; + } + // If the last segment of a multiline rule, then + // append it onto the previous parts to form a + // single-line rule for further processing below. + elseif (!preg_match('/\\\\s*[\n]$/m', $rule) && $b_Multiline) { + $record .= $rule; + $rule = $record; + } + + // We have an actual single-line rule, or else a + // re-assembled multiline rule that is now a + // single-line rule, so store it in our rules map. + + // Get and test the SID. If we don't find one, + // ignore and skip this rule as it is invalid. + $sid = suricata_get_sid($rule); + if (empty($sid)) { + $b_Multiline = false; + $record = ""; + continue; + } + + $gid = suricata_get_gid($rule); + if (!is_array($map_ref[$gid])) + $map_ref[$gid] = array(); + if (!is_array($map_ref[$gid][$sid])) + $map_ref[$gid][$sid] = array(); + $map_ref[$gid][$sid]['rule'] = $rule; + $map_ref[$gid][$sid]['category'] = basename($file, ".rules"); + + // Grab the rule action + $matches = array(); + if (preg_match('/^\s*#*\s*(alert|drop|pass|reject)/i', $rule, $matches)) + $map_ref[$gid][$sid]['action'] = $matches[1]; + else + $map_ref[$gid][$sid]['action'] = ""; + + // Determine if default state is "disabled" + if (preg_match('/^\s*\#+/', $rule)) + $map_ref[$gid][$sid]['disabled'] = 1; + else + $map_ref[$gid][$sid]['disabled'] = 0; + + // Grab any associated flowbits from the rule. + $map_ref[$gid][$sid]['flowbits'] = suricata_get_flowbits($rule); + + // Reset our local flag and record variables + // for the next rule in the set. + $b_Multiline = false; + $record = ""; + } + + // Zero out our processing array and get the next file. + unset($rules_array); + } + return $map_ref; +} + +function suricata_get_gid($rule) { + + /****************************************************************/ + /* If a gid is defined, then return it, else default to "1" for */ + /* general text rules match. */ + /****************************************************************/ + + if (preg_match('/\bgid\s*:\s*(\d+)\s*;/i', $rule, $matches)) + return trim($matches[1]); + else + return "1"; +} + +function suricata_get_sid($rule) { + + /***************************************************************/ + /* If a sid is defined, then return it, else default to an */ + /* empty value. */ + /***************************************************************/ + + if (preg_match('/\bsid\s*:\s*(\d+)\s*;/i', $rule, $matches)) + return trim($matches[1]); + else + return ""; +} + +function suricata_get_msg($rule) { + + /**************************************************************/ + /* Return the MSG section of the passed rule as a string. */ + /**************************************************************/ + + $msg = ""; + if (preg_match('/\bmsg\s*:\s*"(.+?)"\s*;/i', $rule, $matches)) + $msg = trim($matches[1]); + return $msg; +} + +function suricata_get_flowbits($rule) { + + /*************************************************************/ + /* This will pull out "flowbits:" options from the rule text */ + /* and return them in an array (minus the "flowbits:" part). */ + /*************************************************************/ + + $flowbits = array(); + + // Grab any "flowbits:set, setx, unset, isset or toggle" options first. + // Examine flowbits targets for logical operators to capture all targets. + if (preg_match_all('/flowbits\b\s*:\s*(set|setx|unset|toggle|isset|isnotset)\s*,([^;]+)/i', $rule, $matches)) { + $i = -1; + while (++$i < count($matches[1])) { + $action = trim($matches[1][$i]); + $target = preg_split('/[&|]/', $matches[2][$i]); + foreach ($target as $t) + $flowbits[] = "{$action}," . trim($t); + } + } + + // Include the "flowbits:noalert or reset" options, if present. + if (preg_match_all('/flowbits\b\s*:\s*(noalert|reset)\b/i', $rule, $matches)) { + $i = -1; + while (++$i < count($matches[1])) { + $flowbits[] = trim($matches[1][$i]); + } + } + + return $flowbits; +} + +function suricata_get_checked_flowbits($rules_map) { + + /*************************************************************/ + /* This function checks all the currently enabled rules to */ + /* find any checked flowbits, and returns the checked */ + /* flowbit names in an array. */ + /*************************************************************/ + + $checked_flowbits = array(); + foreach ($rules_map as $rulem) { + if (!is_array($rulem)) + continue; + foreach ($rulem as $rulem2) { + if (!is_array($rulem2)) + continue; + if ($rulem2['disabled'] == 1) + continue; + if (empty($rulem2['flowbits'])) + continue; + if (!is_array($rulem2['flowbits'])) + continue; + foreach ($rulem2['flowbits'] as $flowbit) { + if (empty($flowbit)) + continue; + // If no comma in flowbits option, then skip it. + $pos = strpos($flowbit, ","); + if ($pos === false) + continue; + $action = substr(strtolower($flowbit), 0, $pos); + if ($action == "isset" || $action == "isnotset") { + $target = preg_split('/[&|]/', substr($flowbit, $pos + 1)); + foreach ($target as $t) + if (!empty($t) && !isset($checked_flowbits[$t])) { + if (!is_array($checked_flowbits[$t])) + $checked_flowbits[$t] = array(); + $checked_flowbits[$t] = $action; + } + } + } + } + } + unset($rulem, $rulem2); + return $checked_flowbits; +} + +function suricata_get_set_flowbits($rules_map) { + + /*********************************************************/ + /* This function checks all the currently enabled rules */ + /* to find any set flowbits, and returns the flowbit */ + /* names in an array. */ + /*********************************************************/ + + $set_flowbits = array(); + foreach ($rules_map as $rulem) { + if (!is_array($rulem)) + continue; + foreach ($rulem as $rulem2) { + if ($rulem2['disabled'] == 1) + continue; + if (empty($rulem2['flowbits'])) + continue; + if (!is_array($rulem2['flowbits'])) + continue; + foreach ($rulem2['flowbits'] as $flowbit) { + if (empty($flowbit)) + continue; + /* If no comma in flowbits option, then skip it. */ + $pos = strpos($flowbit, ","); + if ($pos === false) + continue; + $action = substr(strtolower($flowbit), 0, $pos); + if ($action == "set" || $action == "toggle" || $action == "setx") { + $target = preg_split('/[&|]/', substr($flowbit, $pos + 1)); + foreach ($target as $t) + if (!empty($t) && !isset($set_flowbits[$t])) { + if (!is_array($set_flowbits[$t])) + $set_flowbits[$t] = array(); + $set_flowbits[$t] = $action; + } + } + } + } + } + unset($rulem, $rulem2); + return $set_flowbits; +} + +function suricata_find_flowbit_required_rules($rules, $unchecked_flowbits) { + + /********************************************************/ + /* This function finds all rules that must be enabled */ + /* in order to satisfy the "checked flowbits" used by */ + /* the currently enabled rules. It returns the list */ + /* of required rules in an array. */ + /********************************************************/ + + $required_flowbits_rules = array(); + foreach ($rules as $k1 => $rule) { + if (!is_array($rule)) + continue; + foreach ($rule as $k2 => $rule2) { + if (empty($rule2['flowbits'])) + continue; + if (!is_array($rule2['flowbits'])) + continue; + foreach ($rule2['flowbits'] as $flowbit) { + if (empty($flowbit)) + continue; + $action = substr($flowbit, 0, strpos($flowbit, ",")); + if (!strcasecmp(substr($action, 0, 3), "set")) { + $tmp = substr($flowbit, strpos($flowbit, ",") +1 ); + if (!empty($tmp) && isset($unchecked_flowbits[$tmp])) { + if (!is_array($required_flowbits_rules[$k1])) + $required_flowbits_rules[$k1] = array(); + if (!is_array($required_flowbits_rules[$k1][$k2])) + $required_flowbits_rules[$k1][$k2] = array(); + $required_flowbits_rules[$k1][$k2]['category'] = $rule2['category']; + if ($rule2['disabled'] == 0) + // If not disabled, just return the rule text "as is" + $required_flowbits_rules[$k1][$k2]['rule'] = ltrim($rule2['rule']); + else { + // If rule is disabled, remove leading '#' to enable it + $required_flowbits_rules[$k1][$k2]['rule'] = ltrim(substr($rule2['rule'], strpos($rule2['rule'], "#") + 1)); + $required_flowbits_rules[$k1][$k2]['disabled'] = 0; + } + } + } + } + } + } + unset($rule, $rule2); + + return $required_flowbits_rules; +} + +function suricata_resolve_flowbits($rules, $active_rules) { + + /******************************************************/ + /* This function auto-resolves flowbit requirements */ + /* by finding all checked flowbits in the currently */ + /* enabled rules, and then making sure all the "set" */ + /* flowbit rules for those "checked" flowbits are */ + /* enabled. For any that are not enabled, they are */ + /* copied to an array, enabled, and returned. */ + /* */ + /* $active_rules --> Rules Map array containing */ + /* the current rules for the */ + /* interface to resolve flowbit */ + /* dependencies for. */ + /* */ + /* $rules --> Rules Map array containing */ + /* all the available rules. */ + /******************************************************/ + + $suricatadir = SURICATADIR; + + // Check $rules array to be sure it is filled. + if (empty($rules)) { + log_error(gettext("[Suricata] WARNING: Flowbit resolution not done - no rules in {$suricatadir}rules/ ...")); + return array(); + } + + // First, find all the "checked" and "set" flowbits. + $checked_flowbits = suricata_get_checked_flowbits($active_rules); + $set_flowbits = suricata_get_set_flowbits($active_rules); + + // Next find any "checked" flowbits without matching + // "set" flowbit rules in the enabled rule set. + $delta_flowbits = array_diff_key($checked_flowbits, $set_flowbits); + + // Cleanup and release the memory we no longer need. + unset($checked_flowbits); + unset($set_flowbits); + + // Now find all the needed "set flowbit" rules from + // the master list of all rules. + $required_rules = suricata_find_flowbit_required_rules($rules, $delta_flowbits); + + // Cleanup and release memory we no longer need. + unset($delta_flowbits); + + return $required_rules; +} + +function suricata_write_flowbit_rules_file($flowbit_rules, $rule_file) { + + /************************************************/ + /* This function takes an array of rules in the */ + /* rules_map format and writes them to the file */ + /* given. */ + /* */ + /* $flowbit_rules --> array of flowbit-required */ + /* rules. */ + /* */ + /* $rule_file --> filename to write the */ + /* flowbit-required rules */ + /* to. */ + /************************************************/ + + $flowbit_rules_file = FLOWBITS_FILENAME; + + // See if we were passed a directory or full + // filename to write the rules to, and adjust + // the destination argument accordingly. + if (is_dir($rule_file)) + $rule_file = rtrim($rule_file, '/')."/{$flowbit_rules_file}"; + + if (empty($flowbit_rules)) { + @file_put_contents($rule_file, ""); + return; + } + + $fp = fopen($rule_file, "w"); + if ($fp) { + @fwrite($fp, "# These rules set flowbits checked by your other enabled rules. If the\n"); + @fwrite($fp, "# dependent flowbits are not set, then some of your chosen rules may\n"); + @fwrite($fp, "# not fire. Enabling all rules that set these dependent flowbits ensures\n"); + @fwrite($fp, "# your chosen rules fire as intended.\n#\n"); + @fwrite($fp, "# If you wish to prevent alerts from any of these rules, add the GID:SID\n"); + @fwrite($fp, "# of the rule to the Suppression List for the interface.\n"); + foreach ($flowbit_rules as $k1 => $rule) { + foreach ($rule as $k2 => $rule2) { + @fwrite($fp, "\n# Category: {$rule2['category']}"); + @fwrite($fp, " GID:{$k1} SID:{$k2}\n"); + @fwrite($fp, $rule2['rule']); + } + } + fclose($fp); + } +} + +function suricata_load_vrt_policy($policy, $all_rules=null) { + + /************************************************/ + /* This function returns an array of all rules */ + /* marked with the passed in $policy metadata. */ + /* */ + /* $policy --> desired VRT security policy */ + /* 1. connectivity */ + /* 2. balanced */ + /* 3. security */ + /* */ + /* $all_rules --> optional Rules Map array of */ + /* rules to scan for policy. */ + /* If not provided, then an */ + /* array will be created. */ + /************************************************/ + + $suricatadir = SURICATADIR; + $vrt_policy_rules = array(); + + // Load a map of all the VRT rules if we were + // not passed a pre-loaded one to use. + if (is_null($all_rules)) { + /* Since only Snort VRT rules have IPS Policy metadata, */ + /* limit our search to just those files. */ + $suricata_file_pattern = VRT_FILE_PREFIX . "*.rules"; + $suricata_vrt_files = glob("{$suricatadir}rules/{$suricata_file_pattern}"); + $all_rules = suricata_load_rules_map($suricata_vrt_files); + } + + // Now walk the rules list and find all those that are + // defined as active for the chosen security policy. + foreach ($all_rules as $k1 => $arulem) { + foreach ($arulem as $k2 => $arulem2) { + if (strripos($arulem2['rule'], "policy {$policy}-ips") !== false) { + if (!preg_match('/flowbits\s*:\s*noalert/i', $arulem2['rule'])) { + if (!is_array($vrt_policy_rules[$k1])) + $vrt_policy_rules[$k1] = array(); + if (!is_array($vrt_policy_rules[$k1][$k2])) + $vrt_policy_rules[$k1][$k2] = array(); + $vrt_policy_rules[$k1][$k2] = $arulem2; + + // Enable the policy rule if disabled + if ($arulem2['disabled'] == 1) { + $vrt_policy_rules[$k1][$k2]['rule'] = ltrim(substr($arulem2['rule'], strpos($arulem2['rule'], "#") + 1)); + $vrt_policy_rules[$k1][$k2]['disabled'] = 0; + } + } + } + } + } + + // Release memory we no longer need. + unset($arulem, $arulem2); + + // Return all the rules that match the policy. + return $vrt_policy_rules; +} + +function suricata_load_sid_mods($sids) { + + /*****************************************/ + /* This function parses the string of */ + /* SID values in $sids and returns an */ + /* array with the SID as the key and */ + /* value. The SID values in $sids are */ + /* assumed to be delimited by "||". */ + /* */ + /* $sids ==> string of SID values from */ + /* saved config file. */ + /* */ + /* Returns ==> a multidimensional array */ + /* with GID and SID as the */ + /* keys ($result[GID][SID]) */ + /*****************************************/ + + $result = array(); + if (empty($sids)) + return $result; + $tmp = explode("||", $sids); + foreach ($tmp as $v) { + if (preg_match('/(\d+)\s*:\s*(\d+)/', $v, $match)) { + if (!is_array($result[$match[1]])) + $result[$match[1]] = array(); + $result[$match[1]][$match[2]] = "{$match[1]}:{$match[2]}"; + } + } + unset($tmp); + + return $result; +} + +function suricata_modify_sids(&$rule_map, $suricatacfg) { + + /*****************************************/ + /* This function modifies the rules in */ + /* the passed rules_map array based on */ + /* values in the enablesid/disablesid */ + /* configuration parameters. */ + /* */ + /* $rule_map = array of current rules */ + /* $suricatacfg = config settings */ + /*****************************************/ + + if (!isset($suricatacfg['rule_sid_on']) && + !isset($suricatacfg['rule_sid_off'])) + return; + + // Load up our enablesid and disablesid + // arrays with lists of modified SIDs. + $enablesid = suricata_load_sid_mods($suricatacfg['rule_sid_on'], "enablesid"); + $disablesid = suricata_load_sid_mods($suricatacfg['rule_sid_off'], "disablesid"); + + /* Turn on any rules that need to be */ + /* forced "on" with enablesid mods. */ + if (!empty($enablesid)) { + foreach ($rule_map as $k1 => $rulem) { + foreach ($rulem as $k2 => $v) { + if (isset($enablesid[$k1][$k2]) && $v['disabled'] == 1) { + $rule_map[$k1][$k2]['rule'] = ltrim($v['rule'], " \t#"); + $rule_map[$k1][$k2]['disabled'] = 0; + } + } + } + } + + /* Turn off any rules that need to be */ + /* forced "off" with disablesid mods. */ + if (!empty($disablesid)) { + foreach ($rule_map as $k1 => $rulem) { + foreach ($rulem as $k2 => $v) { + if (isset($disablesid[$k1][$k2]) && $v['disabled'] == 0) { + $rule_map[$k1][$k2]['rule'] = "# " . $v['rule']; + $rule_map[$k1][$k2]['disabled'] = 1; + } + } + } + } + unset($enablesid, $disablesid); +} + +function suricata_prepare_rule_files($suricatacfg, $suricatacfgdir) { + + /***********************************************************/ + /* This function builds a new set of enforcing rules for */ + /* Suricata and writes them to disk. */ + /* */ + /* $suricatacfg --> pointer to applicable section of */ + /* config.xml containing settings for */ + /* the interface. */ + /* */ + /* $suricatacfgdir --> pointer to physical directory on */ + /* disk where Suricata configuration is */ + /* to be written. */ + /***********************************************************/ + + global $rebuild_rules; + + $suricatadir = SURICATADIR; + $flowbit_rules_file = FLOWBITS_FILENAME; + $suricata_enforcing_rules_file = ENFORCING_RULES_FILENAME; + $no_rules_defined = true; + + // If there is no reason to rebuild the rules, exit to save time. + if (!$rebuild_rules) + return; + + // Log a message for rules rebuild in progress + log_error(gettext("[Suricata] Updating rules configuration for: " . suricata_get_friendly_interface($suricatacfg['interface']) . " ...")); + + // Only rebuild rules if some are selected or an IPS Policy is enabled + if (!empty($suricatacfg['rulesets']) || $suricatacfg['ips_policy_enable'] == 'on') { + $enabled_rules = array(); + $enabled_files = array(); + $all_rules = array(); + $no_rules_defined = false; + + // Load up all the rules into a Rules Map array. + $all_rules = suricata_load_rules_map("{$suricatadir}rules/"); + + // Create an array with the filenames of the enabled + // rule category files if we have any. + if (!empty($suricatacfg['rulesets'])) { + foreach (explode("||", $suricatacfg['rulesets']) as $file){ + $category = basename($file, ".rules"); + if (!is_array($enabled_files[$category])) + $enabled_files[$category] = array(); + $enabled_files[$category] = $file; + } + + /****************************************************/ + /* Walk the ALL_RULES map array and copy the rules */ + /* matching our selected file categories to the */ + /* ENABLED_RULES map array. */ + /****************************************************/ + foreach ($all_rules as $k1 => $rulem) { + foreach ($rulem as $k2 => $v) { + if (isset($enabled_files[$v['category']])) { + if (!is_array($enabled_rules[$k1])) + $enabled_rules[$k1] = array(); + if (!is_array($enabled_rules[$k1][$k2])) + $enabled_rules[$k1][$k2] = array(); + $enabled_rules[$k1][$k2]['rule'] = $v['rule']; + $enabled_rules[$k1][$k2]['category'] = $v['category']; + $enabled_rules[$k1][$k2]['disabled'] = $v['disabled']; + $enabled_rules[$k1][$k2]['flowbits'] = $v['flowbits']; + } + } + } + + // Release memory we no longer need. + unset($enabled_files, $rulem, $v); + } + + // Check if a pre-defined Snort VRT policy is selected. If so, + // add all the VRT policy rules to our enforcing rule set. + if (!empty($suricatacfg['ips_policy'])) { + $policy_rules = suricata_load_vrt_policy($suricatacfg['ips_policy'], $all_rules); + foreach ($policy_rules as $k1 => $policy) { + foreach ($policy as $k2 => $p) { + if (!is_array($enabled_rules[$k1])) + $enabled_rules[$k1] = array(); + if (!is_array($enabled_rules[$k1][$k2])) + $enabled_rules[$k1][$k2] = array(); + $enabled_rules[$k1][$k2]['rule'] = $p['rule']; + $enabled_rules[$k1][$k2]['category'] = $p['category']; + $enabled_rules[$k1][$k2]['disabled'] = $p['disabled']; + $enabled_rules[$k1][$k2]['flowbits'] = $p['flowbits']; + } + } + unset($policy_rules, $policy, $p); + } + + // Process any enablesid or disablesid modifications for the selected rules. + suricata_modify_sids($enabled_rules, $suricatacfg); + + // Write the enforcing rules file to the Suricata interface's "rules" directory. + suricata_write_enforcing_rules_file($enabled_rules, "{$suricatacfgdir}/rules/{$suricata_enforcing_rules_file}"); + + // If auto-flowbit resolution is enabled, generate the dependent flowbits rules file. + if ($suricatacfg['autoflowbitrules'] == 'on') { + log_error('[Suricata] Enabling any flowbit-required rules for: ' . suricata_get_friendly_interface($suricatacfg['interface']) . '...'); + $fbits = suricata_resolve_flowbits($all_rules, $enabled_rules); + + // Check for and disable any flowbit-required rules the user has + // manually forced to a disabled state. + suricata_modify_sids($fbits, $suricatacfg); + suricata_write_flowbit_rules_file($fbits, "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); + unset($fbits); + } else + // Just put an empty file to always have the file present + suricata_write_flowbit_rules_file(array(), "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); + } else { + suricata_write_enforcing_rules_file(array(), "{$suricatacfgdir}/rules/{$suricata_enforcing_rules_file}"); + suricata_write_flowbit_rules_file(array(), "{$suricatacfgdir}/rules/{$flowbit_rules_file}"); + } + + if (!empty($suricatacfg['customrules'])) { + @file_put_contents("{$suricatacfgdir}/rules/custom.rules", base64_decode($suricatacfg['customrules'])); + $no_rules_defined = false; + } + else + @file_put_contents("{$suricatacfgdir}/rules/custom.rules", ""); + + // Log a warning if the interface has no rules defined or enabled + if ($no_rules_defined) + log_error(gettext("[Suricata] Warning - no text rules selected for: " . suricata_get_friendly_interface($suricatacfg['interface']) . " ...")); + + // Build a new sid-msg.map file from the enabled + // rules and copy it to the interface directory. + log_error(gettext("[Suricata] Building new sig-msg.map file for " . suricata_get_friendly_interface($suricatacfg['interface']) . "...")); + suricata_build_sid_msg_map("{$suricatacfgdir}/rules/", "{$suricatacfgdir}/sid-msg.map"); +} + + +function suricata_write_enforcing_rules_file($rule_map, $rule_path) { + + /************************************************/ + /* This function takes a rules map array of */ + /* the rules chosen for the active rule set */ + /* and writes them out to the passed path. */ + /* */ + /* $rule_map --> Rules Map array of rules to */ + /* write to disk. */ + /* */ + /* $rule_path --> filename or directory where */ + /* rules file will be written. */ + /************************************************/ + + $rule_file = "/" . ENFORCING_RULES_FILENAME; + + // See if we were passed a directory or full + // filename to write the rules to, and adjust + // the destination argument accordingly. + if (is_dir($rule_path)) + $rule_file = rtrim($rule_path, '/').$rule_file; + else + $rule_file = $rule_path; + + // If the $rule_map array is empty, then exit. + if (empty($rule_map)) { + file_put_contents($rule_file, ""); + return; + } + + $fp = fopen($rule_file, "w"); + if ($fp) { + @fwrite($fp, "# These rules are your current set of enforced rules for the protected\n"); + @fwrite($fp, "# interface. This list was compiled from the categories selected on the\n"); + @fwrite($fp, "# CATEGORIES tab of the Suricata configuration for the interface and/or any\n"); + @fwrite($fp, "# chosen Snort VRT pre-defined IPS Policy.\n#\n"); + @fwrite($fp, "# Any enablesid or disablesid customizations you made have been applied\n"); + @fwrite($fp, "# to the rules in this file.\n\n"); + foreach ($rule_map as $rulem) { + foreach ($rulem as $rulem2) { + /* No reason to write disabled rules to enforcing file, so skip them. */ + if ($rulem2['disabled'] == 1) + continue; + @fwrite($fp, $rulem2['rule']); + } + } + fclose($fp); + } +} + +function suricata_create_rc() { + + /************************************************************/ + /* This function builds the /usr/local/etc/rc.d/suricata.sh */ + /* shell script for starting and stopping Suricata. The */ + /* script is rebuilt on each package sync operation and */ + /* after any changes to suricata.conf saved in the GUI. */ + /************************************************************/ + + global $config, $g; + + $suricatadir = SURICATADIR; + $suricatalogdir = SURICATALOGDIR; + $rcdir = RCFILEPREFIX; + + // If no interfaces are configured for Suricata, exit + if (!is_array($config['installedpackages']['suricata']['rule'])) + return; + $suricataconf = $config['installedpackages']['suricata']['rule']; + if (empty($suricataconf)) + return; + + // At least one interface is configured, so OK + $start_suricata_iface_start = array(); + $start_suricata_iface_stop = array(); + + // Loop thru each configured interface and build + // the shell script. + foreach ($suricataconf as $value) { + $suricata_uuid = $value['uuid']; + $if_real = suricata_get_real_interface($value['interface']); + + $start_barnyard = <</dev/null; do + sleep 1 + time=\$((time+1)) + if [ \$time -gt \$timeout ]; then + break + fi + done + if [ -f /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then + /bin/rm /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid + fi + fi + /usr/bin/logger -p daemon.info -i -t SuricataStartup "Barnyard2 START for {$value['descr']}({$suricata_uuid}_{$if_real})..." + /usr/local/bin/barnyard2 -r {$suricata_uuid} -f unified2.alert --pid-path {$g['varrun_path']} --nolock-pidfile -c {$suricatadir}suricata_{$suricata_uuid}_{$if_real}/barnyard2.conf -d {$suricatalogdir}suricata_{$if_real}{$suricata_uuid} -D -q + +EOE; + $stop_barnyard2 = <</dev/null; do + sleep 1 + time=\$((time+1)) + if [ \$time -gt \$timeout ]; then + break + fi + done + if [ -f /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid ]; then + /bin/rm /var/run/barnyard2_{$if_real}{$suricata_uuid}.pid + fi + else + pid=`/bin/pgrep -f "barnyard2 -r {$suricata_uuid} "` + if [ ! -z \$pid ]; then + /bin/pkill -TERM -f "barnyard2 -r {$suricata_uuid} " + time=0 timeout=30 + while /bin/kill -TERM \$pid 2>/dev/null; do + sleep 1 + time=\$((time+1)) + if [ \$time -gt \$timeout ]; then + break + fi + done + fi + fi + +EOE; + if ($value['barnyard_enable'] == 'on') + $start_barnyard2 = $start_barnyard; + else + $start_barnyard2 = $stop_barnyard2; + + $start_suricata_iface_start[] = <</dev/null; do + sleep 1 + time=\$((time+1)) + if [ \$time -gt \$timeout ]; then + break + fi + done + if [ -f /var/run/suricata_{$if_real}{$suricata_uuid}.pid ]; then + /bin/rm /var/run/suricata_{$if_real}{$suricata_uuid}.pid + fi + else + pid=`/bin/pgrep -f "suricata -i {$if_real} "` + if [ ! -z \$pid ]; then + /usr/bin/logger -p daemon.info -i -t SuricataStartup "Suricata STOP for {$value['descr']}({$suricata_uuid}_{$if_real})..." + /bin/pkill -TERM -f "suricata -i {$if_real} " + time=0 timeout=30 + while /bin/kill -TERM \$pid 2>/dev/null; do + sleep 1 + time=\$((time+1)) + if [ \$time -gt \$timeout ]; then + break + fi + done + fi + fi + + sleep 2 + {$stop_barnyard2} + +EOE; + } + + $rc_start = implode("\n", $start_suricata_iface_start); + $rc_stop = implode("\n", $start_suricata_iface_stop); + + $suricata_sh_text = << Suricata instance info in */ + /* the config.xml master config */ + /* file. */ + /************************************************************/ + + global $config, $g; + + $suricatadir = SURICATADIR; + $suricatalogdir = SURICATALOGDIR; + $flowbit_rules_file = FLOWBITS_FILENAME; + $suricata_enforcing_rules_file = ENFORCING_RULES_FILENAME; + $if_real = suricata_get_real_interface($suricatacfg['interface']); + $suricata_uuid = $suricatacfg['uuid']; + $suricatacfgdir = "{$suricatadir}suricata_{$suricata_uuid}_{$if_real}"; + + conf_mount_rw(); + + if (!is_array($config['installedpackages']['suricata']['rule'])) + return; + + // Pull in the PHP code that generates the suricata.yaml file + // variables that will be substitued further down below. + include("/usr/local/www/suricata/suricata_generate_yaml.php"); + + // Pull in the boilerplate template for the suricata.yaml + // configuration file. The contents of the template along + // with substituted variables is stored in $suricata_conf_text + // (which is defined in the included file). + include("/usr/local/pkg/suricata/suricata_yaml_template.inc"); + + // Now write out the conf file using $suricata_conf_text contents + $conf = fopen("{$suricatacfgdir}/suricata.yaml", "w"); + if(!$conf) { + log_error("Could not open {$suricatacfgdir}/suricata.yaml for writing."); + return -1; + } + fwrite($conf, $suricata_conf_text); + fclose($conf); + + conf_mount_ro(); +} + +?> diff --git a/config/suricata/suricata.priv.inc b/config/suricata/suricata.priv.inc new file mode 100644 index 00000000..a8f9807a --- /dev/null +++ b/config/suricata/suricata.priv.inc @@ -0,0 +1,46 @@ + \ No newline at end of file diff --git a/config/suricata/suricata.xml b/config/suricata/suricata.xml new file mode 100644 index 00000000..4c3e3e67 --- /dev/null +++ b/config/suricata/suricata.xml @@ -0,0 +1,241 @@ + + + + + + + + Suricata IDS/IPS Package + None + suricata + 1.4.6 pkg v0.1-BETA + Services: Suricata IDS + /usr/local/pkg/suricata/suricata.inc + + Suricata + Configure Suricata settings +
Services
+ /suricata/suricata_interfaces.php +
+ + suricata + suricata.sh + suricata + Suricata IDS/IPS Daemon + + + /etc/inc/priv/ + 077 + http://www.pfsense.com/packages/config/suricata/suricata.priv.inc + + + http://www.pfsense.com/packages/config/suricata/suricata.inc + /usr/local/pkg/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_check_cron_misc.inc + /usr/local/pkg/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_yaml_template.inc + /usr/local/pkg/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_generate_yaml.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_download_updates.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_global.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_alerts.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_interfaces.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_interfaces_edit.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_download_rules.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_check_for_rule_updates.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_log_view.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_rules.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_rulesets.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_rules_flowbits.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_rules_edit.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_flow_stream.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_os_policy_engine.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_import_aliases.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_select_alias.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_suppress.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_suppress_edit.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_logs_browser.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_list_view.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_app_parsers.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_libhtp_policy_engine.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_uninstall.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_define_vars.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_barnyard.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_post_install.php + /usr/local/www/suricata/ + 0755 + + + http://www.pfsense.com/packages/config/suricata/suricata_uninstall.php + /usr/local/www/suricata/ + 0755 + + + ['installedpackages']['suricata'] + + + + + + + + + + + + sync_suricata_package_config(); + + + +
diff --git a/config/suricata/suricata_alerts.php b/config/suricata/suricata_alerts.php new file mode 100644 index 00000000..d21f7388 --- /dev/null +++ b/config/suricata/suricata_alerts.php @@ -0,0 +1,578 @@ + suppression entry text */ + /* */ + /* Returns: */ + /* TRUE if successful or FALSE on failure */ + /************************************************/ + + global $config, $a_instance, $instanceid; + + if (!is_array($config['installedpackages']['suricata']['suppress'])) + $config['installedpackages']['suricata']['suppress'] = array(); + if (!is_array($config['installedpackages']['suricata']['suppress']['item'])) + $config['installedpackages']['suricata']['suppress']['item'] = array(); + $a_suppress = &$config['installedpackages']['suricata']['suppress']['item']; + + $found_list = false; + + /* If no Suppress List is set for the interface, then create one with the interface name */ + if (empty($a_instance[$instanceid]['suppresslistname']) || $a_instance[$instanceid]['suppresslistname'] == 'default') { + $s_list = array(); + $s_list['uuid'] = uniqid(); + $s_list['name'] = $a_instance[$instanceid]['interface'] . "suppress" . "_" . $s_list['uuid']; + $s_list['descr'] = "Auto-generated list for Alert suppression"; + $s_list['suppresspassthru'] = base64_encode($suppress); + $a_suppress[] = $s_list; + $a_instance[$instanceid]['suppresslistname'] = $s_list['name']; + $found_list = true; + } else { + /* If we get here, a Suppress List is defined for the interface so see if we can find it */ + foreach ($a_suppress as $a_id => $alist) { + if ($alist['name'] == $a_instance[$instanceid]['suppresslistname']) { + $found_list = true; + if (!empty($alist['suppresspassthru'])) { + $tmplist = base64_decode($alist['suppresspassthru']); + $tmplist .= "\n{$suppress}"; + $alist['suppresspassthru'] = base64_encode($tmplist); + $a_suppress[$a_id] = $alist; + } + else { + $alist['suppresspassthru'] = base64_encode($suppress); + $a_suppress[$a_id] = $alist; + } + } + } + } + + /* If we created a new list or updated an existing one, save the change, */ + /* tell Snort to load it, and return true; otherwise return false. */ + if ($found_list) { + write_config(); + sync_suricata_package_config(); + suricata_reload_config($a_instance[$instanceid]); + return true; + } + else + return false; +} + +if ($_GET['instance']) + $instanceid = $_GET['instance']; +if ($_POST['instance']) + $instanceid = $_POST['instance']; +if (empty($instanceid)) + $instanceid = 0; + +if (!is_array($config['installedpackages']['suricata']['rule'])) + $config['installedpackages']['suricata']['rule'] = array(); +$a_instance = &$config['installedpackages']['suricata']['rule']; +$suricata_uuid = $a_instance[$instanceid]['uuid']; +$if_real = suricata_get_real_interface($a_instance[$instanceid]['interface']); +$suricatalogdir = SURICATALOGDIR; + +// Load up the arrays of force-enabled and force-disabled SIDs +$enablesid = suricata_load_sid_mods($a_instance[$instanceid]['rule_sid_on']); +$disablesid = suricata_load_sid_mods($a_instance[$instanceid]['rule_sid_off']); + +$pconfig = array(); +if (is_array($config['installedpackages']['suricata']['alertsblocks'])) { + $pconfig['arefresh'] = $config['installedpackages']['suricata']['alertsblocks']['arefresh']; + $pconfig['alertnumber'] = $config['installedpackages']['suricata']['alertsblocks']['alertnumber']; +} + +if (empty($pconfig['alertnumber'])) + $pconfig['alertnumber'] = '250'; +if (empty($pconfig['arefresh'])) + $pconfig['arefresh'] = 'off'; +$anentries = $pconfig['alertnumber']; + +if ($_POST['save']) { + if (!is_array($config['installedpackages']['suricata']['alertsblocks'])) + $config['installedpackages']['suricata']['alertsblocks'] = array(); + $config['installedpackages']['suricata']['alertsblocks']['arefresh'] = $_POST['arefresh'] ? 'on' : 'off'; + $config['installedpackages']['suricata']['alertsblocks']['alertnumber'] = $_POST['alertnumber']; + + write_config(); + + header("Location: /suricata/suricata_alerts.php?instance={$instanceid}"); + exit; +} + +//if ($_POST['todelete'] || $_GET['todelete']) { +// $ip = ""; +// if($_POST['todelete']) +// $ip = $_POST['todelete']; +// else if($_GET['todelete']) +// $ip = $_GET['todelete']; +// if (is_ipaddr($ip)) { +// exec("/sbin/pfctl -t snort2c -T delete {$ip}"); +// $savemsg = gettext("Host IP address {$ip} has been removed from the Blocked Table."); +// } +//} + +if ($_GET['act'] == "addsuppress" && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) { + if (empty($_GET['descr'])) + $suppress = "suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n"; + else + $suppress = "#{$_GET['descr']}\nsuppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n"; + + /* Add the new entry to the Suppress List */ + if (suricata_add_supplist_entry($suppress)) + $savemsg = gettext("An entry for 'suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}' has been added to the Suppress List."); + else + $input_errors[] = gettext("Suppress List '{$a_instance[$instanceid]['suppresslistname']}' is defined for this interface, but it could not be found!"); +} + +if (($_GET['act'] == "addsuppress_srcip" || $_GET['act'] == "addsuppress_dstip") && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) { + if ($_GET['act'] == "addsuppress_srcip") + $method = "by_src"; + else + $method = "by_dst"; + + /* Check for valid IP addresses, exit if not valid */ + if (is_ipaddr($_GET['ip']) || is_ipaddrv6($_GET['ip'])) { + if (empty($_GET['descr'])) + $suppress = "suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}, track {$method}, ip {$_GET['ip']}\n"; + else + $suppress = "#{$_GET['descr']}\nsuppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}, track {$method}, ip {$_GET['ip']}\n"; + } + else { + header("Location: /suricata/suricata_alerts.php?instance={$instanceid}"); + exit; + } + + /* Add the new entry to the Suppress List */ + if (suricata_add_supplist_entry($suppress)) + $savemsg = gettext("An entry for 'suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}, track {$method}, ip {$_GET['ip']}' has been added to the Suppress List."); + else + /* We did not find the defined list, so notify the user with an error */ + $input_errors[] = gettext("Suppress List '{$a_instance[$instanceid]['suppresslistname']}' is defined for this interface, but it could not be found!"); +} + +if ($_GET['act'] == "togglesid" && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) { + // Get the GID tag embedded in the clicked rule icon. + $gid = $_GET['gen_id']; + + // Get the SID tag embedded in the clicked rule icon. + $sid= $_GET['sidid']; + + // See if the target SID is in our list of modified SIDs, + // and toggle it if present. + if (isset($enablesid[$gid][$sid])) + unset($enablesid[$gid][$sid]); + if (isset($disablesid[$gid][$sid])) + unset($disablesid[$gid][$sid]); + elseif (!isset($disablesid[$gid][$sid])) + $disablesid[$gid][$sid] = "disablesid"; + + // Write the updated enablesid and disablesid values to the config file. + $tmp = ""; + foreach (array_keys($enablesid) as $k1) { + foreach (array_keys($enablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_instance[$instanceid]['rule_sid_on'] = $tmp; + else + unset($a_instance[$instanceid]['rule_sid_on']); + + $tmp = ""; + foreach (array_keys($disablesid) as $k1) { + foreach (array_keys($disablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_instance[$instanceid]['rule_sid_off'] = $tmp; + else + unset($a_instance[$instanceid]['rule_sid_off']); + + /* Update the config.xml file. */ + write_config(); + + /*************************************************/ + /* Update the suricata.yaml file and rebuild the */ + /* rules for this interface. */ + /*************************************************/ + $rebuild_rules = true; + suricata_generate_yaml($a_instance[$instanceid]); + $rebuild_rules = false; + + /* Signal Suricata to live-load the new rules */ + suricata_reload_config($a_instance[$instanceid]); + + $savemsg = gettext("The state for rule {$gid}:{$sid} has been modified. Suricata is 'live-reloading' the new rules list. Please wait at least 30 secs for the process to complete before toggling additional rules."); +} + +if ($_GET['action'] == "clear" || $_POST['delete']) { + conf_mount_rw(); + suricata_post_delete_logs($suricata_uuid); + $fd = @fopen("{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/alerts.log", "w+"); + if ($fd) + fclose($fd); + conf_mount_ro(); + /* XXX: This is needed if suricata is run as suricata user */ + mwexec('/bin/chmod 660 {$suricatalogdir}*', true); + if (file_exists("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid")) + mwexec("/bin/pkill -HUP -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid -a"); + header("Location: /suricata/suricata_alerts.php?instance={$instanceid}"); + exit; +} + +if ($_POST['download']) { + $save_date = exec('/bin/date "+%Y-%m-%d-%H-%M-%S"'); + $file_name = "suricata_logs_{$save_date}_{$if_real}.tar.gz"; + exec("cd {$suricatalogdir}suricata_{$if_real}{$suricata_uuid} && /usr/bin/tar -czf /tmp/{$file_name} *"); + + if (file_exists("/tmp/{$file_name}")) { + ob_start(); //important or other posts will fail + if (isset($_SERVER['HTTPS'])) { + header('Pragma: '); + header('Cache-Control: '); + } else { + header("Pragma: private"); + header("Cache-Control: private, must-revalidate"); + } + header("Content-Type: application/octet-stream"); + header("Content-length: " . filesize("/tmp/{$file_name}")); + header("Content-disposition: attachment; filename = {$file_name}"); + ob_end_clean(); //important or other post will fail + readfile("/tmp/{$file_name}"); + + // Clean up the temp file + @unlink("/tmp/{$file_name}"); + } + else + $savemsg = gettext("An error occurred while creating archive"); +} + +/* Load up an array with the current Suppression List GID,SID values */ +$supplist = suricata_load_suppress_sigs($a_instance[$instanceid], true); + +$pgtitle = gettext("Suricata: Alerts"); +include_once("head.inc"); + +?> + + + +\n"; +?> + +' . $pgtitle . '

';} + /* Display Alert message */ + if ($input_errors) { + print_input_errors($input_errors); // TODO: add checks + } + if ($savemsg) { + print_info_box($savemsg); + } +?> +
+ + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
+    +
+    + + +
+ + > + ', '', '', ''); ?>   + + ', '', '', ''); ?> +
   +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + /tmp/alerts_{$suricata_uuid}"); + if (file_exists("/tmp/alerts_{$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 */ + $fd = fopen("/tmp/alerts_{$suricata_uuid}", "r"); + while (($fields = fgetcsv($fd, 1000, ',', '"')) !== FALSE) { + if(count($fields) < 12) + continue; + + /* Time */ + $alert_time = substr($fields[0], strpos($fields[0], '-')+1, -7); + /* Date */ + $alert_date = trim(substr($fields[0], 0, strpos($fields[0], '-'))); + /* Description */ + $alert_descr = $fields[5]; + $alert_descr_url = urlencode($fields[5]); + /* Priority */ + $alert_priority = $fields[7]; + /* Protocol */ + $alert_proto = $fields[8]; + /* 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 .= "  "; + $alert_ip_src .= ""; + } + elseif (isset($supplist[$fields[2]][$fields[3]]['by_src'][$fields[9]])) { + $alert_ip_src .= "  "; + } + /* Add icon for auto-removing from Blocked Table if required */ + if (isset($tmpblocked[$fields[9]])) { + $alert_ip_src .= " "; + $alert_ip_src .= " + \"Remove"; + } + /* 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[1]])) { + $alert_ip_dst .= "  "; + $alert_ip_dst .= ""; + } + elseif (isset($supplist[$fields[2]][$fields[3]]['by_dst'][$fields[11]])) { + $alert_ip_dst .= "  "; + } + /* Add icon for auto-removing from Blocked Table if required */ + if (isset($tmpblocked[$fields[11]])) { + $alert_ip_dst .= " "; + $alert_ip_dst .= " + \"Remove"; + } + /* IP DST Port */ + $alert_dst_p = $fields[12]; + /* SID */ + $alert_sid_str = "{$fields[2]}:{$fields[3]}"; + if (!suricata_is_alert_globally_suppressed($supplist, $fields[2], $fields[3])) { + $sidsupplink = ""; + $sidsupplink .= ""; + } + else { + $sidsupplink = ""; + } + /* Add icon for toggling rule state */ + if (isset($disablesid[$fields[2]][$fields[3]])) { + $sid_dsbl_link = ""; + $sid_dsbl_link .= ""; + } + else { + $sid_dsbl_link = ""; + $sid_dsbl_link .= ""; + } + /* DESCRIPTION */ + $alert_class = $fields[6]; + + echo " + + + + + + + + + + + \n"; + + $counter++; + } + fclose($fd); + @unlink("/tmp/alerts_{$suricata_uuid}"); + } +} +?> + +
{$alert_date}
{$alert_time}
{$alert_priority}{$alert_proto}{$alert_class}{$alert_ip_src}{$alert_src_p}{$alert_ip_dst}{$alert_dst_p}{$alert_sid_str}
{$sidsupplink}  {$sid_dsbl_link}
{$alert_descr}
+
+
+
+
+ + + + diff --git a/config/suricata/suricata_app_parsers.php b/config/suricata/suricata_app_parsers.php new file mode 100644 index 00000000..def78f94 --- /dev/null +++ b/config/suricata/suricata_app_parsers.php @@ -0,0 +1,340 @@ + "default", "bind_to" => "all", "personality" => "IDS", + "request-body-limit" => 4096, "response-body-limit" => 4096, + "double-decode-path" => "no", "double-decode-query" => "no" ); + $pconfig['libhtp_policy']['item'] = array(); + $pconfig['libhtp_policy']['item'][] = $default; + if (!is_array($a_nat[$id]['libhtp_policy']['item'])) + $a_nat[$id]['libhtp_policy']['item'] = array(); + $a_nat[$id]['libhtp_policy']['item'][] = $default; + write_config(); + $libhtp_engine_next_id++; + } + else + $pconfig['libhtp_policy'] = $a_nat[$id]['libhtp_policy']; +} + +// Check for returned "selected alias" if action is import +if ($_GET['act'] == "import" && isset($_GET['varname']) && !empty($_GET['varvalue'])) { + $pconfig[$_GET['varname']] = $_GET['varvalue']; +} + +if ($_GET['act'] && isset($_GET['eng_id'])) { + + $natent = array(); + $natent = $pconfig; + + if ($_GET['act'] == "del_libhtp_policy") + unset($natent['libhtp_policy']['item'][$_GET['eng_id']]); + + if (isset($id) && $a_nat[$id]) { + $a_nat[$id] = $natent; + write_config(); + } + + header("Location: /suricata/suricata_app_parsers.php?id=$id"); + exit; +} + +if ($_POST['ResetAll']) { + + /* Reset all the settings to defaults */ + $pconfig['asn1_max_frames'] = "256"; + + /* Log a message at the top of the page to inform the user */ + $savemsg = gettext("All flow and stream settings have been reset to their defaults."); +} +elseif ($_POST['Submit']) { + $natent = array(); + $natent = $pconfig; + + // TODO: validate input values + if (!is_numeric($_POST['asn1_max_frames'] ) || $_POST['asn1_max_frames'] < 1) + $input_errors[] = gettext("The value for 'ASN1 Max Frames' must be all numbers and greater than 0."); + + /* if no errors write to conf */ + if (!$input_errors) { + if ($_POST['asn1_max_frames'] != "") { $natent['asn1_max_frames'] = $_POST['asn1_max_frames']; }else{ $natent['asn1_max_frames'] = "256"; } + + /**************************************************/ + /* If we have a valid rule ID, save configuration */ + /* then update the suricata.conf file and rebuild */ + /* the rules for this interface. */ + /**************************************************/ + if (isset($id) && $a_nat[$id]) { + $a_nat[$id] = $natent; + write_config(); + $rebuild_rules = true; + suricata_generate_yaml($natent); + $rebuild_rules = false; + } + + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: suricata_app_parsers.php?id=$id"); + exit; + } +} + +$if_friendly = suricata_get_friendly_interface($pconfig['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} - Layer 7 Application Parsers"); +include_once("head.inc"); +?> + + + +' . $pgtitle . '

';} + + + /* Display Alert message */ + + if ($input_errors) { + print_input_errors($input_errors); // TODO: add checks + } + + if ($savemsg) { + print_info_box($savemsg); + } + +?> + + + + +
+ +'; + echo ' +
+
'; + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface "); + $tab_array = array(); + $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), false, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), false, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), false, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), true, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + display_top_tabs($tab_array); +?> +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+   + " . gettext("256") . "" . gettext(" frames."); ?>

+ +
+ + + + + + + + + + + + + + $v): ?> + + + + + + +
+ "> + + ">
+ "> + "all") : ?> + + "> + + "> + +
+
  + "> +      + >
  + +
+
+
+
+ + + + diff --git a/config/suricata/suricata_barnyard.php b/config/suricata/suricata_barnyard.php new file mode 100644 index 00000000..a65c5402 --- /dev/null +++ b/config/suricata/suricata_barnyard.php @@ -0,0 +1,503 @@ + 'on') { + if (empty($_POST['barnyard_syslog_dport']) || !is_numeric($_POST['barnyard_syslog_dport'])) + $input_errors[] = gettext("Please provide a valid number between 1 and 65535 for the Syslog Remote Port."); + if (empty($_POST['barnyard_syslog_rhost'])) + $input_errors[] = gettext("Please provide a valid hostname or IP address for the Syslog Remote Host."); + } + + // if no errors write to conf + if (!$input_errors) { + $natent = array(); + /* repost the options already in conf */ + $natent = $pconfig; + + $natent['barnyard_enable'] = $_POST['barnyard_enable'] ? 'on' : 'off'; + $natent['barnyard_show_year'] = $_POST['barnyard_show_year'] ? 'on' : 'off'; + $natent['barnyard_archive_enable'] = $_POST['barnyard_archive_enable'] ? 'on' : 'off'; + $natent['barnyard_dump_payload'] = $_POST['barnyard_dump_payload'] ? 'on' : 'off'; + $natent['barnyard_obfuscate_ip'] = $_POST['barnyard_obfuscate_ip'] ? 'on' : 'off'; + $natent['barnyard_mysql_enable'] = $_POST['barnyard_mysql_enable'] ? 'on' : 'off'; + $natent['barnyard_syslog_enable'] = $_POST['barnyard_syslog_enable'] ? 'on' : 'off'; + $natent['barnyard_syslog_local'] = $_POST['barnyard_syslog_local'] ? 'on' : 'off'; + $natent['barnyard_syslog_opmode'] = $_POST['barnyard_syslog_opmode']; + $natent['barnyard_syslog_proto'] = $_POST['barnyard_syslog_proto']; + + if ($_POST['barnyard_sensor_name']) $natent['barnyard_sensor_name'] = $_POST['barnyard_sensor_name']; else unset($natent['barnyard_sensor_name']); + if ($_POST['barnyard_dbhost']) $natent['barnyard_dbhost'] = $_POST['barnyard_dbhost']; else unset($natent['barnyard_dbhost']); + if ($_POST['barnyard_dbname']) $natent['barnyard_dbname'] = $_POST['barnyard_dbname']; else unset($natent['barnyard_dbname']); + if ($_POST['barnyard_dbuser']) $natent['barnyard_dbuser'] = $_POST['barnyard_dbuser']; else unset($natent['barnyard_dbuser']); + if ($_POST['barnyard_dbpwd']) $natent['barnyard_dbpwd'] = base64_encode($_POST['barnyard_dbpwd']); else unset($natent['barnyard_dbpwd']); + if ($_POST['barnyard_syslog_rhost']) $natent['barnyard_syslog_rhost'] = $_POST['barnyard_syslog_rhost']; else unset($natent['barnyard_syslog_rhost']); + if ($_POST['barnyard_syslog_dport']) $natent['barnyard_syslog_dport'] = $_POST['barnyard_syslog_dport']; else $natent['barnyard_syslog_dport'] = '514'; + if ($_POST['barnyard_syslog_facility']) $natent['barnyard_syslog_facility'] = $_POST['barnyard_syslog_facility']; else $natent['barnyard_syslog_facility'] = 'LOG_USER'; + if ($_POST['barnyard_syslog_priority']) $natent['barnyard_syslog_priority'] = $_POST['barnyard_syslog_priority']; else $natent['barnyard_syslog_priority'] = 'LOG_INFO'; + if ($_POST['barnconfigpassthru']) $natent['barnconfigpassthru'] = base64_encode($_POST['barnconfigpassthru']); else unset($natent['barnconfigpassthru']); + + if (isset($id) && $a_nat[$id]) + $a_nat[$id] = $natent; + else { + $a_nat[] = $natent; + } + + write_config(); + + // No need to rebuild rules if just toggling Barnyard2 on or off + $rebuild_rules = false; + sync_suricata_package_config(); + + // Signal any running barnyard2 instance on this interface to + // reload its configuration to pick up any changes made. + suricata_barnyard_reload_config($a_nat[$id], "HUP"); + + // after click go to this page + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: suricata_barnyard.php?id=$id"); + exit; + } +} + +$if_friendly = suricata_get_friendly_interface($pconfig['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} - Barnyard2 Settings"); +include_once("head.inc"); + +?> + + + +' . $pgtitle . '

';}?> + + + +
+ +'; + echo ' + + + +
+
'; + $tab_array = array(); + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface "); + $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), false, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), false, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), false, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), true, "/suricata/suricata_barnyard.php?id={$id}"); + display_top_tabs($tab_array); +?> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ onClick="enable_change(false)"/> +
+
+ /> + " . gettext("Checked") . ""; ?> +
+ /> + " . gettext("Checked") . ""; ?>
+ +
+ /> + " . gettext("Not Checked") . ""; ?>
+
+ /> + " . gettext("Not Checked") . ""; ?> +
+ +   +
+ + onClick="toggle_mySQL()"/>
+
+ +   +
+ +   +
+ +   +
+ +   +
+ + onClick="toggle_syslog()"/> +
+
+ /> +  /> +    +

+ +
+ + onClick="toggle_local_syslog()"/> +
+
+ +   +
+ +  " . gettext("514") . "."; ?> +
+ /> +  /> +    + " . gettext("UDP") . "."; ?> +
+    + " . gettext("LOG_USER") . "."; ?> +
+    + " . gettext("LOG_INFO") . "."; ?> +
+
+
  + +
  +
+
+
+
+
+ + + + + + diff --git a/config/suricata/suricata_check_cron_misc.inc b/config/suricata/suricata_check_cron_misc.inc new file mode 100644 index 00000000..88dfd5ff --- /dev/null +++ b/config/suricata/suricata_check_cron_misc.inc @@ -0,0 +1,109 @@ + 1, +// 'KB' => 1024, +// 'MB' => 1024 * 1024, +// 'GB' => 1024 * 1024 * 1024, +// 'TB' => 1024 * 1024 * 1024 * 1024, +// 'PB' => 1024 * 1024 * 1024 * 1024 * 1024, + + +/* chk if snort log dir is full if so clear it */ +$suricataloglimit = $config['installedpackages']['suricata']['config'][0]['suricataloglimit']; +$suricataloglimitsize = $config['installedpackages']['suricata']['config'][0]['suricataloglimitsize']; + +if ($g['booting']==true) + return; + +if ($suricataloglimit == 'off') + return; + +if (!is_array($config['installedpackages']['suricata']['rule'])) + return; + +/* Convert Log Limit Size setting from MB to KB */ +$suricataloglimitsizeKB = round($suricataloglimitsize * 1024); +$suricatalogdirsizeKB = suricata_Getdirsize(SURICATALOGDIR); +if ($suricatalogdirsizeKB > 0 && $suricatalogdirsizeKB > $suricataloglimitsizeKB) { + log_error(gettext("[Suricata] Log directory size exceeds configured limit of " . number_format($suricataloglimitsize) . " MB set on Global Settings tab. All Suricata log files will be truncated.")); + conf_mount_rw(); + + /* Truncate the Rules Update Log file if it exists */ + if (file_exists(RULES_UPD_LOGFILE)) { + log_error(gettext("[Suricata] Truncating the Rules Update Log file...")); + $fd = @fopen(RULES_UPD_LOGFILE, "w+"); + if ($fd) + fclose($fd); + } + + /* Clean-up the logs for each configured Suricata instance */ + foreach ($config['installedpackages']['suricata']['rule'] as $value) { + $if_real = suricata_get_real_interface($value['interface']); + $suricata_uuid = $value['uuid']; + $suricata_log_dir = SURICATALOGDIR . "suricata_{$if_real}{$suricata_uuid}"; + log_error(gettext("[Suricata] Truncating logs for {$value['descr']} ({$if_real})...")); + suricata_post_delete_logs($suricata_uuid); + + // Initialize an array of the log files we want to prune + $logs = array ( "alerts.log", "http.log", "files-json.log", "tls.log", "stats.log" ); + + foreach ($logs as $file) { + // Truncate the log file if it exists + if (file_exists("{$suricata_log_dir}/$file")) { + $fd = @fopen("{$suricata_log_dir}/$file", "w+"); + if ($fd) + fclose($fd); + } + } + + // Check for any captured stored files and clean them up + $filelist = glob("{$suricata_log_dir}/files/*"); + if (!empty($filelist)) { + foreach ($filelist as $file) + @unlink($file); + } + + // This is needed if suricata is run as suricata user + mwexec('/bin/chmod 660 /var/log/suricata/*', true); + + // Soft-restart Suricata process to resync logging + if (file_exists("{$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid")) { + log_error(gettext("[Suricata] Restarting logging on {$value['descr']} ({$if_real})...")); + mwexec("/bin/pkill -HUP -F {$g['varrun_path']}/suricata_{$if_real}{$suricata_uuid}.pid -a"); + } + } + conf_mount_ro(); + log_error(gettext("[Suricata] Automatic clean-up of Suricata logs completed.")); +} + +?> diff --git a/config/suricata/suricata_check_for_rule_updates.php b/config/suricata/suricata_check_for_rule_updates.php new file mode 100644 index 00000000..ec39c203 --- /dev/null +++ b/config/suricata/suricata_check_for_rule_updates.php @@ -0,0 +1,683 @@ + "OK", 202 => "Accepted", 204 => "No Content", 205 => "Reset Content", + 206 => "Partial Content", 301 => "Moved Permanently", 302 => "Found", + 305 => "Use Proxy", 307 => "Temporary Redirect", 400 => "Bad Request", + 401 => "Unauthorized", 402 => "Payment Required", 403 => "Forbidden", + 404 => "Not Found", 405 => "Method Not Allowed", 407 => "Proxy Authentication Required", + 408 => "Request Timeout", 410 => "Gone", 500 => "Internal Server Error", + 501 => "Not Implemented", 502 => "Bad Gateway", 503 => "Service Unavailable", + 504 => "Gateway Timeout", 505 => "HTTP Version Not Supported" ); + + $last_curl_error = ""; + + $fout = fopen($file_out, "wb"); + if ($fout) { + $ch = curl_init($url); + if (!$ch) + return false; + curl_setopt($ch, CURLOPT_FILE, $fout); + + // NOTE: required to suppress errors from XMLRPC due to progress bar output + if ($g['suricata_sync_in_progress']) + curl_setopt($ch, CURLOPT_HEADER, false); + else { + curl_setopt($ch, CURLOPT_HEADERFUNCTION, 'read_header'); + curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'read_body'); + } + + curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true); + curl_setopt($ch, CURLOPT_USERAGENT, "Mozilla/5.0 (compatible; MSIE 10.0; Windows NT 6.1; Win64; x64; Trident/6.0)"); + curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); + curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30); + curl_setopt($ch, CURLOPT_TIMEOUT, 0); + + // Use the system proxy server setttings if configured + if (!empty($config['system']['proxyurl'])) { + curl_setopt($ch, CURLOPT_PROXY, $config['system']['proxyurl']); + if (!empty($config['system']['proxyport'])) + curl_setopt($ch, CURLOPT_PROXYPORT, $config['system']['proxyport']); + if (!empty($config['system']['proxyuser']) && !empty($config['system']['proxypass'])) { + @curl_setopt($ch, CURLOPT_PROXYAUTH, CURLAUTH_ANY | CURLAUTH_ANYSAFE); + curl_setopt($ch, CURLOPT_PROXYUSERPWD, "{$config['system']['proxyuser']}:{$config['system']['proxypass']}"); + } + } + + $counter = 0; + $rc = true; + // Try up to 4 times to download the file before giving up + while ($counter < 4) { + $counter++; + $rc = curl_exec($ch); + if ($rc === true) + break; + log_error(gettext("[Suricata] Rules download error: " . curl_error($ch))); + log_error(gettext("[Suricata] Will retry in 15 seconds...")); + sleep(15); + } + if ($rc === false) + $last_curl_error = curl_error($ch); + $http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE); + if (isset($http_resp_msg[$http_code])) + $last_curl_error = $http_resp_msg[$http_code]; + curl_close($ch); + fclose($fout); + + // If we had to try more than once, log it + if ($counter > 1) + log_error(gettext("File '" . basename($file_out) . "' download attempts: {$counter} ...")); + return ($http_code == 200) ? true : $http_code; + } + else { + $last_curl_error = gettext("Failed to create file " . $file_out); + log_error(gettext("[Suricata] Failed to create file {$file_out} ...")); + return false; + } +} + +function suricata_check_rule_md5($file_url, $file_dst, $desc = "") { + + /**********************************************************/ + /* This function attempts to download the passed MD5 hash */ + /* file and compare its contents to the currently stored */ + /* hash file to see if a new rules file has been posted. */ + /* */ + /* On Entry: $file_url = URL for md5 hash file */ + /* $file_dst = Temp destination to store the */ + /* downloaded hash file */ + /* $desc = Short text string used to label */ + /* log messages with rules type */ + /* */ + /* Returns: TRUE if new rule file download required. */ + /* FALSE if rule download not required or an */ + /* error occurred. */ + /**********************************************************/ + + global $pkg_interface, $suricata_rules_upd_log, $last_curl_error; + + $suricatadir = SURICATADIR; + $filename_md5 = basename($file_dst); + + if ($pkg_interface <> "console") + update_status(gettext("Downloading {$desc} md5 file...")); + error_log(gettext("\tDownloading {$desc} md5 file {$filename_md5}...\n"), 3, $suricata_rules_upd_log); + $rc = suricata_download_file_url($file_url, $file_dst); + + // See if download from URL was successful + if ($rc === true) { + if ($pkg_interface <> "console") + update_status(gettext("Done downloading {$filename_md5}.")); + error_log("\tChecking {$desc} md5 file...\n", 3, $suricata_rules_upd_log); + + // check md5 hash in new file against current file to see if new download is posted + if (file_exists("{$suricatadir}{$filename_md5}")) { + $md5_check_new = file_get_contents($file_dst); + $md5_check_old = file_get_contents("{$suricatadir}{$filename_md5}"); + if ($md5_check_new == $md5_check_old) { + if ($pkg_interface <> "console") + update_status(gettext("{$desc} are up to date...")); + log_error(gettext("[Suricata] {$desc} are up to date...")); + error_log(gettext("\t{$desc} are up to date.\n"), 3, $suricata_rules_upd_log); + return false; + } + else + return true; + } + return true; + } + else { + error_log(gettext("\t{$desc} md5 download failed.\n"), 3, $suricata_rules_upd_log); + $suricata_err_msg = gettext("Server returned error code {$rc}."); + if ($pkg_interface <> "console") { + update_status(gettext("{$desc} md5 error ... Server returned error code {$rc} ...")); + update_output_window(gettext("{$desc} will not be updated.\n\t{$suricata_err_msg}")); + } + log_error(gettext("[Suricata] {$desc} md5 download failed...")); + log_error(gettext("[Suricata] Server returned error code {$rc}...")); + error_log(gettext("\t{$suricata_err_msg}\n"), 3, $suricata_rules_upd_log); + if ($pkg_interface == "console") + error_log(gettext("\tServer error message was: {$last_curl_error}\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$desc} will not be updated.\n"), 3, $suricata_rules_upd_log); + return false; + } +} + +function suricata_fetch_new_rules($file_url, $file_dst, $file_md5, $desc = "") { + + /**********************************************************/ + /* This function downloads the passed rules file and */ + /* compares its computed md5 hash to the passed md5 hash */ + /* to verify the file's integrity. */ + /* */ + /* On Entry: $file_url = URL of rules file */ + /* $file_dst = Temp destination to store the */ + /* downloaded rules file */ + /* $file_md5 = Expected md5 hash for the new */ + /* downloaded rules file */ + /* $desc = Short text string for use in */ + /* log messages */ + /* */ + /* Returns: TRUE if download was successful. */ + /* FALSE if download was not successful. */ + /**********************************************************/ + + global $pkg_interface, $suricata_rules_upd_log, $last_curl_error; + + $suricatadir = SURICATADIR; + $filename = basename($file_dst); + + if ($pkg_interface <> "console") + update_status(gettext("There is a new set of {$desc} posted. Downloading...")); + log_error(gettext("[Suricata] There is a new set of {$desc} posted. Downloading {$filename}...")); + error_log(gettext("\tThere is a new set of {$desc} posted.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tDownloading file '{$filename}'...\n"), 3, $suricata_rules_upd_log); + $rc = suricata_download_file_url($file_url, $file_dst); + + // See if the download from the URL was successful + if ($rc === true) { + if ($pkg_interface <> "console") + update_status(gettext("Done downloading {$desc} file.")); + log_error("[Suricata] {$desc} file update downloaded successfully"); + error_log(gettext("\tDone downloading rules file.\n"),3, $suricata_rules_upd_log); + + // Test integrity of the rules file. Turn off update if file has wrong md5 hash + if ($file_md5 != trim(md5_file($file_dst))){ + if ($pkg_interface <> "console") + update_output_window(gettext("{$desc} file MD5 checksum failed...")); + log_error(gettext("[Suricata] {$desc} file download failed. Bad MD5 checksum...")); + log_error(gettext("[Suricata] Downloaded File MD5: " . md5_file($file_dst))); + log_error(gettext("[Suricata] Expected File MD5: {$file_md5}")); + error_log(gettext("\t{$desc} file download failed. Bad MD5 checksum.\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tDownloaded {$desc} file MD5: " . md5_file($file_dst) . "\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\tExpected {$desc} file MD5: {$file_md5}\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$desc} file download failed. {$desc} will not be updated.\n"), 3, $suricata_rules_upd_log); + return false; + } + return true; + } + else { + if ($pkg_interface <> "console") + update_output_window(gettext("{$desc} file download failed...")); + log_error(gettext("[Suricata] {$desc} file download failed... server returned error '{$rc}'...")); + error_log(gettext("\t{$desc} file download failed. Server returned error {$rc}.\n"), 3, $suricata_rules_upd_log); + if ($pkg_interface == "console") + error_log(gettext("\tThe error text was: {$last_curl_error}\n"), 3, $suricata_rules_upd_log); + error_log(gettext("\t{$desc} will not be updated.\n"), 3, $suricata_rules_upd_log); + return false; + } + +} + +/* Start of main code */ +conf_mount_rw(); + +/* remove old $tmpfname files if present */ +if (is_dir("{$tmpfname}")) + exec("/bin/rm -r {$tmpfname}"); + +/* Make sure required suricatadirs exsist */ +exec("/bin/mkdir -p {$suricatadir}rules"); +exec("/bin/mkdir -p {$tmpfname}"); +exec("/bin/mkdir -p {$suricatalogdir}"); + +/* See if we need to automatically clear the Update Log based on 1024K size limit */ +if (file_exists($suricata_rules_upd_log)) { + if (1048576 < filesize($suricata_rules_upd_log)) + exec("/bin/rm -r {$suricata_rules_upd_log}"); +} + +/* Log start time for this rules update */ +error_log(gettext("Starting rules update... Time: " . date("Y-m-d H:i:s") . "\n"), 3, $suricata_rules_upd_log); +$last_curl_error = ""; + +/* Check for and download any new Emerging Threats Rules sigs */ +if ($emergingthreats == 'on') { + if (suricata_check_rule_md5("{$emergingthreats_url}{$emergingthreats_filename_md5}", "{$tmpfname}/{$emergingthreats_filename_md5}", "{$et_name} rules")) { + /* download Emerging Threats rules file */ + $file_md5 = trim(file_get_contents("{$tmpfname}/{$emergingthreats_filename_md5}")); + if (!suricata_fetch_new_rules("{$emergingthreats_url}{$emergingthreats_filename}", "{$tmpfname}/{$emergingthreats_filename}", $file_md5, "{$et_name} rules")) + $emergingthreats = 'off'; + } + else + $emergingthreats = 'off'; +} + +/* Check for and download any new Snort VRT sigs */ +if ($snortdownload == 'on') { + if (suricata_check_rule_md5("{$snort_rule_url}{$snort_filename_md5}/{$oinkid}/", "{$tmpfname}/{$snort_filename_md5}", "Snort VRT rules")) { + /* download snortrules file */ + $file_md5 = trim(file_get_contents("{$tmpfname}/{$snort_filename_md5}")); + if (!suricata_fetch_new_rules("{$snort_rule_url}{$snort_filename}/{$oinkid}/", "{$tmpfname}/{$snort_filename}", $file_md5, "Snort VRT rules")) + $snortdownload = 'off'; + } + else + $snortdownload = 'off'; +} + +/* Check for and download any new Snort GPLv2 Community Rules sigs */ +if ($snortcommunityrules == 'on') { + if (suricata_check_rule_md5("{$snort_community_rules_url}{$snort_community_rules_filename_md5}", "{$tmpfname}/{$snort_community_rules_filename_md5}", "Snort GPLv2 Community Rules")) { + /* download Snort GPLv2 Community Rules file */ + $file_md5 = trim(file_get_contents("{$tmpfname}/{$snort_community_rules_filename_md5}")); + if (!suricata_fetch_new_rules("{$snort_community_rules_url}{$snort_community_rules_filename}", "{$tmpfname}/{$snort_community_rules_filename}", $file_md5, "Snort GPLv2 Community Rules")) + $snortcommunityrules = 'off'; + } + else + $snortcommunityrules = 'off'; +} + +/* Untar Emerging Threats rules file to tmp if downloaded */ +if ($emergingthreats == 'on') { + safe_mkdir("{$tmpfname}/emerging"); + if (file_exists("{$tmpfname}/{$emergingthreats_filename}")) { + if ($pkg_interface <> "console") { + update_status(gettext("Extracting {$et_name} rules...")); + update_output_window(gettext("Installing {$et_name} rules...")); + } + error_log(gettext("\tExtracting and installing {$et_name} rules...\n"), 3, $suricata_rules_upd_log); + exec("/usr/bin/tar xzf {$tmpfname}/{$emergingthreats_filename} -C {$tmpfname}/emerging rules/"); + + /* Remove the old Emerging Threats rules files */ + $eto_prefix = ET_OPEN_FILE_PREFIX; + $etpro_prefix = ET_PRO_FILE_PREFIX; + array_map('unlink', glob("{$suricatadir}rules/{$eto_prefix}*.rules")); + array_map('unlink', glob("{$suricatadir}rules/{$etpro_prefix}*.rules")); + array_map('unlink', glob("{$suricatadir}rules/{$eto_prefix}*ips.txt")); + array_map('unlink', glob("{$suricatadir}rules/{$etpro_prefix}*ips.txt")); + + // The code below renames ET-Pro files with a prefix, so we + // skip renaming the Suricata default events rule files + // that are also bundled in the ET-Pro rules. + $default_rules = array( "decoder-events.rules", "files.rules", "http-events.rules", "smtp-events.rules", "stream-events.rules" ); + $files = glob("{$tmpfname}/emerging/rules/*.rules"); + foreach ($files as $file) { + $newfile = basename($file); + if ($etpro == "on" && !in_array($newfile, $default_rules)) + @copy($file, "{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "{$newfile}"); + else + @copy($file, "{$suricatadir}rules/{$newfile}"); + } + /* IP lists for Emerging Threats rules */ + $files = glob("{$tmpfname}/emerging/rules/*ips.txt"); + foreach ($files as $file) { + $newfile = basename($file); + if ($etpro == "on") + @copy($file, "{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "{$newfile}"); + else + @copy($file, "{$suricatadir}rules/" . ET_OPEN_FILE_PREFIX . "{$newfile}"); + } + /* base etc files for Emerging Threats rules */ + foreach (array("classification.config", "reference.config", "gen-msg.map", "unicode.map") as $file) { + if (file_exists("{$tmpfname}/emerging/rules/{$file}")) + @copy("{$tmpfname}/emerging/rules/{$file}", "{$tmpfname}/ET_{$file}"); + } + + /* Copy emergingthreats md5 sig to Suricata dir */ + if (file_exists("{$tmpfname}/{$emergingthreats_filename_md5}")) { + if ($pkg_interface <> "console") + update_status(gettext("Copying md5 signature to Suricata directory...")); + @copy("{$tmpfname}/{$emergingthreats_filename_md5}", "{$suricatadir}{$emergingthreats_filename_md5}"); + } + if ($pkg_interface <> "console") { + update_status(gettext("Extraction of {$et_name} rules completed...")); + update_output_window(gettext("Installation of {$et_name} rules completed...")); + } + error_log(gettext("\tInstallation of {$et_name} rules completed.\n"), 3, $suricata_rules_upd_log); + exec("rm -r {$tmpfname}/emerging"); + } +} + +/* Untar Snort rules file to tmp */ +if ($snortdownload == 'on') { + if (file_exists("{$tmpfname}/{$snort_filename}")) { + /* Remove the old Snort rules files */ + $vrt_prefix = VRT_FILE_PREFIX; + array_map('unlink', glob("{$suricatadir}rules/{$vrt_prefix}*.rules")); + + if ($pkg_interface <> "console") { + update_status(gettext("Extracting Snort VRT rules...")); + update_output_window(gettext("Installing Sourcefire VRT rules...")); + } + error_log(gettext("\tExtracting and installing Snort VRT rules...\n"), 3, $suricata_rules_upd_log); + + /* extract snort.org rules and add prefix to all snort.org files */ + safe_mkdir("{$tmpfname}/snortrules"); + exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname}/snortrules rules/"); + $files = glob("{$tmpfname}/snortrules/rules/*.rules"); + foreach ($files as $file) { + $newfile = basename($file); + @copy($file, "{$suricatadir}rules/" . VRT_FILE_PREFIX . "{$newfile}"); + } + + /* IP lists */ + $files = glob("{$tmpfname}/snortrules/rules/*.txt"); + foreach ($files as $file) { + $newfile = basename($file); + @copy($file, "{$suricatadir}rules/{$newfile}"); + } + exec("rm -r {$tmpfname}/snortrules"); + + /* extract base etc files */ + if ($pkg_interface <> "console") { + update_status(gettext("Extracting Snort VRT config and map files...")); + update_output_window(gettext("Copying config and map files...")); + } + exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$tmpfname} etc/"); + foreach (array("classification.config", "reference.config", "gen-msg.map", "unicode.map") as $file) { + if (file_exists("{$tmpfname}/etc/{$file}")) + @copy("{$tmpfname}/etc/{$file}", "{$tmpfname}/VRT_{$file}"); + } + exec("rm -r {$tmpfname}/etc"); + if (file_exists("{$tmpfname}/{$snort_filename_md5}")) { + if ($pkg_interface <> "console") + update_status(gettext("Copying md5 signature to Suricata directory...")); + @copy("{$tmpfname}/{$snort_filename_md5}", "{$suricatadir}{$snort_filename_md5}"); + } + if ($pkg_interface <> "console") { + update_status(gettext("Extraction of Snort VRT rules completed...")); + update_output_window(gettext("Installation of Sourcefire VRT rules completed...")); + } + error_log(gettext("\tInstallation of Snort VRT rules completed.\n"), 3, $suricata_rules_upd_log); + } +} + +/* Untar Snort GPLv2 Community rules file to tmp */ +if ($snortcommunityrules == 'on') { + safe_mkdir("{$tmpfname}/community"); + if (file_exists("{$tmpfname}/{$snort_community_rules_filename}")) { + if ($pkg_interface <> "console") { + update_status(gettext("Extracting Snort GPLv2 Community Rules...")); + update_output_window(gettext("Installing Snort GPLv2 Community Rules...")); + } + error_log(gettext("\tExtracting and installing Snort GPLv2 Community Rules...\n"), 3, $suricata_rules_upd_log); + exec("/usr/bin/tar xzf {$tmpfname}/{$snort_community_rules_filename} -C {$tmpfname}/community/"); + + $files = glob("{$tmpfname}/community/community-rules/*.rules"); + foreach ($files as $file) { + $newfile = basename($file); + @copy($file, "{$suricatadir}rules/" . GPL_FILE_PREFIX . "{$newfile}"); + } + /* base etc files for Snort GPLv2 Community rules */ + foreach (array("classification.config", "reference.config", "gen-msg.map", "unicode.map") as $file) { + if (file_exists("{$tmpfname}/community/community-rules/{$file}")) + @copy("{$tmpfname}/community/community-rules/{$file}", "{$tmpfname}/" . GPL_FILE_PREFIX . "{$file}"); + } + /* Copy snort community md5 sig to suricata dir */ + if (file_exists("{$tmpfname}/{$snort_community_rules_filename_md5}")) { + if ($pkg_interface <> "console") + update_status(gettext("Copying md5 signature to suricata directory...")); + @copy("{$tmpfname}/{$snort_community_rules_filename_md5}", "{$suricatadir}{$snort_community_rules_filename_md5}"); + } + if ($pkg_interface <> "console") { + update_status(gettext("Extraction of Snort GPLv2 Community Rules completed...")); + update_output_window(gettext("Installation of Snort GPLv2 Community Rules file completed...")); + } + error_log(gettext("\tInstallation of Snort GPLv2 Community Rules completed.\n"), 3, $suricata_rules_upd_log); + exec("rm -r {$tmpfname}/community"); + } +} + +function suricata_apply_customizations($suricatacfg, $if_real) { + + global $vrt_enabled, $rebuild_rules; + $suricatadir = SURICATADIR; + + suricata_prepare_rule_files($suricatacfg, "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}"); + + /* Copy the master config and map files to the interface directory */ + @copy("{$suricatadir}classification.config", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/classification.config"); + @copy("{$suricatadir}reference.config", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/reference.config"); + @copy("{$suricatadir}gen-msg.map", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/gen-msg.map"); + @copy("{$suricatadir}unicode.map", "{$suricatadir}suricata_{$suricatacfg['uuid']}_{$if_real}/unicode.map"); +} + +if ($snortdownload == 'on' || $emergingthreats == 'on' || $snortcommunityrules == 'on') { + + if ($pkg_interface <> "console") + update_status(gettext('Copying new config and map files...')); + error_log(gettext("\tCopying new config and map files...\n"), 3, $suricata_rules_upd_log); + + /******************************************************************/ + /* Build the classification.config and reference.config files */ + /* using the ones from all the downloaded rules plus the default */ + /* files installed with Suricata. */ + /******************************************************************/ + $cfgs = glob("{$tmpfname}/*reference.config"); + $cfgs[] = "{$suricatadir}reference.config"; + suricata_merge_reference_configs($cfgs, "{$suricatadir}reference.config"); + $cfgs = glob("{$tmpfname}/*classification.config"); + $cfgs[] = "{$suricatadir}classification.config"; + suricata_merge_classification_configs($cfgs, "{$suricatadir}classification.config"); + + /* Determine which map files to use for the master copy. */ + /* The Snort VRT ones are preferred, if available. */ + if ($snortdownload == 'on') + $prefix = "VRT_"; + elseif ($emergingthreats == 'on') + $prefix = "ET_"; + elseif ($snortcommunityrules == 'on') + $prefix = GPL_FILE_PREFIX; + if (file_exists("{$tmpfname}/{$prefix}unicode.map")) + @copy("{$tmpfname}/{$prefix}unicode.map", "{$suricatadir}unicode.map"); + if (file_exists("{$tmpfname}/{$prefix}gen-msg.map")) + @copy("{$tmpfname}/{$prefix}gen-msg.map", "{$suricatadir}gen-msg.map"); + + /* Start the rules rebuild proccess for each configured interface */ + if (is_array($config['installedpackages']['suricata']['rule']) && + !empty($config['installedpackages']['suricata']['rule'])) { + + /* Set the flag to force rule rebuilds since we downloaded new rules */ + $rebuild_rules = true; + + /* Create configuration for each active Suricata interface */ + foreach ($config['installedpackages']['suricata']['rule'] as $value) { + $if_real = suricata_get_real_interface($value['interface']); + // Make sure the interface subdirectory exists. We need to re-create + // it during a pkg reinstall on the intial rules set download. + if (!is_dir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}")) + safe_mkdir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}"); + if (!is_dir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}/rules")) + safe_mkdir("{$suricatadir}suricata_{$value['uuid']}_{$if_real}/rules"); + $tmp = "Updating rules configuration for: " . suricata_get_friendly_interface($value['interface']) . " ..."; + if ($pkg_interface <> "console"){ + update_status(gettext($tmp)); + update_output_window(gettext("Please wait while Suricata interface files are being updated...")); + } + suricata_apply_customizations($value, $if_real); + $tmp = "\t" . $tmp . "\n"; + error_log($tmp, 3, $suricata_rules_upd_log); + } + } + else { + if ($pkg_interface <> "console") { + update_output_window(gettext("Warning: No interfaces configured for Suricata were found...")); + update_output_window(gettext("No interfaces currently have Suricata configured and enabled on them...")); + } + error_log(gettext("\tWarning: No interfaces configured for Suricata were found...\n"), 3, $suricata_rules_upd_log); + } + + /* Clear the rebuild rules flag. */ + $rebuild_rules = false; + + /* Restart Suricata if already running and we are not rebooting to pick up the new rules. */ + if (is_process_running("suricata") && !$g['booting']) { + if ($pkg_interface <> "console") { + update_status(gettext('Restarting Suricata to activate the new set of rules...')); + update_output_window(gettext("Please wait ... restarting Suricata will take some time...")); + } + error_log(gettext("\tRestarting Suricata to activate the new set of rules...\n"), 3, $suricata_rules_upd_log); + restart_service("suricata"); + if ($pkg_interface <> "console") + update_output_window(gettext("Suricata has restarted with your new set of rules...")); + log_error(gettext("[Suricata] Suricata has restarted with your new set of rules...")); + error_log(gettext("\tSuricata has restarted with your new set of rules.\n"), 3, $suricata_rules_upd_log); + } + else { + if ($pkg_interface <> "console") + update_output_window(gettext("The rules update task is complete...")); + } +} + +// Remove old $tmpfname files +if (is_dir("{$tmpfname}")) { + if ($pkg_interface <> "console") + update_status(gettext("Cleaning up after rules extraction...")); + exec("/bin/rm -r {$tmpfname}"); +} + +if ($pkg_interface <> "console") + update_status(gettext("The Rules update has finished...")); +log_error(gettext("[Suricata] The Rules update has finished.")); +error_log(gettext("The Rules update has finished. Time: " . date("Y-m-d H:i:s"). "\n\n"), 3, $suricata_rules_upd_log); +conf_mount_ro(); + +// Restore the state of $pkg_interface +$pkg_interface = $pkg_interface_orig; + +?> diff --git a/config/suricata/suricata_define_vars.php b/config/suricata/suricata_define_vars.php new file mode 100644 index 00000000..05378477 --- /dev/null +++ b/config/suricata/suricata_define_vars.php @@ -0,0 +1,290 @@ + "\$HOME_NET", "smtp_servers" => "\$HOME_NET", "http_servers" => "\$HOME_NET", + "sql_servers" => "\$HOME_NET", "telnet_servers" => "\$HOME_NET", "dnp3_server" => "\$HOME_NET", + "dnp3_client" => "\$HOME_NET", "modbus_server" => "\$HOME_NET", "modbus_client" => "\$HOME_NET", + "enip_server" => "\$HOME_NET", "enip_client" => "\$HOME_NET", + "aim_servers" => "64.12.24.0/23,64.12.28.0/23,64.12.161.0/24,64.12.163.0/24,64.12.200.0/24,205.188.3.0/24,205.188.5.0/24,205.188.7.0/24,205.188.9.0/24,205.188.153.0/24,205.188.179.0/24,205.188.248.0/24" +); + +/* if user has defined a custom ssh port, use it */ +if(is_array($config['system']['ssh']) && isset($config['system']['ssh']['port'])) + $ssh_port = $config['system']['ssh']['port']; +else + $ssh_port = "22"; +$suricata_ports = array( + "http_ports" => "80", + "oracle_ports" => "1521", + "ssh_ports" => $ssh_port, + "shellcode_ports" => "!80", + "DNP3_PORTS" => "20000", "file_data_ports" => "\$HTTP_PORTS,110,143" +); + +// Sort our SERVERS and PORTS arrays to make values +// easier to locate by the the user. +ksort($suricata_servers); +ksort($suricata_ports); + +$pconfig = $a_nat[$id]; + +/* convert fake interfaces to real */ +$if_real = suricata_get_real_interface($pconfig['interface']); +$suricata_uuid = $config['installedpackages']['suricata']['rule'][$id]['uuid']; + +if ($_POST) { + + $natent = array(); + $natent = $pconfig; + + foreach ($suricata_servers as $key => $server) { + if ($_POST["def_{$key}"] && !is_alias($_POST["def_{$key}"])) + $input_errors[] = "Only aliases are allowed"; + } + foreach ($suricata_ports as $key => $server) { + if ($_POST["def_{$key}"] && !is_alias($_POST["def_{$key}"])) + $input_errors[] = "Only aliases are allowed"; + } + /* if no errors write to suricata.yaml */ + if (!$input_errors) { + /* post new options */ + foreach ($suricata_servers as $key => $server) { + if ($_POST["def_{$key}"]) + $natent["def_{$key}"] = $_POST["def_{$key}"]; + else + unset($natent["def_{$key}"]); + } + foreach ($suricata_ports as $key => $server) { + if ($_POST["def_{$key}"]) + $natent["def_{$key}"] = $_POST["def_{$key}"]; + else + unset($natent["def_{$key}"]); + } + + $a_nat[$id] = $natent; + + write_config(); + + /* Update the suricata.yaml file for this interface. */ + $rebuild_rules = false; + suricata_generate_yaml($a_nat[$id]); + + /* Soft-restart Suricaa to live-load new variables. */ + suricata_reload_config($a_nat[$id]); + + /* after click go to this page */ + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: suricata_define_vars.php?id=$id"); + exit; + } +} + +$if_friendly = suricata_get_friendly_interface($pconfig['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} Variables - Servers and Ports"); +include_once("head.inc"); + +?> + + +' . $pgtitle . '

';} +/* Display Alert message */ +if ($input_errors) + print_input_errors($input_errors); // TODO: add checks +if ($savemsg) + print_info_box($savemsg); +?> + + + +
+ +'; + echo ' + + +
+
'; + $tab_array = array(); + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface "); + $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), false, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), false, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), false, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), true, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + display_top_tabs($tab_array); +?> +
+ + + + + $server): + if (strlen($server) > 40) + $server = substr($server, 0, 40) . "..."; + $label = strtoupper($key); + $value = ""; + $title = ""; + if (!empty($pconfig["def_{$key}"])) { + $value = htmlspecialchars($pconfig["def_{$key}"]); + $title = trim(filter_expand_alias($pconfig["def_{$key}"])); + } +?> + + + + + + + + + $server): + if (strlen($server) > 40) + $server = substr($server, 0, 40) . "..."; + $label = strtoupper($key); + $value = ""; + $title = ""; + if (!empty($pconfig["def_{$key}"])) { + $value = htmlspecialchars($pconfig["def_{$key}"]); + $title = trim(filter_expand_alias($pconfig["def_{$key}"])); + } +?> + + + + + + + + + +
+
+ ""
+
+
+ ""
+
  + + +
+
+
+
+ + + + + diff --git a/config/suricata/suricata_download_rules.php b/config/suricata/suricata_download_rules.php new file mode 100644 index 00000000..26737dcf --- /dev/null +++ b/config/suricata/suricata_download_rules.php @@ -0,0 +1,97 @@ + + + + + +' . $pgtitle . '

';}?> + +
+ + + + + +
+ + + + + + + + + + +
+ + + + + + +
+ + + +
/images/misc/bar_blue.gif' + width='0' height='15' name='progressbar' id='progressbar' alt='' />
+
+ + + + +
+
+
+
+ + + +document.progressbar.style.visibility='hidden';\n"; + +?> diff --git a/config/suricata/suricata_download_updates.php b/config/suricata/suricata_download_updates.php new file mode 100644 index 00000000..8ff30e9b --- /dev/null +++ b/config/suricata/suricata_download_updates.php @@ -0,0 +1,241 @@ + + + + + +' . $pgtitle . '

';}?> + + + +
+ + + + + + +
+ +
+
+ + + + +
+
+ + + + +
+
+

+ +

+   --> +   
+ SNORT VRT RULES  --> +   
+ SNORT GPLv2 COMMUNITY RULES  --> +   
+

+
+
+
+ + + + +
+
+

+
+
+ + ' . gettext("Update Rules") . '
+

+ ' . gettext("WARNING:") . '  ' . gettext('No rule types have been selected for download. ') . + gettext('Visit the ') . 'Global Settings Tab' . gettext(' to select rule types.') . '
'; + + echo '

' . "\n"; + } else { + + echo ' +
' . "\n"; + + } + + ?>
+

+
+
+
+ + + + +
+
+

+
+
+ " . gettext("View Log") . ""; + echo "          \n"; + }else{ + echo " +    " . gettext("Log is empty.") . "\n"; + } + echo '

' . gettext("The log file is limited to 1024K in size and automatically clears when the limit is exceeded."); + ?> +
+

+
+
+ +
+ + + + + +
+
+ +   " . + gettext(" and ") . "" . gettext("EmergingThreats.net") . "" . + gettext(" will go down from time to time. Please be patient."); ?> +
+
+ +
+
+
+
+ +
+ + + diff --git a/config/suricata/suricata_flow_stream.php b/config/suricata/suricata_flow_stream.php new file mode 100644 index 00000000..8db40a47 --- /dev/null +++ b/config/suricata/suricata_flow_stream.php @@ -0,0 +1,680 @@ + "default", "bind_to" => "all", "policy" => "bsd" ); + $pconfig['host_os_policy']['item'] = array(); + $pconfig['host_os_policy']['item'][] = $default; + if (!is_array($a_nat[$id]['host_os_policy']['item'])) + $a_nat[$id]['host_os_policy']['item'] = array(); + $a_nat[$id]['host_os_policy']['item'][] = $default; + write_config(); + $host_os_policy_engine_next_id++; + } + else + $pconfig['host_os_policy'] = $a_nat[$id]['host_os_policy']; +} + +// Check for returned "selected alias" if action is import +if ($_GET['act'] == "import" && isset($_GET['varname']) && !empty($_GET['varvalue'])) { + $pconfig[$_GET['varname']] = $_GET['varvalue']; +} + +if ($_GET['act'] && isset($_GET['eng_id'])) { + + $natent = array(); + $natent = $pconfig; + + if ($_GET['act'] == "del_host_os_policy") + unset($natent['host_os_policy']['item'][$_GET['eng_id']]); + + if (isset($id) && $a_nat[$id]) { + $a_nat[$id] = $natent; + write_config(); + } + + header("Location: /suricata/suricata_flow_stream.php?id=$id"); + exit; +} + +if ($_POST['ResetAll']) { + + /* Reset all the settings to defaults */ + $pconfig['ip_max_frags'] = "65535"; + $pconfig['ip_frag_timeout'] = "60"; + $pconfig['frag_memcap'] = '33554432'; + $pconfig['ip_max_trackers'] = '65535'; + $pconfig['frag_hash_size'] = '65536'; + + $pconfig['flow_memcap'] = '33554432'; + $pconfig['flow_prealloc'] = '10000'; + $pconfig['flow_hash_size'] = '65536'; + $pconfig['flow_emerg_recovery'] = '30'; + $pconfig['flow_prune'] = '5'; + + $pconfig['flow_tcp_new_timeout'] = '60'; + $pconfig['flow_tcp_established_timeout'] = '3600'; + $pconfig['flow_tcp_closed_timeout'] = '120'; + $pconfig['flow_tcp_emerg_new_timeout'] = '10'; + $pconfig['flow_tcp_emerg_established_timeout'] = '300'; + $pconfig['flow_tcp_emerg_closed_timeout'] = '20'; + + $pconfig['flow_udp_new_timeout'] = '30'; + $pconfig['flow_udp_established_timeout'] = '300'; + $pconfig['flow_udp_emerg_new_timeout'] = '10'; + $pconfig['flow_udp_emerg_established_timeout'] = '100'; + + $pconfig['flow_icmp_new_timeout'] = '30'; + $pconfig['flow_icmp_established_timeout'] = '300'; + $pconfig['flow_icmp_emerg_new_timeout'] = '10'; + $pconfig['flow_icmp_emerg_established_timeout'] = '100'; + + $pconfig['stream_memcap'] = '33554432'; + $pconfig['stream_max_sessions'] = '262144'; + $pconfig['stream_prealloc_sessions'] = '32768'; + $pconfig['reassembly_memcap'] = '67108864'; + $pconfig['reassembly_depth'] = '1048576'; + $pconfig['reassembly_to_server_chunk'] = '2560'; + $pconfig['reassembly_to_client_chunk'] = '2560'; + $pconfig['enable_midstream_sessions'] = 'off'; + $pconfig['enable_async_sessions'] = 'off'; + + /* Log a message at the top of the page to inform the user */ + $savemsg = gettext("All flow and stream settings have been reset to their defaults."); +} +elseif ($_POST['Submit']) { + $natent = array(); + $natent = $pconfig; + + // TODO: validate input values + + /* if no errors write to conf */ + if (!$input_errors) { + if ($_POST['ip_max_frags'] != "") { $natent['ip_max_frags'] = $_POST['ip_max_frags']; }else{ $natent['ip_max_frags'] = "65535"; } + if ($_POST['ip_frag_timeout'] != "") { $natent['ip_frag_timeout'] = $_POST['ip_frag_timeout']; }else{ $natent['ip_frag_timeout'] = "60"; } + if ($_POST['frag_memcap'] != "") { $natent['frag_memcap'] = $_POST['frag_memcap']; }else{ $natent['frag_memcap'] = "33554432"; } + if ($_POST['ip_max_trackers'] != "") { $natent['ip_max_trackers'] = $_POST['ip_max_trackers']; }else{ $natent['ip_max_trackers'] = "65535"; } + if ($_POST['frag_hash_size'] != "") { $natent['frag_hash_size'] = $_POST['frag_hash_size']; }else{ $natent['frag_hash_size'] = "65536"; } + if ($_POST['flow_memcap'] != "") { $natent['flow_memcap'] = $_POST['flow_memcap']; }else{ $natent['flow_memcap'] = "33554432"; } + if ($_POST['flow_prealloc'] != "") { $natent['flow_prealloc'] = $_POST['flow_prealloc']; }else{ $natent['flow_prealloc'] = "10000"; } + if ($_POST['flow_hash_size'] != "") { $natent['flow_hash_size'] = $_POST['flow_hash_size']; }else{ $natent['flow_hash_size'] = "65536"; } + if ($_POST['flow_emerg_recovery'] != "") { $natent['flow_emerg_recovery'] = $_POST['flow_emerg_recovery']; }else{ $natent['flow_emerg_recovery'] = "30"; } + if ($_POST['flow_prune'] != "") { $natent['flow_prune'] = $_POST['flow_prune']; }else{ $natent['flow_prune'] = "5"; } + + if ($_POST['flow_tcp_new_timeout'] != "") { $natent['flow_tcp_new_timeout'] = $_POST['flow_tcp_new_timeout']; }else{ $natent['flow_tcp_new_timeout'] = "60"; } + if ($_POST['flow_tcp_established_timeout'] != "") { $natent['flow_tcp_established_timeout'] = $_POST['flow_tcp_established_timeout']; }else{ $natent['flow_tcp_established_timeout'] = "3600"; } + if ($_POST['flow_tcp_closed_timeout'] != "") { $natent['flow_tcp_closed_timeout'] = $_POST['flow_tcp_closed_timeout']; }else{ $natent['flow_tcp_closed_timeout'] = "120"; } + if ($_POST['flow_tcp_emerg_new_timeout'] != "") { $natent['flow_tcp_emerg_new_timeout'] = $_POST['flow_tcp_emerg_new_timeout']; }else{ $natent['flow_tcp_emerg_new_timeout'] = "10"; } + if ($_POST['flow_tcp_emerg_established_timeout'] != "") { $natent['flow_tcp_emerg_established_timeout'] = $_POST['flow_tcp_emerg_established_timeout']; }else{ $natent['flow_tcp_emerg_established_timeout'] = "300"; } + if ($_POST['flow_tcp_emerg_closed_timeout'] != "") { $natent['flow_tcp_emerg_closed_timeout'] = $_POST['flow_tcp_emerg_closed_timeout']; }else{ $natent['flow_tcp_emerg_closed_timeout'] = "20"; } + + if ($_POST['flow_udp_new_timeout'] != "") { $natent['flow_udp_new_timeout'] = $_POST['flow_udp_new_timeout']; }else{ $natent['flow_udp_new_timeout'] = "30"; } + if ($_POST['flow_udp_established_timeout'] != "") { $natent['flow_udp_established_timeout'] = $_POST['flow_udp_established_timeout']; }else{ $natent['flow_udp_established_timeout'] = "300"; } + if ($_POST['flow_udp_emerg_new_timeout'] != "") { $natent['flow_udp_emerg_new_timeout'] = $_POST['flow_udp_emerg_new_timeout']; }else{ $natent['flow_udp_emerg_new_timeout'] = "10"; } + if ($_POST['flow_udp_emerg_established_timeout'] != "") { $natent['flow_udp_emerg_established_timeout'] = $_POST['flow_udp_emerg_established_timeout']; }else{ $natent['flow_udp_emerg_established_timeout'] = "100"; } + + if ($_POST['flow_icmp_new_timeout'] != "") { $natent['flow_icmp_new_timeout'] = $_POST['flow_icmp_new_timeout']; }else{ $natent['flow_icmp_new_timeout'] = "30"; } + if ($_POST['flow_icmp_established_timeout'] != "") { $natent['flow_icmp_established_timeout'] = $_POST['flow_icmp_established_timeout']; }else{ $natent['flow_icmp_established_timeout'] = "300"; } + if ($_POST['flow_icmp_emerg_new_timeout'] != "") { $natent['flow_icmp_emerg_new_timeout'] = $_POST['flow_icmp_emerg_new_timeout']; }else{ $natent['flow_icmp_emerg_new_timeout'] = "10"; } + if ($_POST['flow_icmp_emerg_established_timeout'] != "") { $natent['flow_icmp_emerg_established_timeout'] = $_POST['flow_icmp_emerg_established_timeout']; }else{ $natent['flow_icmp_emerg_established_timeout'] = "100"; } + + if ($_POST['stream_memcap'] != "") { $natent['stream_memcap'] = $_POST['stream_memcap']; }else{ $natent['stream_memcap'] = "33554432"; } + if ($_POST['stream_max_sessions'] != "") { $natent['stream_max_sessions'] = $_POST['stream_max_sessions']; }else{ $natent['stream_max_sessions'] = "262144"; } + if ($_POST['stream_prealloc_sessions'] != "") { $natent['stream_prealloc_sessions'] = $_POST['stream_prealloc_sessions']; }else{ $natent['stream_prealloc_sessions'] = "32768"; } + if ($_POST['enable_midstream_sessions'] == "on") { $natent['enable_midstream_sessions'] = 'on'; }else{ $natent['enable_midstream_sessions'] = 'off'; } + if ($_POST['enable_async_sessions'] == "on") { $natent['enable_async_sessions'] = 'on'; }else{ $natent['enable_async_sessions'] = 'off'; } + if ($_POST['reassembly_memcap'] != "") { $natent['reassembly_memcap'] = $_POST['reassembly_memcap']; }else{ $natent['reassembly_memcap'] = "67108864"; } + if ($_POST['reassembly_depth'] != "") { $natent['reassembly_depth'] = $_POST['reassembly_depth']; }else{ $natent['reassembly_depth'] = "1048576"; } + if ($_POST['reassembly_to_server_chunk'] != "") { $natent['reassembly_to_server_chunk'] = $_POST['reassembly_to_server_chunk']; }else{ $natent['reassembly_to_server_chunk'] = "2560"; } + if ($_POST['reassembly_to_client_chunk'] != "") { $natent['reassembly_to_client_chunk'] = $_POST['reassembly_to_client_chunk']; }else{ $natent['reassembly_to_client_chunk'] = "2560"; } + + /**************************************************/ + /* If we have a valid rule ID, save configuration */ + /* then update the suricata.conf file and rebuild */ + /* the rules for this interface. */ + /**************************************************/ + if (isset($id) && $a_nat[$id]) { + $a_nat[$id] = $natent; + write_config(); + $rebuild_rules = true; + suricata_generate_yaml($natent); + $rebuild_rules = false; + } + + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: suricata_flow_stream.php?id=$id"); + exit; + } +} + +$if_friendly = suricata_get_friendly_interface($pconfig['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} - Flow and Stream"); +include_once("head.inc"); +?> + + + +' . $pgtitle . '

';} + + + /* Display Alert message */ + + if ($input_errors) { + print_input_errors($input_errors); // TODO: add checks + } + + if ($savemsg) { + print_info_box($savemsg); + } + +?> + + + + +
+ +'; + echo ' +
+
'; + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface "); + $tab_array = array(); + $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), false, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), false, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), true, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + display_top_tabs($tab_array); +?> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + + + + + + + + + + + $v): ?> + + + + + + +
+ "> + + ">
+ "> + "all") : ?> + + "> + + "> + +
+
+   + " . gettext("33,554,432") . "" . gettext(" bytes (32 MB)."); ?>

+ +
  + " . gettext("65,535") . "" . gettext(" fragments.");?>

+ +
  + " . gettext("65,535") . "" . gettext(" fragments.");?>

+

+ " . gettext("This must be equal to or greater than the Max Trackers value specified above."); ?> +
+   + " . gettext("65,536") . "" . gettext(" entries."); ?>

+ +
  + " . gettext("60") . "" . gettext(" seconds.");?>

+ +
+   + " . gettext("33,554,432") . "" . gettext(" bytes (32 MB)"); ?> +
+   + " . gettext("65,536") . "" . gettext(" entries."); ?> +
+   + " . gettext("10,000") . "" . gettext(" flows."); ?> +
+   + " . gettext("30%") . "."; ?> +
+   + " . gettext("5") . "" . gettext(" flows."); ?> +
+ + + + + + + + + + + + + + + + + + + +
  + " . gettext("60") . "."; ?> +
  + " . gettext("3600") . "."; ?> +
  + " . gettext("120") . "."; ?> +
  + " . gettext("10") . "."; ?> +
  + " . gettext("300") . "."; ?> +
  + " . gettext("20") . "."; ?> +
+
+ + + + + + + + + + + + + +
  + " . gettext("30") . "."; ?> +
  + " . gettext("300") . "."; ?> +
  + " . gettext("10") . "."; ?> +
  + " . gettext("100") . "."; ?> +
+
+ + + + + + + + + + + + + +
  + " . gettext("30") . "."; ?> +
  + " . gettext("300") . "."; ?> +
  + " . gettext("10") . "."; ?> +
  + " . gettext("100") . "."; ?> +
+
+   + " . gettext("33,554,432") . "" . gettext(" bytes (32MB)"); ?>

+ +
+   + " . gettext("262,144") . "" . gettext(" sessions."); ?>

+ +
+   + " . gettext("32,768") . "" . gettext(" sessions."); ?>

+ +
> + " . gettext("Not Checked") . "."; ?>
> + " . gettext("Not Checked") . "."; ?>
+   + " . gettext("67,108,864") . "" . gettext(" bytes (64MB)."); ?>

+ +
+   + " . gettext("1,048,576") . "" . gettext(" bytes (1MB)."); ?>

+ " . + "" . gettext("Note: ") . "" . gettext("Set to 0 (unlimited) to reassemble entire stream. This is required for file extraction."); ?> +
+   + " . gettext("2,560") . "" . gettext(" bytes."); ?>

+ +
+   + " . gettext("2,560") . "" . gettext(" bytes."); ?>

+ +
  + "> +      + >
  + +
+
+
+
+ + + + diff --git a/config/suricata/suricata_generate_yaml.php b/config/suricata/suricata_generate_yaml.php new file mode 100644 index 00000000..0614adf8 --- /dev/null +++ b/config/suricata/suricata_generate_yaml.php @@ -0,0 +1,515 @@ + "\$HOME_NET", "smtp_servers" => "\$HOME_NET", "http_servers" => "\$HOME_NET", + "sql_servers" => "\$HOME_NET", "telnet_servers" => "\$HOME_NET", "dnp3_server" => "\$HOME_NET", + "dnp3_client" => "\$HOME_NET", "modbus_server" => "\$HOME_NET", "modbus_client" => "\$HOME_NET", + "enip_server" => "\$HOME_NET", "enip_client" => "\$HOME_NET", + "aim_servers" => "64.12.24.0/23,64.12.28.0/23,64.12.161.0/24,64.12.163.0/24,64.12.200.0/24,205.188.3.0/24,205.188.5.0/24,205.188.7.0/24,205.188.9.0/24,205.188.153.0/24,205.188.179.0/24,205.188.248.0/24" +); +$addr_vars = ""; + foreach ($suricata_servers as $alias => $avalue) { + if (!empty($suricatacfg["def_{$alias}"]) && is_alias($suricatacfg["def_{$alias}"])) { + $avalue = trim(filter_expand_alias($suricatacfg["def_{$alias}"])); + $avalue = preg_replace('/\s+/', ',', trim($avalue)); + } + $addr_vars .= " " . strtoupper($alias) . ": \"{$avalue}\"\n"; + } +$addr_vars = trim($addr_vars); +if(is_array($config['system']['ssh']) && isset($config['system']['ssh']['port'])) + $ssh_port = $config['system']['ssh']['port']; +else + $ssh_port = "22"; +$suricata_ports = array( + "http_ports" => "80", + "oracle_ports" => "1521", + "ssh_ports" => $ssh_port, + "shellcode_ports" => "!80", + "DNP3_PORTS" => "20000", "file_data_ports" => "\$HTTP_PORTS,110,143" +); +$port_vars = ""; + foreach ($suricata_ports as $alias => $avalue) { + if (!empty($suricatacfg["def_{$alias}"]) && is_alias($suricatacfg["def_{$alias}"])) { + $avalue = trim(filter_expand_alias($suricatacfg["def_{$alias}"])); + $avalue = preg_replace('/\s+/', ',', trim($avalue)); + } + $port_vars .= " " . strtoupper($alias) . ": \"{$avalue}\"\n"; + } +$port_vars = trim($port_vars); + +// Define a Suppress List (Threshold) if one is configured +$suppress = suricata_find_list($suricatacfg['suppresslistname'], 'suppress'); +if (!empty($suppress)) { + $suppress_data = str_replace("\r", "", base64_decode($suppress['suppresspassthru'])); + @file_put_contents("{$suricatacfgdir}/threshold.config", $suppress_data); +} +else + @file_put_contents("{$suricatacfgdir}/threshold.config", ""); + +// Add interface-specific detection engine settings +if (!empty($suricatacfg['max_pending_packets'])) + $max_pend_pkts = $suricatacfg['max_pending_packets']; +else + $max_pend_pkts = 1024; + +if (!empty($suricatacfg['detect_eng_profile'])) + $detect_eng_profile = $suricatacfg['detect_eng_profile']; +else + $detect_eng_profile = "medium"; + +if (!empty($suricatacfg['sgh_mpm_context'])) + $sgh_mpm_ctx = $suricatacfg['sgh_mpm_context']; +else + $sgh_mpm_ctx = "auto"; + +if (!empty($suricatacfg['mpm_algo'])) + $mpm_algo = $suricatacfg['mpm_algo']; +else + $mpm_algo = "ac"; + +if (!empty($suricatacfg['inspect_recursion_limit']) || $suricatacfg['inspect_recursion_limit'] == '0') + $inspection_recursion_limit = $suricatacfg['inspect_recursion_limit']; +else + $inspection_recursion_limit = ""; + +// Add interface-specific logging settings +if ($suricatacfg['alertsystemlog'] == 'on') + $alert_syslog = "yes"; +else + $alert_syslog = "no"; + +if ($suricatacfg['enable_stats_log'] == 'on') + $stats_log_enabled = "yes"; +else + $stats_log_enabled = "no"; + +if (!empty($suricatacfg['stats_upd_interval'])) + $stats_upd_interval = $suricatacfg['stats_upd_interval']; +else + $stats_upd_interval = "10"; + +if ($suricatacfg['append_stats_log'] == 'on') + $stats_log_append = "yes"; +else + $stats_log_append = "no"; + +if ($suricatacfg['enable_http_log'] == 'on') + $http_log_enabled = "yes"; +else + $http_log_enabled = "no"; + +if ($suricatacfg['append_http_log'] == 'on') + $http_log_append = "yes"; +else + $http_log_append = "no"; + +if ($suricatacfg['enable_tls_log'] == 'on') + $tls_log_enabled = "yes"; +else + $tls_log_enabled = "no"; + +if ($suricatacfg['tls_log_extended'] == 'on') + $tls_log_extended = "yes"; +else + $tls_log_extended = "no"; + +if ($suricatacfg['enable_json_file_log'] == 'on') + $json_log_enabled = "yes"; +else + $json_log_enabled = "no"; + +if ($suricatacfg['append_json_file_log'] == 'on') + $json_log_append = "yes"; +else + $json_log_append = "no"; + +if ($suricatacfg['enable_tracked_files_magic'] == 'on') + $json_log_magic = "yes"; +else + $json_log_magic = "no"; + +if ($suricatacfg['enable_tracked_files_md5'] == 'on') + $json_log_md5 = "yes"; +else + $json_log_md5 = "no"; + +if ($suricatacfg['enable_file_store'] == 'on') { + $file_store_enabled = "yes"; + if (!file_exists("{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/file.waldo")) + @file_put_contents("{$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/file.waldo", ""); +} +else + $file_store_enabled = "no"; + +if ($suricatacfg['enable_pcap_log'] == 'on') + $pcap_log_enabled = "yes"; +else + $pcap_log_enabled = "no"; + +if (!empty($suricatacfg['max_pcap_log_size'])) + $pcap_log_limit_size = $suricatacfg['max_pcap_log_size']; +else + $pcap_log_limit_size = "32"; + +if (!empty($suricatacfg['max_pcap_log_files'])) + $pcap_log_max_files = $suricatacfg['max_pcap_log_files']; +else + $pcap_log_max_files = "1000"; + +if ($suricatacfg['barnyard_enable'] == 'on') + $barnyard2_enabled = "yes"; +else + $barnyard2_enabled = "no"; + +// Add interface-specific IP defrag settings +if (!empty($suricatacfg['frag_memcap'])) + $frag_memcap = $suricatacfg['frag_memcap']; +else + $frag_memcap = "33554432"; + +if (!empty($suricatacfg['ip_max_trackers'])) + $ip_max_trackers = $suricatacfg['ip_max_trackers']; +else + $ip_max_trackers = "65535"; + +if (!empty($suricatacfg['ip_max_frags'])) + $ip_max_frags = $suricatacfg['ip_max_frags']; +else + $ip_max_frags = "65535"; + +if (!empty($suricatacfg['frag_hash_size'])) + $frag_hash_size = $suricatacfg['frag_hash_size']; +else + $frag_hash_size = "65536"; + +if (!empty($suricatacfg['ip_frag_timeout'])) + $ip_frag_timeout = $suricatacfg['ip_frag_timeout']; +else + $ip_frag_timeout = "60"; + +// Add interface-specific flow manager setttings +if (!empty($suricatacfg['flow_memcap'])) + $flow_memcap = $suricatacfg['flow_memcap']; +else + $flow_memcap = "33554432"; + +if (!empty($suricatacfg['flow_hash_size'])) + $flow_hash_size = $suricatacfg['flow_hash_size']; +else + $flow_hash_size = "65536"; + +if (!empty($suricatacfg['flow_prealloc'])) + $flow_prealloc = $suricatacfg['flow_prealloc']; +else + $flow_prealloc = "10000"; + +if (!empty($suricatacfg['flow_emerg_recovery'])) + $flow_emerg_recovery = $suricatacfg['flow_emerg_recovery']; +else + $flow_emerg_recovery = "30"; + +if (!empty($suricatacfg['flow_prune'])) + $flow_prune = $suricatacfg['flow_prune']; +else + $flow_prune = "5"; + +// Add interface-specific flow timeout setttings +if (!empty($suricatacfg['flow_tcp_new_timeout'])) + $flow_tcp_new_timeout = $suricatacfg['flow_tcp_new_timeout']; +else + $flow_tcp_new_timeout = "60"; + +if (!empty($suricatacfg['flow_tcp_established_timeout'])) + $flow_tcp_established_timeout = $suricatacfg['flow_tcp_established_timeout']; +else + $flow_tcp_established_timeout = "3600"; + +if (!empty($suricatacfg['flow_tcp_closed_timeout'])) + $flow_tcp_closed_timeout = $suricatacfg['flow_tcp_closed_timeout']; +else + $flow_tcp_closed_timeout = "120"; + +if (!empty($suricatacfg['flow_tcp_emerg_new_timeout'])) + $flow_tcp_emerg_new_timeout = $suricatacfg['flow_tcp_emerg_new_timeout']; +else + $flow_tcp_emerg_new_timeout = "10"; + +if (!empty($suricatacfg['flow_tcp_emerg_established_timeout'])) + $flow_tcp_emerg_established_timeout = $suricatacfg['flow_tcp_emerg_established_timeout']; +else + $flow_tcp_emerg_established_timeout = "300"; + +if (!empty($suricatacfg['flow_tcp_emerg_closed_timeout'])) + $flow_tcp_emerg_closed_timeout = $suricatacfg['flow_tcp_emerg_closed_timeout']; +else + $flow_tcp_emerg_closed_timeout = "20"; + +if (!empty($suricatacfg['flow_udp_new_timeout'])) + $flow_udp_new_timeout = $suricatacfg['flow_udp_new_timeout']; +else + $flow_udp_new_timeout = "30"; + +if (!empty($suricatacfg['flow_udp_established_timeout'])) + $flow_udp_established_timeout = $suricatacfg['flow_udp_established_timeout']; +else + $flow_udp_established_timeout = "300"; + +if (!empty($suricatacfg['flow_udp_emerg_new_timeout'])) + $flow_udp_emerg_new_timeout = $suricatacfg['flow_udp_emerg_new_timeout']; +else + $flow_udp_emerg_new_timeout = "10"; + +if (!empty($suricatacfg['flow_udp_emerg_established_timeout'])) + $flow_udp_emerg_established_timeout = $suricatacfg['flow_udp_emerg_established_timeout']; +else + $flow_udp_emerg_established_timeout = "100"; + +if (!empty($suricatacfg['flow_icmp_new_timeout'])) + $flow_icmp_new_timeout = $suricatacfg['flow_icmp_new_timeout']; +else + $flow_icmp_new_timeout = "30"; + +if (!empty($suricatacfg['flow_icmp_established_timeout'])) + $flow_icmp_established_timeout = $suricatacfg['flow_icmp_established_timeout']; +else + $flow_icmp_established_timeout = "300"; + +if (!empty($suricatacfg['flow_icmp_emerg_new_timeout'])) + $flow_icmp_emerg_new_timeout = $suricatacfg['flow_icmp_emerg_new_timeout']; +else + $flow_icmp_emerg_new_timeout = "10"; + +if (!empty($suricatacfg['flow_icmp_emerg_established_timeout'])) + $flow_icmp_emerg_established_timeout = $suricatacfg['flow_icmp_emerg_established_timeout']; +else + $flow_icmp_emerg_established_timeout = "100"; + +// Add interface-specific stream settings +if (!empty($suricatacfg['stream_memcap'])) + $stream_memcap = $suricatacfg['stream_memcap']; +else + $stream_memcap = "33554432"; + +if (!empty($suricatacfg['stream_max_sessions'])) + $stream_max_sessions = $suricatacfg['stream_max_sessions']; +else + $stream_max_sessions = "262144"; + +if (!empty($suricatacfg['stream_prealloc_sessions'])) + $stream_prealloc_sessions = $suricatacfg['stream_prealloc_sessions']; +else + $stream_prealloc_sessions = "32768"; + +if (!empty($suricatacfg['reassembly_memcap'])) + $reassembly_memcap = $suricatacfg['reassembly_memcap']; +else + $reassembly_memcap = "67108864"; + +if (!empty($suricatacfg['reassembly_depth']) || $suricatacfg['reassembly_depth'] == '0') + $reassembly_depth = $suricatacfg['reassembly_depth']; +else + $reassembly_depth = "1048576"; + +if (!empty($suricatacfg['reassembly_to_server_chunk'])) + $reassembly_to_server_chunk = $suricatacfg['reassembly_to_server_chunk']; +else + $reassembly_to_server_chunk = "2560"; + +if (!empty($suricatacfg['reassembly_to_client_chunk'])) + $reassembly_to_client_chunk = $suricatacfg['reassembly_to_client_chunk']; +else + $reassembly_to_client_chunk = "2560"; + +if ($suricatacfg['enable_midstream_sessions'] == 'on') + $stream_enable_midstream = "true"; +else + $stream_enable_midstream = "false"; + +if ($suricatacfg['enable_async_sessions'] == 'on') + $stream_enable_async = "true"; +else + $stream_enable_async = "false"; + +// Add the OS-specific host policies if configured, otherwise +// just set default to BSD for all networks. +if (!is_array($suricatacfg['host_os_policy']['item'])) + $suricatacfg['host_os_policy']['item'] = array(); +if (empty($suricatacfg['host_os_policy']['item'])) + $host_os_policy = "bsd: [0.0.0.0/0]"; +else { + foreach ($suricatacfg['host_os_policy']['item'] as $k => $v) { + $engine = "{$v['policy']}: "; + if ($v['bind_to'] <> "all") { + $tmp = trim(filter_expand_alias($v['bind_to'])); + if (!empty($tmp)) { + $engine .= "["; + $tmp = preg_replace('/\s+/', ',', $tmp); + $list = explode(',', $tmp); + foreach ($list as $addr) { + if (is_ipaddrv6($addr) || is_subnetv6($addr)) + $engine .= "\"{$addr}\", "; + elseif (is_ipaddrv4($addr) || is_subnetv4($addr)) + $engine .= "{$addr}, "; + else + log_error("[suricata] WARNING: invalid IP address value '{$addr}' in Alias {$v['bind_to']} will be ignored."); + } + $engine = trim($engine, ' ,'); + $engine .= "]"; + } + else { + log_error("[suricata] WARNING: unable to resolve IP List Alias '{$v['bind_to']}' for Host OS Policy '{$v['name']}' ... ignoring this entry."); + continue; + } + } + else + $engine .= "[0.0.0.0/0]"; + + $host_os_policy .= " {$engine}\n"; + } + // Remove trailing newline + $host_os_policy = trim($host_os_policy); +} + +// Add the HTTP Server-specific policies if configured, otherwise +// just set default to IDS for all networks. +if (!is_array($suricatacfg['libhtp_policy']['item'])) + $suricatacfg['libhtp_policy']['item'] = array(); +if (empty($suricatacfg['libhtp_policy']['item'])) { + $http_hosts_default_policy = "default-config:\n personality: IDS\n request-body-limit: 4096\n response-body-limit: 4096\n"; + $http_hosts_default_policy .= " double-decode-path: no\n double-decode-query: no\n"; +} +else { + foreach ($suricatacfg['libhtp_policy']['item'] as $k => $v) { + if ($v['bind_to'] <> "all") { + $engine = "server-config:\n - {$v['name']}:\n"; + $tmp = trim(filter_expand_alias($v['bind_to'])); + if (!empty($tmp)) { + $engine .= " address: ["; + $tmp = preg_replace('/\s+/', ',', $tmp); + $list = explode(',', $tmp); + foreach ($list as $addr) { + if (is_ipaddrv6($addr) || is_subnetv6($addr)) + $engine .= "\"{$addr}\", "; + elseif (is_ipaddrv4($addr) || is_subnetv4($addr)) + $engine .= "{$addr}, "; + else { + log_error("[suricata] WARNING: invalid IP address value '{$addr}' in Alias {$v['bind_to']} will be ignored."); + continue; + } + } + $engine = trim($engine, ' ,'); + $engine .= "]\n"; + $engine .= " personality: {$v['personality']}\n request-body-limit: {$v['request-body-limit']}\n"; + $engine .= " response-body-limit: {$v['response-body-limit']}\n"; + $engine .= " double-decode-path: {$v['double-decode-path']}\n"; + $engine .= " double-decode-query: {$v['double-decode-query']}\n"; + $http_hosts_policy .= " {$engine}\n"; + } + else { + log_error("[suricata] WARNING: unable to resolve IP List Alias '{$v['bind_to']}' for Host OS Policy '{$v['name']}' ... ignoring this entry."); + continue; + } + } + else { + $http_hosts_default_policy = " personality: {$v['personality']}\n request-body-limit: {$v['request-body-limit']}\n"; + $http_hosts_default_policy .= " response-body-limit: {$v['response-body-limit']}\n"; + $http_hosts_default_policy .= " double-decode-path: {$v['double-decode-path']}\n"; + $http_hosts_default_policy .= " double-decode-query: {$v['double-decode-query']}\n"; + } + } + // Remove trailing newline + $http_hosts_default_policy = trim($http_hosts_default_policy); + $http_hosts_policy = trim($http_hosts_policy); +} + +// Configure ASN1 max frames value +if (!empty($suricatacfg['asn1_max_frames'])) + $asn1_max_frames = $suricatacfg['asn1_max_frames']; +else + $asn1_max_frames = "256"; + +// Create the rules files and save in the interface directory +suricata_prepare_rule_files($suricatacfg, $suricatacfgdir); + +// Check and configure only non-empty rules files for the interface +$rules_files = ""; +if (filesize("{$suricatacfgdir}/rules/".ENFORCING_RULES_FILENAME) > 0) + $rules_files .= ENFORCING_RULES_FILENAME; +if (filesize("{$suricatacfgdir}/rules/".FLOWBITS_FILENAME) > 0) + $rules_files .= "\n - " . FLOWBITS_FILENAME; +if (filesize("{$suricatacfgdir}/rules/custom.rules") > 0) + $rules_files .= "\n - custom.rules"; +$rules_files = ltrim($rules_files, '\n -'); + +// Add the general logging settings to the configuration (non-interface specific) +if ($config['installedpackages']['suricata']['config'][0]['log_to_systemlog'] == 'on') + $suricata_use_syslog = "yes"; +else + $suricata_use_syslog = "no"; + +?> diff --git a/config/suricata/suricata_global.php b/config/suricata/suricata_global.php new file mode 100644 index 00000000..f6b5d83d --- /dev/null +++ b/config/suricata/suricata_global.php @@ -0,0 +1,456 @@ + $v) { + foreach ($disabled_rules as $d) + if (strpos(trim($v), $d) !== false) + unset($enabled_rules[$k]); + } + $iface['rulesets'] = implode("||", $enabled_rules); + } + } + + $config['installedpackages']['suricata']['config'][0]['oinkcode'] = $_POST['oinkcode']; + $config['installedpackages']['suricata']['config'][0]['etprocode'] = $_POST['etprocode']; + + $config['installedpackages']['suricata']['config'][0]['rm_blocked'] = $_POST['rm_blocked']; + if ($_POST['suricataloglimitsize']) { + $config['installedpackages']['suricata']['config'][0]['suricataloglimit'] = $_POST['suricataloglimit']; + $config['installedpackages']['suricata']['config'][0]['suricataloglimitsize'] = $_POST['suricataloglimitsize']; + } else { + $config['installedpackages']['suricata']['config'][0]['suricataloglimit'] = 'on'; + + /* code will set limit to 21% of slice that is unused */ + $suricataloglimitDSKsize = round(exec('df -k /var | grep -v "Filesystem" | awk \'{print $4}\'') * .22 / 1024); + $config['installedpackages']['suricata']['config'][0]['suricataloglimitsize'] = $suricataloglimitDSKsize; + } + $config['installedpackages']['suricata']['config'][0]['autoruleupdate'] = $_POST['autoruleupdate']; + + /* Check and adjust format of Rule Update Starttime string to add colon and leading zero if necessary */ + $pos = strpos($_POST['autoruleupdatetime'], ":"); + if ($pos === false) { + $tmp = str_pad($_POST['autoruleupdatetime'], 4, "0", STR_PAD_LEFT); + $_POST['autoruleupdatetime'] = substr($tmp, 0, 2) . ":" . substr($tmp, -2); + } + $config['installedpackages']['suricata']['config'][0]['autoruleupdatetime'] = str_pad($_POST['autoruleupdatetime'], 4, "0", STR_PAD_LEFT); + $config['installedpackages']['suricata']['config'][0]['log_to_systemlog'] = $_POST['log_to_systemlog'] ? 'on' : 'off'; + $config['installedpackages']['suricata']['config'][0]['clearlogs'] = $_POST['clearlogs'] ? 'on' : 'off'; + $config['installedpackages']['suricata']['config'][0]['forcekeepsettings'] = $_POST['forcekeepsettings'] ? 'on' : 'off'; + + $retval = 0; + + /* create whitelist and homenet file, then sync files */ + sync_suricata_package_config(); + + write_config(); + + /* forces page to reload new settings */ + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: /suricata/suricata_global.php"); + exit; + } +} + +$pgtitle = gettext("Suricata: Global Settings"); +include_once("head.inc"); + +?> + + + +' . $pgtitle . '

'; + +/* Display Alert message, under form tag or no refresh */ +if ($input_errors) + print_input_errors($input_errors); + +?> + +
+ + + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
" . gettext("Emerging Threats") . "" . gettext(" rules");?> + + + + + + + + + + + + + + + + + +
>
>
 
 " . gettext("Note:") . "" . " " . + gettext("The ETPro rules contain all of the ETOpen rules, so the ETOpen rules are not required and are disabled when the ETPro rules are selected."); ?>
+ + + + + + + + + + + +
 

+
+
" . gettext("Snort VRT") . "" . gettext(" rules");?> + + + + + + + + +
>
 
+ +
+ + + + + + + + + + + +
 

+
+
" . gettext("Snort Community") . "" . gettext(" rules");?> + + + + + +
> +

" . gettext("Note: ") . "" . + gettext("If you are a Snort VRT Paid Subscriber, the community ruleset is already built into your download of the ") . + gettext("Snort VRT rules, and there is no benefit in adding this rule set.");?>
+   " . gettext("NEVER") . "" . gettext(" disables auto-updates."); ?>

+ " . gettext("Hint: ") . "
" . gettext("in most cases, every 12 hours is a good choice."); ?>
>   + " . + gettext("Default") . " " . gettext("is ") . "" . gettext("00:03") . ""; ?>.

+

+
+
+
+  MB
+ + + + + + + +
> + ()
> +
+
+
+ + + + +
" . gettext("MB:") . "";?>  + +  " . gettext("20%") . "" . gettext(" of available space.");?>
+
+   +

+ " . gettext("Hint:") . "" . gettext(" in most cases, 1 hour is a good choice.");?>
+ > 
+ > 
+ > 
+ + +
   +
+

+
+
+ + + + + + diff --git a/config/suricata/suricata_import_aliases.php b/config/suricata/suricata_import_aliases.php new file mode 100644 index 00000000..c16ac65d --- /dev/null +++ b/config/suricata/suricata_import_aliases.php @@ -0,0 +1,272 @@ + "", "bind_to" => "", "policy" => "bsd" ); + + $def_libhtp_policy = array( "name" => "default", "bind_to" => "all", "personality" => "IDS", + "request-body-limit" => 4096, "response-body-limit" => 4096, + "double-decode-path" => "no", "double-decode-query" => "no" ); + + // Figure out which engine type we are importing and set up default engine array + $engine = array(); + switch ($eng) { + case "host_os_policy": + $engine = $def_os_policy; + break; + case "libhtp_policy": + $engine = $def_libhtp_policy; + break; + default: + $engine = ""; + $input_errors[] = gettext("Invalid ENGINE TYPE passed in query string. Aborting operation."); + } + + // See if anything was checked to import + if (is_array($_POST['toimport']) && count($_POST['toimport']) > 0) { + foreach ($_POST['toimport'] as $item) { + $engine['name'] = strtolower($item); + $engine['bind_to'] = $item; + $a_nat[] = $engine; + } + } + else + $input_errors[] = gettext("No entries were selected for import. Please select one or more Aliases for import and click SAVE."); + + // if no errors, write new entry to conf + if (!$input_errors) { + // Reorder the engine array to ensure the + // 'bind_to=all' entry is at the bottom if + // the array contains more than one entry. + if (count($a_nat) > 1) { + $i = -1; + foreach ($a_nat as $f => $v) { + if ($v['bind_to'] == "all") { + $i = $f; + break; + } + } + // Only relocate the entry if we + // found it, and it's not already + // at the end. + if ($i > -1 && ($i < (count($a_nat) - 1))) { + $tmp = $a_nat[$i]; + unset($a_nat[$i]); + $a_nat[] = $tmp; + } + } + + // Now write the new engine array to conf and return + write_config(); + + header("Location: {$returl}?id={$id}"); + exit; + } +} + +$pgtitle = gettext("Suricata: Import Host/Network Alias for {$title}"); +include("head.inc"); + +?> + + + +
+ + + +
+ + + + + + + + + + + + + + + + + + + + + + +

+
+ + + + + + + + + + + + + + + + + + "host" && $alias['type'] <> "network") + continue; + if (isset($used[$alias['name']])) + continue; + elseif (trim(filter_expand_alias($alias['name'])) == "") { + $textss = ""; + $textse = ""; + $disable = true; + $tooltip = gettext("Aliases representing a FQDN host cannot be used in Suricata Host OS Policy configurations."); + } + else { + $textss = ""; + $textse = ""; + $disable = ""; + $selectablealias = true; + $tooltip = gettext("Selected entries will be imported. Click to toggle selection of this entry."); + } + ?> + + + + + + + + + + +
+ +
+ 10) { + echo "..."; + } + ?> + +   +
+
+ "/> +
+ "/>    + "/> +
+
+
+
+
+ + + diff --git a/config/suricata/suricata_interfaces.php b/config/suricata/suricata_interfaces.php new file mode 100644 index 00000000..47a3ba11 --- /dev/null +++ b/config/suricata/suricata_interfaces.php @@ -0,0 +1,474 @@ + $i) { + if ($i['name'] == $autolist) { + unset($config['installedpackages']['suricata']['suppress']['item'][$k]); + break; + } + } + } + + // Finally delete the interface's config entry entirely + unset($a_nat[$rulei]); + } + conf_mount_ro(); + + /* If all the Suricata interfaces are removed, then unset the config array. */ + if (empty($a_nat)) + unset($a_nat); + + write_config(); + sleep(2); + + /* if there are no ifaces remaining do not create suricata.sh */ + if (!empty($config['installedpackages']['suricata']['rule'])) + suricata_create_rc(); + else { + conf_mount_rw(); + @unlink("{$rcdir}/suricata.sh"); + conf_mount_ro(); + } + + sync_suricata_package_config(); + + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: /suricata/suricata_interfaces.php"); + exit; + } + +} + +/* start/stop Barnyard2 */ +if ($_GET['act'] == 'bartoggle' && is_numeric($id)) { + $suricatacfg = $config['installedpackages']['suricata']['rule'][$id]; + $if_real = suricata_get_real_interface($suricatacfg['interface']); + $if_friendly = suricata_get_friendly_interface($suricatacfg['interface']); + + if (suricata_is_running($suricatacfg['uuid'], $if_real, 'barnyard2') == 'no') { + log_error("Toggle (barnyard starting) for {$if_friendly}({$suricatacfg['descr']})..."); + sync_suricata_package_config(); + suricata_barnyard_start($suricatacfg, $if_real); + } else { + log_error("Toggle (barnyard stopping) for {$if_friendly}({$suricatacfg['descr']})..."); + suricata_barnyard_stop($suricatacfg, $if_real); + } + + sleep(3); // So the GUI reports correctly + header("Location: /suricata/suricata_interfaces.php"); + exit; +} + +/* start/stop Suricata */ +if ($_GET['act'] == 'toggle' && is_numeric($id)) { + $suricatacfg = $config['installedpackages']['suricata']['rule'][$id]; + $if_real = suricata_get_real_interface($suricatacfg['interface']); + $if_friendly = suricata_get_friendly_interface($suricatacfg['interface']); + + if (suricata_is_running($suricatacfg['uuid'], $if_real) == 'yes') { + log_error("Toggle (suricata stopping) for {$if_friendly}({$suricatacfg['descr']})..."); + suricata_stop($suricatacfg, $if_real); + } else { + log_error("Toggle (suricata starting) for {$if_friendly}({$suricatacfg['descr']})..."); + // set flag to rebuild interface rules before starting Snort + $rebuild_rules = true; + sync_suricata_package_config(); + $rebuild_rules = false; + suricata_start($suricatacfg, $if_real); + } + sleep(3); // So the GUI reports correctly + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: /suricata/suricata_interfaces.php"); + exit; +} + +$pgtitle = "Services: Suricata Intrusion Detection System"; +include_once("head.inc"); + +?> + + +' . $pgtitle . '

'; +?> + +
+ + + + + + + + + +
+ +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
  + + + + + +
+
+ + + + + + "; + echo ($no_rules) ? " " : ""; + } else + echo gettext("DISABLED"); + ?> + + + + + + + "; + } else + echo gettext("DISABLED"); + ?> + +   + + + + + +
+
+
+
+    +   + +
+ + + + +
+ + " + onclick="return intf_del()"> +
+
 
  + + + + + + + + + + + + + + + + + + + + + + + + + +

+ " . gettext("Suricata Menu ") . + "" . gettext("where you can see an overview of all your interface settings. "); + if (empty($a_nat)) { + echo gettext("Please configure the parameters on the ") . "" . gettext("Global Settings") . + "" . gettext(" tab before adding an interface."); + }?> +

+

+ +

+
Click on the "> icon to add + an interface. +   + "> + "> icons will show current + suricata and barnyard2 status. +
Click on the "> icon to edit + an interface and settings. +   + Click on the status icons to toggle suricata and barnyard2 status. +
Click on the "> icon to + delete an interface and settings. +
+
 
+
+
+
+ + + + + + diff --git a/config/suricata/suricata_interfaces_edit.php b/config/suricata/suricata_interfaces_edit.php new file mode 100644 index 00000000..4a805ea2 --- /dev/null +++ b/config/suricata/suricata_interfaces_edit.php @@ -0,0 +1,911 @@ + 'WAN', 'lan' => 'LAN'); + for ($i = 1; isset($config['interfaces']['opt' . $i]); $i++) + $interfaces['opt' . $i] = $config['interfaces']['opt' . $i]['descr']; +} + +// See if interface is already configured, and use its values +if (isset($id) && $a_rule[$id]) { + $pconfig = $a_rule[$id]; + if (!empty($pconfig['configpassthru'])) + $pconfig['configpassthru'] = base64_decode($pconfig['configpassthru']); + if (empty($pconfig['uuid'])) + $pconfig['uuid'] = $suricata_uuid; +} +// Must be a new interface, so try to pick next available physical interface to use +elseif (isset($id) && !isset($a_rule[$id])) { + $ifaces = get_configured_interface_list(); + $ifrules = array(); + foreach($a_rule as $r) + $ifrules[] = $r['interface']; + foreach ($ifaces as $i) { + if (!in_array($i, $ifrules)) { + $pconfig['interface'] = $i; + break; + } + } + if (count($ifrules) == count($ifaces)) { + $input_errors[] = gettext("No more available interfaces to configure for Suricata!"); + $interfaces = array(); + $pconfig = array(); + } +} + +if (isset($_GET['dup'])) + unset($id); + +// Set defaults for any empty key parameters +if (empty($pconfig['blockoffendersip'])) + $pconfig['blockoffendersip'] = "both"; +if (empty($pconfig['max_pending_packets'])) + $pconfig['max_pending_packets'] = "1024"; +if (empty($pconfig['inspect_recursion_limit'])) + $pconfig['inspect_recursion_limit'] = "3000"; +if (empty($pconfig['detect_eng_profile'])) + $pconfig['detect_eng_profile'] = "medium"; +if (empty($pconfig['mpm_algo'])) + $pconfig['mpm_algo'] = "ac"; +if (empty($pconfig['sgh_mpm_context'])) + $pconfig['sgh_mpm_context'] = "auto"; +if (empty($pconfig['enable_http_log'])) + $pconfig['enable_http_log'] = "on"; +if (empty($pconfig['append_http_log'])) + $pconfig['append_http_log'] = "on"; +if (empty($pconfig['enable_tls_log'])) + $pconfig['enable_tls_log'] = "off"; +if (empty($pconfig['tls_log_extended'])) + $pconfig['tls_log_extended'] = "on"; +if (empty($pconfig['enable_stats_log'])) + $pconfig['enable_stats_log'] = "off"; +if (empty($pconfig['stats_upd_interval'])) + $pconfig['stats_upd_interval'] = "10"; +if (empty($pconfig['append_stats_log'])) + $pconfig['append_stats_log'] = "off"; +if (empty($pconfig['append_json_file_log'])) + $pconfig['append_json_file_log'] = "on"; +if (empty($pconfig['enable_pcap_log'])) + $pconfig['enable_pcap_log'] = "off"; +if (empty($pconfig['max_pcap_log_size'])) + $pconfig['max_pcap_log_size'] = "32"; +if (empty($pconfig['max_pcap_log_files'])) + $pconfig['max_pcap_log_files'] = "1000"; + +if ($_POST["Submit"]) { + if (!$_POST['interface']) + $input_errors[] = gettext("Choosing an Interface is mandatory!"); + + if ($_POST['max_pending_packets'] < 1 || $_POST['max_pending_packets'] > 65535) + $input_errors[] = gettext("The value for Maximum-Pending-Packets must be between 1 and 65,535!"); + + if (!empty($_POST['max_pcap_log_size']) && !is_numeric($_POST['max_pcap_log_size'])) + $input_errors[] = gettext("The value for 'Max Packet Log Size' must be numbers only. Do not include any alphabetic characters."); + + if (!empty($_POST['max_pcap_log_files']) && !is_numeric($_POST['max_pcap_log_files'])) + $input_errors[] = gettext("The value for 'Max Packet Log Files' must be numbers only."); + + // if no errors write to suricata.yaml + if (!$input_errors) { + $natent = $a_rule[$id]; + $natent['interface'] = $_POST['interface']; + $natent['enable'] = $_POST['enable'] ? 'on' : 'off'; + $natent['uuid'] = $pconfig['uuid']; + + // See if the HOME_NET, EXTERNAL_NET, or SUPPRESS LIST values were changed + $suricata_reload = false; + if ($_POST['homelistname'] && ($_POST['homelistname'] <> $natent['homelistname'])) + $suricata_reload = true; + if ($_POST['externallistname'] && ($_POST['externallistname'] <> $natent['externallistname'])) + $suricata_reload = true; + if ($_POST['suppresslistname'] && ($_POST['suppresslistname'] <> $natent['suppresslistname'])) + $suricata_reload = true; + + if ($_POST['descr']) $natent['descr'] = $_POST['descr']; else $natent['descr'] = strtoupper($natent['interface']); + if ($_POST['max_pcap_log_size']) $natent['max_pcap_log_size'] = $_POST['max_pcap_log_size']; else unset($natent['max_pcap_log_size']); + if ($_POST['max_pcap_log_files']) $natent['max_pcap_log_files'] = $_POST['max_pcap_log_files']; else unset($natent['max_pcap_log_files']); + if ($_POST['enable_stats_log'] == "on") { $natent['enable_stats_log'] = 'on'; }else{ $natent['enable_stats_log'] = 'off'; } + if ($_POST['append_stats_log'] == "on") { $natent['append_stats_log'] = 'on'; }else{ $natent['append_stats_log'] = 'off'; } + if ($_POST['stats_upd_interval']) $natent['stats_upd_interval'] = $_POST['stats_upd_interval']; else $natent['stats_upd_interval'] = "10"; + if ($_POST['enable_http_log'] == "on") { $natent['enable_http_log'] = 'on'; }else{ $natent['enable_http_log'] = 'off'; } + if ($_POST['append_http_log'] == "on") { $natent['append_http_log'] = 'on'; }else{ $natent['append_http_log'] = 'off'; } + if ($_POST['enable_tls_log'] == "on") { $natent['enable_tls_log'] = 'on'; }else{ $natent['enable_tls_log'] = 'off'; } + if ($_POST['tls_log_extended'] == "on") { $natent['tls_log_extended'] = 'on'; }else{ $natent['tls_log_extended'] = 'off'; } + if ($_POST['enable_pcap_log'] == "on") { $natent['enable_pcap_log'] = 'on'; }else{ $natent['enable_pcap_log'] = 'off'; } + if ($_POST['enable_json_file_log'] == "on") { $natent['enable_json_file_log'] = 'on'; }else{ $natent['enable_json_file_log'] = 'off'; } + if ($_POST['append_json_file_log'] == "on") { $natent['append_json_file_log'] = 'on'; }else{ $natent['append_json_file_log'] = 'off'; } + if ($_POST['enable_tracked_files_magic'] == "on") { $natent['enable_tracked_files_magic'] = 'on'; }else{ $natent['enable_tracked_files_magic'] = 'off'; } + if ($_POST['enable_tracked_files_md5'] == "on") { $natent['enable_tracked_files_md5'] = 'on'; }else{ $natent['enable_tracked_files_md5'] = 'off'; } + if ($_POST['enable_file_store'] == "on") { $natent['enable_file_store'] = 'on'; }else{ $natent['enable_file_store'] = 'off'; } + if ($_POST['max_pending_packets']) $natent['max_pending_packets'] = $_POST['max_pending_packets']; else unset($natent['max_pending_packets']); + if ($_POST['inspect_recursion_limit']) $natent['inspect_recursion_limit'] = $_POST['inspect_recursion_limit']; else unset($natent['inspect_recursion_limit']); + if ($_POST['detect_eng_profile']) $natent['detect_eng_profile'] = $_POST['detect_eng_profile']; else unset($natent['detect_eng_profile']); + if ($_POST['mpm_algo']) $natent['mpm_algo'] = $_POST['mpm_algo']; else unset($natent['mpm_algo']); + if ($_POST['sgh_mpm_context']) $natent['sgh_mpm_context'] = $_POST['sgh_mpm_context']; else unset($natent['sgh_mpm_context']); + if ($_POST['blockoffenders'] == "on") $natent['blockoffenders'] = 'on'; else $natent['blockoffenders'] = 'off'; + if ($_POST['blockoffenderskill'] == "on") $natent['blockoffenderskill'] = 'on'; else unset($natent['blockoffenderskill']); + if ($_POST['blockoffendersip']) $natent['blockoffendersip'] = $_POST['blockoffendersip']; else unset($natent['blockoffendersip']); + if ($_POST['whitelistname']) $natent['whitelistname'] = $_POST['whitelistname']; else unset($natent['whitelistname']); + if ($_POST['homelistname']) $natent['homelistname'] = $_POST['homelistname']; else unset($natent['homelistname']); + if ($_POST['externallistname']) $natent['externallistname'] = $_POST['externallistname']; else unset($natent['externallistname']); + if ($_POST['suppresslistname']) $natent['suppresslistname'] = $_POST['suppresslistname']; else unset($natent['suppresslistname']); + if ($_POST['alertsystemlog'] == "on") { $natent['alertsystemlog'] = 'on'; }else{ $natent['alertsystemlog'] = 'off'; } + if ($_POST['configpassthru']) $natent['configpassthru'] = base64_encode($_POST['configpassthru']); else unset($natent['configpassthru']); + + $if_real = suricata_get_real_interface($natent['interface']); + if (isset($id) && $a_rule[$id]) { + if ($natent['interface'] != $a_rule[$id]['interface']) { + $oif_real = suricata_get_real_interface($a_rule[$id]['interface']); + suricata_stop($a_rule[$id], $oif_real); + exec("rm -r /var/log/suricata_{$oif_real}" . $a_rule[$id]['uuid']); + exec("mv -f {$suricatadir}/suricata_" . $a_rule[$id]['uuid'] . "_{$oif_real} {$suricatadir}/suricata_" . $a_rule[$id]['uuid'] . "_{$if_real}"); + } + // Edits don't require a rules rebuild, so turn it "off" + $rebuild_rules = false; + $a_rule[$id] = $natent; + } else { + // Adding new interface, so set interface configuration parameter defaults + $natent['ip_max_frags'] = "65535"; + $natent['ip_frag_timeout'] = "60"; + $natent['frag_memcap'] = '33554432'; + $natent['ip_max_trackers'] = '65535'; + $natent['frag_hash_size'] = '65536'; + + $natent['flow_memcap'] = '33554432'; + $natent['flow_prealloc'] = '10000'; + $natent['flow_hash_size'] = '65536'; + $natent['flow_emerg_recovery'] = '30'; + $natent['flow_prune'] = '5'; + + $natent['flow_tcp_new_timeout'] = '60'; + $natent['flow_tcp_established_timeout'] = '3600'; + $natent['flow_tcp_closed_timeout'] = '120'; + $natent['flow_tcp_emerg_new_timeout'] = '10'; + $natent['flow_tcp_emerg_established_timeout'] = '300'; + $natent['flow_tcp_emerg_closed_timeout'] = '20'; + + $natent['flow_udp_new_timeout'] = '30'; + $natent['flow_udp_established_timeout'] = '300'; + $natent['flow_udp_emerg_new_timeout'] = '10'; + $natent['flow_udp_emerg_established_timeout'] = '100'; + + $natent['flow_icmp_new_timeout'] = '30'; + $natent['flow_icmp_established_timeout'] = '300'; + $natent['flow_icmp_emerg_new_timeout'] = '10'; + $natent['flow_icmp_emerg_established_timeout'] = '100'; + + $natent['stream_memcap'] = '33554432'; + $natent['stream_max_sessions'] = '262144'; + $natent['stream_prealloc_sessions'] = '32768'; + $natent['reassembly_memcap'] = '67108864'; + $natent['reassembly_depth'] = '1048576'; + $natent['reassembly_to_server_chunk'] = '2560'; + $natent['reassembly_to_client_chunk'] = '2560'; + $natent['enable_midstream_sessions'] = 'off'; + $natent['enable_async_sessions'] = 'off'; + + $natent['asn1_max_frames'] = '256'; + + $default = array( "name" => "default", "bind_to" => "all", "policy" => "bsd" ); + if (!is_array($natent['host_os_policy']['item'])) + $natent['host_os_policy']['item'] = array(); + $natent['host_os_policy']['item'][] = $default; + + $default = array( "name" => "default", "bind_to" => "all", "personality" => "IDS", + "request-body-limit" => 4096, "response-body-limit" => 4096, + "double-decode-path" => "no", "double-decode-query" => "no" ); + if (!is_array($natent['libhtp_policy']['item'])) + $natent['libhtp_policy']['item'] = array(); + $natent['libhtp_policy']['item'][] = $default; + + // Enable the basic default rules for the interface + $natent['rulesets'] = "decoder-events.rules||files.rules||http-events.rules||smtp-events.rules||stream-events"; + + // Adding a new interface, so set flag to build new rules + $rebuild_rules = true; + + // Add the new interface configuration to the [rule] array in config + $a_rule[] = $natent; + } + + // If Suricata is disabled on this interface, stop any running instance + if ($natent['enable'] != 'on') + suricata_stop($natent, $if_real); + + // Save configuration changes + write_config(); + + // Update suricata.conf and suricata.sh files for this interface + sync_suricata_package_config(); + + /*******************************************************/ + /* Signal Suricata to reload configuration if we changed */ + /* HOME_NET, EXTERNAL_NET or Suppress list values. */ + /* The function only signals a running Suricata instance */ + /* to safely reload these parameters. */ + /*******************************************************/ + if ($suricata_reload == true) + suricata_reload_config($natent, "USR2"); + + header( 'Expires: Sat, 26 Jul 1997 05:00:00 GMT' ); + header( 'Last-Modified: ' . gmdate( 'D, d M Y H:i:s' ) . ' GMT' ); + header( 'Cache-Control: no-store, no-cache, must-revalidate' ); + header( 'Cache-Control: post-check=0, pre-check=0', false ); + header( 'Pragma: no-cache' ); + header("Location: /suricata/suricata_interfaces.php"); + exit; + } else + $pconfig = $_POST; +} + +$if_friendly = suricata_get_friendly_interface($pconfig['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} - Edit Settings"); +include_once("head.inc"); +?> + + + + + +' . $pgtitle . '

';}?> + + + +
" method="post" name="iform" id="iform"> + +'; + echo ' + +
+
'; + $tab_array = array(); + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface "); + $tab_array[] = array($menu_iface . gettext("Settings"), true, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), false, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), false, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), false, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + display_top_tabs($tab_array); +?> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ onClick="enable_change(false)"/> + +
+    +
+  


+
/> +
+ onClick="toggle_stats_log();" id="enable_stats_log"/> + " . gettext("Not Checked") . "."; ?> +
  + " . gettext("seconds") . "" . gettext(" for stats updating. Default is ") . "" . + gettext("10") . "."; ?>
/> + " . gettext("Not Checked") . "."; ?>
+ onClick="toggle_http_log()" id="enable_http_log"/> + " . gettext("Checked") . "."; ?>
/> + " . gettext("Checked") . "."; ?>
+ onClick="toggle_tls_log()" id="enable_tls_log"/> + " . gettext("Not Checked") . "."; ?>
/> + " . gettext("Checked") . "."; ?>
+ onClick="toggle_json_file_log()" id="enable_json_file_log"/> + " . gettext("Not Checked") . "."; ?>
+ id="append_json_file_log"/> + " . gettext("Checked") . "."; ?>
+ id="enable_tracked_files_magic"/> + " . gettext("Not Checked") . "."; ?>
+ id="enable_tracked_files_md5"/> + " . gettext("Not Checked") . "."; ?>
+ onClick="toggle_file_store()" id="enable_file_store"/> + " . gettext("Not Checked") . "."; ?> + +
+ onClick="toggle_pcap_log()"/> + " . gettext("Not Checked") . "."; ?> + +
  + " . gettext("MB") . "" . gettext(" for a packet log file. Default is ") . "" . + gettext("32") . "."; ?>

  + " . + gettext("1000") . "."; ?>

  + " . + gettext("1024") . "."; ?>

+    + " . gettext("Default") . + "" . gettext(" is ") . "" . gettext("Medium") . ""; ?>.

+ +
+    + " . gettext("Default") . + "" . gettext(" is ") . "" . gettext("AC") . ""; ?>.

+ +
+    + " . gettext("Default") . + "" . gettext(" is ") . "" . gettext("Auto") . ""; ?>.

+ +
  + " . + gettext("3000") . "."; ?>

+ +      "/> +
+ +

+  
+  
+
+    +  

+  
+  
+
+ +      "/> +
+

+  
+   +
+ +      "/> +
+
 
" . + gettext("Default option disables suppression and filtering."); ?> +
+ +
"/> + +
 " . + gettext("Please save your settings before you attempt to start Suricata."); ?> +
+
+
+
+ + + + + diff --git a/config/suricata/suricata_libhtp_policy_engine.php b/config/suricata/suricata_libhtp_policy_engine.php new file mode 100644 index 00000000..a1f6a77c --- /dev/null +++ b/config/suricata/suricata_libhtp_policy_engine.php @@ -0,0 +1,329 @@ + "engine_{$eng_id}", "bind_to" => "", "personality" => "IDS", + "request-body-limit" => "4096", "response-body-limit" => "4096", + "double-decode-path" => "no", "double-decode-query" => "no" ); + + // See if this is initial entry and set to "default" if true + if ($eng_id < 1) { + $def['name'] = "default"; + $def['bind_to'] = "all"; + } + $pconfig = $def; +} +else { + $pconfig = $a_nat[$eng_id]; + + // Check for any empty values and set sensible defaults + if (empty($pconfig['personality'])) + $pconfig['personality'] = "IDS"; +} + +if ($_POST['Cancel']) { + header("Location: /suricata/suricata_app_parsers.php?id={$id}"); + exit; +} + +// Check for returned "selected alias" if action is import +if ($_GET['act'] == "import") { + if ($_GET['varname'] == "bind_to" && !empty($_GET['varvalue'])) + $pconfig[$_GET['varname']] = $_GET['varvalue']; +} + +if ($_POST['Submit']) { + + /* Grab all the POST values and save in new temp array */ + $engine = array(); + if ($_POST['policy_name']) { $engine['name'] = trim($_POST['policy_name']); } else { $engine['name'] = "default"; } + if ($_POST['policy_bind_to']) { + if (is_alias($_POST['policy_bind_to'])) + $engine['bind_to'] = $_POST['policy_bind_to']; + elseif (strtolower(trim($_POST['policy_bind_to'])) == "all") + $engine['bind_to'] = "all"; + else + $input_errors[] = gettext("You must provide a valid Alias or the reserved keyword 'all' for the 'Bind-To IP Address' value."); + } + else { + $input_errors[] = gettext("The 'Bind-To IP Address' value cannot be blank. Provide a valid Alias or the reserved keyword 'all'."); + } + + if ($_POST['personality']) { $engine['personality'] = $_POST['personality']; } else { $engine['personality'] = "IDS"; } + if (is_numeric($_POST['req_body_limit']) && $_POST['req_body_limit'] >= 0) + $engine['request-body-limit'] = $_POST['req_body_limit']; + else + $input_errors[] = gettext("The value for 'Request Body Limit' must be all numbers and greater than or equal to zero."); + + if (is_numeric($_POST['resp_body_limit']) && $_POST['resp_body_limit'] >= 0) + $engine['response-body-limit'] = $_POST['resp_body_limit']; + else + $input_errors[] = gettext("The value for 'Response Body Limit' must be all numbers and greater than or equal to zero."); + + if ($_POST['enable_double_decode_path']) { $engine['double-decode-path'] = 'yes'; }else{ $engine['double-decode-path'] = 'no'; } + if ($_POST['enable_double_decode_query']) { $engine['double-decode-query'] = 'yes'; }else{ $engine['double-decode-query'] = 'no'; } + + /* Can only have one "all" Bind_To address */ + if ($engine['bind_to'] == "all" && $engine['name'] <> "default") { + $input_errors[] = gettext("Only one default HTTP Server Policy Engine can be bound to all addresses."); + $pconfig = $engine; + } + + /* if no errors, write new entry to conf */ + if (!$input_errors) { + if (isset($eng_id) && $a_nat[$eng_id]) { + $a_nat[$eng_id] = $engine; + } + else + $a_nat[] = $engine; + + /* Reorder the engine array to ensure the */ + /* 'bind_to=all' entry is at the bottom */ + /* if it contains more than one entry. */ + if (count($a_nat) > 1) { + $i = -1; + foreach ($a_nat as $f => $v) { + if ($v['bind_to'] == "all") { + $i = $f; + break; + } + } + /* Only relocate the entry if we */ + /* found it, and it's not already */ + /* at the end. */ + if ($i > -1 && ($i < (count($a_nat) - 1))) { + $tmp = $a_nat[$i]; + unset($a_nat[$i]); + $a_nat[] = $tmp; + } + } + + /* Now write the new engine array to conf */ + write_config(); + + header("Location: /suricata/suricata_app_parsers.php?id={$id}"); + exit; + } +} + +$if_friendly = suricata_get_friendly_interface($config['installedpackages']['suricata']['rule'][$id]['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} HTTP Server Policy Engine"); +include_once("head.inc"); + +?> + + + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ >  + "default") + echo gettext("Name or description for this engine. (Max 25 characters)"); + else + echo "" . gettext("The name for the 'default' engine is read-only.") . "";?>
+ " . gettext("default") . ""; ?>.
+
+ "default") : ?> + + + + + + + + +
  + "/>
+
" . gettext("Supplied value must be a pre-configured Alias or the keyword 'all'.");?> + +   + " . gettext("IP List for the default engine is read-only and must be 'all'.") . "";?>
+
+ +
+   " . gettext("IDS") . ""; ?>.

+
+
+   + " . gettext("4,096") . "" . gettext(" bytes."); ?>

+
" . + gettext("Note: ") . "" . gettext("Setting this parameter to 0 will inspect all of the client-body."); ?> +
+   + " . gettext("4,096") . "" . gettext(" bytes."); ?>

+
" . + gettext("Note: ") . "" . gettext("Setting this parameter to 0 will inspect all of the server-body."); ?> +
> + " . gettext("Not Checked") . "."; ?>
> + " . gettext("Not Checked") . "."; ?>
  + "> +      + ">
+
+
+
+ + + + + + diff --git a/config/suricata/suricata_list_view.php b/config/suricata/suricata_list_view.php new file mode 100644 index 00000000..2ff121f2 --- /dev/null +++ b/config/suricata/suricata_list_view.php @@ -0,0 +1,100 @@ + + + + + + + + +
+ + + + +
+ + + + + + + + + + + +
Suricata:
+ + +  ' . $_GET['wlist']; ?>     +
+
+ +
+
+
+
+ + + diff --git a/config/suricata/suricata_log_view.php b/config/suricata/suricata_log_view.php new file mode 100644 index 00000000..41a7225e --- /dev/null +++ b/config/suricata/suricata_log_view.php @@ -0,0 +1,86 @@ + + + + + + + + +
+ + + + +
+ + + + + + + + + + + +
Suricata: Log File Viewer
+ + +  ' . $_GET['logfile']; ?>     +
+
+ +
+
+
+
+ + + diff --git a/config/suricata/suricata_logs_browser.php b/config/suricata/suricata_logs_browser.php new file mode 100644 index 00000000..dfa56146 --- /dev/null +++ b/config/suricata/suricata_logs_browser.php @@ -0,0 +1,217 @@ + + + + +' . $pgtitle . '

';} +if ($input_errors) { + print_input_errors($input_errors); +} + +?> + + + +
+ + + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + +
+    +
+    +
+ + +
+ + + + +
+
+ +
+
+
+
+
+
+ + + + + + + + diff --git a/config/suricata/suricata_os_policy_engine.php b/config/suricata/suricata_os_policy_engine.php new file mode 100644 index 00000000..5c0ebbc1 --- /dev/null +++ b/config/suricata/suricata_os_policy_engine.php @@ -0,0 +1,275 @@ + "engine_{$eng_id}", "bind_to" => "", "policy" => "bsd" ); + // See if this is initial entry and set to "default" if true + if ($eng_id < 1) { + $def['name'] = "default"; + $def['bind_to'] = "all"; + } + $pconfig = $def; +} +else { + $pconfig = $a_nat[$eng_id]; + + // Check for any empty values and set sensible defaults + if (empty($pconfig['policy'])) + $pconfig['policy'] = "bsd"; +} + +if ($_POST['Cancel']) { + header("Location: /suricata/suricata_flow_stream.php?id={$id}"); + exit; +} + +// Check for returned "selected alias" if action is import +if ($_GET['act'] == "import") { + if ($_GET['varname'] == "bind_to" && !empty($_GET['varvalue'])) + $pconfig[$_GET['varname']] = $_GET['varvalue']; +} + +if ($_POST['Submit']) { + + /* Grab all the POST values and save in new temp array */ + $engine = array(); + if ($_POST['policy_name']) { $engine['name'] = trim($_POST['policy_name']); } else { $engine['name'] = "default"; } + if ($_POST['policy_bind_to']) { + if (is_alias($_POST['policy_bind_to'])) + $engine['bind_to'] = $_POST['policy_bind_to']; + elseif (strtolower(trim($_POST['policy_bind_to'])) == "all") + $engine['bind_to'] = "all"; + else + $input_errors[] = gettext("You must provide a valid Alias or the reserved keyword 'all' for the 'Bind-To IP Address' value."); + } + else { + $input_errors[] = gettext("The 'Bind-To IP Address' value cannot be blank. Provide a valid Alias or the reserved keyword 'all'."); + } + + if ($_POST['policy']) { $engine['policy'] = $_POST['policy']; } else { $engine['policy'] = "bsd"; } + + /* Can only have one "all" Bind_To address */ + if ($engine['bind_to'] == "all" && $engine['name'] <> "default") { + $input_errors[] = gettext("Only one default OS-Policy Engine can be bound to all addresses."); + $pconfig = $engine; + } + + /* if no errors, write new entry to conf */ + if (!$input_errors) { + if (isset($eng_id) && $a_nat[$eng_id]) { + $a_nat[$eng_id] = $engine; + } + else + $a_nat[] = $engine; + + /* Reorder the engine array to ensure the */ + /* 'bind_to=all' entry is at the bottom */ + /* if it contains more than one entry. */ + if (count($a_nat) > 1) { + $i = -1; + foreach ($a_nat as $f => $v) { + if ($v['bind_to'] == "all") { + $i = $f; + break; + } + } + /* Only relocate the entry if we */ + /* found it, and it's not already */ + /* at the end. */ + if ($i > -1 && ($i < (count($a_nat) - 1))) { + $tmp = $a_nat[$i]; + unset($a_nat[$i]); + $a_nat[] = $tmp; + } + } + + /* Now write the new engine array to conf */ + write_config(); + + header("Location: /suricata/suricata_flow_stream.php?id={$id}"); + exit; + } +} + +$if_friendly = suricata_get_friendly_interface($config['installedpackages']['suricata']['rule'][$id]['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} Operating System Policy Engine"); +include_once("head.inc"); + +?> + + + + + +
+ + +
+ + + + +
+ + + + + + + + + + + + + + + + + + + + +
+ >  + "default") + echo gettext("Name or description for this engine. (Max 25 characters)"); + else + echo "" . gettext("The name for the 'default' engine is read-only.") . "";?>
+ " . gettext("default") . ""; ?>.
+
+ "default") : ?> + + + + + + + + +
  + "/>
+ " . gettext("Supplied value must be a pre-configured Alias or the keyword 'all'.");?> +      + +   + " . gettext("IP List for the default engine is read-only and must be 'all'.") . "";?>
+
+ +
+   " . gettext("BSD") . ""; ?>.

+
+
  + "> +      + ">
+
+
+
+ + + + + + diff --git a/config/suricata/suricata_post_install.php b/config/suricata/suricata_post_install.php new file mode 100644 index 00000000..0d6f553e --- /dev/null +++ b/config/suricata/suricata_post_install.php @@ -0,0 +1,139 @@ + "console") + $suricata_gui_include = true; + include('/usr/local/www/suricata/suricata_check_for_rule_updates.php'); + update_status(gettext("Generating suricata.yaml configuration file from saved settings...")); + $rebuild_rules = true; + + // Create the suricata.yaml files for each enabled interface + $suriconf = $config['installedpackages']['suricata']['rule']; + foreach ($suriconf as $value) { + $if_real = suricata_get_real_interface($value['interface']); + + // create a suricata.yaml file for interface + suricata_generate_yaml($value); + + // create barnyard2.conf file for interface + if ($value['barnyard_enable'] == 'on') + suricata_generate_barnyard2_conf($value, $if_real); + } + + // create Suricata bootup file suricata.sh + suricata_create_rc(); + + // Set Log Limit, Block Hosts Time and Rules Update Time + suricata_loglimit_install_cron($config['installedpackages']['suricata']['config'][0]['suricataloglimit'] == 'on' ? true : false); +// suricata_rm_blocked_install_cron($config['installedpackages']['suricata']['config'][0]['rm_blocked'] != "never_b" ? true : false); + suricata_rules_up_install_cron($config['installedpackages']['suricata']['config'][0]['autoruleupdate'] != "never_up" ? true : false); + + // Add the recurring jobs created above to crontab + configure_cron(); + + $rebuild_rules = false; + update_output_window(gettext("Finished rebuilding Suricata configuration files...")); + log_error(gettext("[Suricata] Finished rebuilding installation from saved settings...")); + + // Only try to start Suricata if not in reboot + if (!$g['booting']) { + update_status(gettext("Starting Suricata using rebuilt configuration...")); + update_output_window(gettext("Please wait... while Suricata is started...")); + log_error(gettext("[Suricata] Starting Suricata using rebuilt configuration...")); + start_service("suricata"); + update_output_window(gettext("Suricata has been started using the rebuilt configuration...")); + } +} + +// Update Suricata package version in configuration +$config['installedpackages']['suricata']['config'][0]['suricata_config_ver'] = "0.1-BETA"; +write_config(); + +// Done with post-install, so clear flag +unset($g['suricata_postinstall']); +log_error(gettext("[Suricata] Package post-installation tasks completed...")); +return true; + +?> diff --git a/config/suricata/suricata_rules.php b/config/suricata/suricata_rules.php new file mode 100644 index 00000000..f979d8b2 --- /dev/null +++ b/config/suricata/suricata_rules.php @@ -0,0 +1,790 @@ + $length) + $string = substr($string, 0, ($length - 2)) . "..."; + return $string; +} + +function add_title_attribute($tag, $title) { + + /******************************** + * This function adds a "title" * + * attribute to the passed tag * + * and sets the value to the * + * value specified by "$title". * + ********************************/ + $result = ""; + if (empty($tag)) { + // If passed an empty element tag, then + // just create a tag with title + $result = ""; + } + else { + // Find the ending ">" for the element tag + $pos = strpos($tag, ">"); + if ($pos !== false) { + // We found the ">" delimter, so add "title" + // attribute and close the element tag + $result = substr($tag, 0, $pos) . " title=\"" . $title . "\">"; + } + else { + // We did not find the ">" delimiter, so + // something is wrong, just return the + // tag "as-is" + $result = $tag; + } + } + return $result; +} + +/* convert fake interfaces to real */ +$if_real = suricata_get_real_interface($pconfig['interface']); +$suricata_uuid = $a_rule[$id]['uuid']; +$suricatacfgdir = "{$suricatadir}suricata_{$suricata_uuid}_{$if_real}"; +$snortdownload = $config['installedpackages']['suricata']['config'][0]['enable_vrt_rules']; +$emergingdownload = $config['installedpackages']['suricata']['config'][0]['enable_etopen_rules']; +$etpro = $config['installedpackages']['suricata']['config'][0]['enable_etpro_rules']; +$categories = explode("||", $pconfig['rulesets']); + +if ($_GET['openruleset']) + $currentruleset = $_GET['openruleset']; +else if ($_POST['openruleset']) + $currentruleset = $_POST['openruleset']; +else + $currentruleset = $categories[0]; + +if (empty($categories[0]) && ($currentruleset != "custom.rules") && ($currentruleset != "Auto-Flowbit Rules")) { + if (!empty($a_rule[$id]['ips_policy'])) + $currentruleset = "IPS Policy - " . ucfirst($a_rule[$id]['ips_policy']); + else + $currentruleset = "custom.rules"; +} + +/* One last sanity check -- if the rules directory is empty, default to loading custom rules */ +$tmp = glob("{$suricatadir}rules/*.rules"); +if (empty($tmp)) + $currentruleset = "custom.rules"; + +$ruledir = "{$suricatadir}rules"; +$rulefile = "{$ruledir}/{$currentruleset}"; +if ($currentruleset != 'custom.rules') { + // Read the current rules file into our rules map array. + // If it is the auto-flowbits file, set the full path. + if ($currentruleset == "Auto-Flowbit Rules") + $rulefile = "{$suricatacfgdir}/rules/" . FLOWBITS_FILENAME; + // Test for the special case of an IPS Policy file. + if (substr($currentruleset, 0, 10) == "IPS Policy") + $rules_map = suricata_load_vrt_policy($a_rule[$id]['ips_policy']); + elseif (!file_exists($rulefile)) + $input_errors[] = gettext("{$currentruleset} seems to be missing!!! Please verify rules files have been downloaded, then go to the Categories tab and save the rule set again."); + else + $rules_map = suricata_load_rules_map($rulefile); +} + +/* Load up our enablesid and disablesid arrays with enabled or disabled SIDs */ +$enablesid = suricata_load_sid_mods($a_rule[$id]['rule_sid_on']); +$disablesid = suricata_load_sid_mods($a_rule[$id]['rule_sid_off']); + +if ($_GET['act'] == "toggle" && $_GET['ids'] && !empty($rules_map)) { + + // Get the GID tag embedded in the clicked rule icon. + $gid = $_GET['gid']; + + // Get the SID tag embedded in the clicked rule icon. + $sid= $_GET['ids']; + + // See if the target SID is in our list of modified SIDs, + // and toggle it back to default if present; otherwise, + // add it to the appropriate modified SID list. + if (isset($enablesid[$gid][$sid])) + unset($enablesid[$gid][$sid]); + elseif (isset($disablesid[$gid][$sid])) + unset($disablesid[$gid][$sid]); + else { + if ($rules_map[$gid][$sid]['disabled'] == 1) + $enablesid[$gid][$sid] = "enablesid"; + else + $disablesid[$gid][$sid] = "disablesid"; + } + + // Write the updated enablesid and disablesid values to the config file. + $tmp = ""; + foreach (array_keys($enablesid) as $k1) { + foreach (array_keys($enablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_on'] = $tmp; + else + unset($a_rule[$id]['rule_sid_on']); + + $tmp = ""; + foreach (array_keys($disablesid) as $k1) { + foreach (array_keys($disablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_off'] = $tmp; + else + unset($a_rule[$id]['rule_sid_off']); + + /* Update the config.xml file. */ + write_config(); + + $_GET['openruleset'] = $currentruleset; + $anchor = "rule_{$gid}_{$sid}"; +} + +if ($_GET['act'] == "disable_all" && !empty($rules_map)) { + + // Mark all rules in the currently selected category "disabled". + foreach (array_keys($rules_map) as $k1) { + foreach (array_keys($rules_map[$k1]) as $k2) { + if (isset($enablesid[$k1][$k2])) + unset($enablesid[$k1][$k2]); + $disablesid[$k1][$k2] = "disablesid"; + } + } + + // Write the updated enablesid and disablesid values to the config file. + $tmp = ""; + foreach (array_keys($enablesid) as $k1) { + foreach (array_keys($enablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_on'] = $tmp; + else + unset($a_rule[$id]['rule_sid_on']); + + $tmp = ""; + foreach (array_keys($disablesid) as $k1) { + foreach (array_keys($disablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_off'] = $tmp; + else + unset($a_rule[$id]['rule_sid_off']); + + write_config(); + + $_GET['openruleset'] = $currentruleset; + header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}"); + exit; +} + +if ($_GET['act'] == "enable_all" && !empty($rules_map)) { + + // Mark all rules in the currently selected category "enabled". + foreach (array_keys($rules_map) as $k1) { + foreach (array_keys($rules_map[$k1]) as $k2) { + if (isset($disablesid[$k1][$k2])) + unset($disablesid[$k1][$k2]); + $enablesid[$k1][$k2] = "enablesid"; + } + } + // Write the updated enablesid and disablesid values to the config file. + $tmp = ""; + foreach (array_keys($enablesid) as $k1) { + foreach (array_keys($enablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_on'] = $tmp; + else + unset($a_rule[$id]['rule_sid_on']); + + $tmp = ""; + foreach (array_keys($disablesid) as $k1) { + foreach (array_keys($disablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_off'] = $tmp; + else + unset($a_rule[$id]['rule_sid_off']); + + write_config(); + + $_GET['openruleset'] = $currentruleset; + header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}"); + exit; +} + +if ($_GET['act'] == "resetcategory" && !empty($rules_map)) { + + // Reset any modified SIDs in the current rule category to their defaults. + foreach (array_keys($rules_map) as $k1) { + foreach (array_keys($rules_map[$k1]) as $k2) { + if (isset($enablesid[$k1][$k2])) + unset($enablesid[$k1][$k2]); + if (isset($disablesid[$k1][$k2])) + unset($disablesid[$k1][$k2]); + } + } + + // Write the updated enablesid and disablesid values to the config file. + $tmp = ""; + foreach (array_keys($enablesid) as $k1) { + foreach (array_keys($enablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_on'] = $tmp; + else + unset($a_rule[$id]['rule_sid_on']); + + $tmp = ""; + foreach (array_keys($disablesid) as $k1) { + foreach (array_keys($disablesid[$k1]) as $k2) + $tmp .= "{$k1}:{$k2}||"; + } + $tmp = rtrim($tmp, "||"); + + if (!empty($tmp)) + $a_rule[$id]['rule_sid_off'] = $tmp; + else + unset($a_rule[$id]['rule_sid_off']); + + write_config(); + + $_GET['openruleset'] = $currentruleset; + header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}"); + exit; +} + +if ($_GET['act'] == "resetall" && !empty($rules_map)) { + + // Remove all modified SIDs from config.xml and save the changes. + unset($a_rule[$id]['rule_sid_on']); + unset($a_rule[$id]['rule_sid_off']); + + /* Update the config.xml file. */ + write_config(); + + $_GET['openruleset'] = $currentruleset; + header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}"); + exit; +} + +if ($_POST['clear']) { + unset($a_rule[$id]['customrules']); + write_config(); + $rebuild_rules = true; + suricata_generate_yaml($a_rule[$id]); + $rebuild_rules = false; + header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}"); + exit; +} + +if ($_POST['customrules']) { + $a_rule[$id]['customrules'] = base64_encode($_POST['customrules']); + write_config(); + $rebuild_rules = true; + suricata_generate_yaml($a_rule[$id]); + $rebuild_rules = false; + $output = ""; + $retcode = ""; +// exec("/usr/local/bin/snort -T -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/snort.conf 2>&1", $output, $retcode); +// if (intval($retcode) != 0) { +// $error = ""; +// $start = count($output); +// $end = $start - 4; +// for($i = $start; $i > $end; $i--) +// $error .= $output[$i]; +// $input_errors[] = "Custom rules have errors:\n {$error}"; +// } +// else { +// header("Location: /snort/snort_rules.php?id={$id}&openruleset={$currentruleset}"); +// exit; +// } +} + +else if ($_POST['apply']) { + + /* Save new configuration */ + write_config(); + + /*************************************************/ + /* Update the suricata.yaml file and rebuild the */ + /* rules for this interface. */ + /*************************************************/ + $rebuild_rules = true; + suricata_generate_yaml($a_rule[$id]); + $rebuild_rules = false; + + /* Signal Suricata to "live reload" the rules */ + suricata_reload_config($a_rule[$id]); + + /* Return to this same page */ + header("Location: /suricata/suricata_rules.php?id={$id}&openruleset={$currentruleset}"); + exit; +} +else if ($_POST['cancel']) { + + /* Return to this same page */ + header("Location: /suricata/suricata_rules.php?id={$id}"); + exit; +} + +require_once("guiconfig.inc"); +include_once("head.inc"); + +$if_friendly = suricata_get_friendly_interface($pconfig['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} - Rules: {$currentruleset}"); +?> + + +' . $pgtitle . '

';} + +/* Display message */ +if ($input_errors) { + print_input_errors($input_errors); // TODO: add checks +} + +if ($savemsg) { + print_info_box($savemsg); +} + +?> + +
+ + '; + echo ' + + +
+
'; + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface ");; + $tab_array = array(); + $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), false, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), true, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), false, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + display_top_tabs($tab_array); + ?> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
      +
+ + + +
+ " title=" "/>   + " title=""/>   + " onclick="return confirm('')" title=""/> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
" class="formbtn" + title=""/> + +

+ " . + gettext("Suricata must be restarted to activate any SID enable/disable changes made on this tab."); ?>
+ "?> +   
+ "?> +   
+ "?> +   
+ "?> +   
+ + title="" width="17" height="17" border="0"> +   
 
" . gettext("WARNING: ") . "" . + gettext("You should not disable flowbit rules! Add Suppress List entries for them instead by ") . + "" . + gettext("clicking here") . ".";?>
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + $rulem) { + foreach ($rulem as $k2 => $v) { + $sid = suricata_get_sid($v['rule']); + $gid = suricata_get_gid($v['rule']); + + if (isset($disablesid[$gid][$sid])) { + $textss = ""; + $textse = ""; + $iconb = "icon_reject_d.gif"; + $disable_cnt++; + $title = gettext("Disabled by user. Click to toggle to default state"); + } + elseif (($v['disabled'] == 1) && (!isset($enablesid[$gid][$sid]))) { + $textss = ""; + $textse = ""; + $iconb = "icon_block_d.gif"; + $disable_cnt++; + $title = gettext("Disabled by default. Click to toggle to enabled state"); + } + elseif (isset($enablesid[$gid][$sid])) { + $textss = $textse = ""; + $iconb = "icon_reject.gif"; + $enable_cnt++; + $title = gettext("Enabled by user. Click to toggle to default state"); + } + else { + $textss = $textse = ""; + $iconb = "icon_block.gif"; + $enable_cnt++; + $title = gettext("Enabled by default. Click to toggle to disabled state"); + } + + // Pick off the first section of the rule (prior to the start of the MSG field), + // and then use a REGX split to isolate the remaining fields into an array. + $tmp = substr($v['rule'], 0, strpos($v['rule'], "(")); + $tmp = trim(preg_replace('/^\s*#+\s*/', '', $tmp)); + $rule_content = preg_split('/[\s]+/', $tmp); + + // Create custom tags for the fields we truncate so we can + // have a "title" attribute for tooltips to show the full string. + $srcspan = add_title_attribute($textss, $rule_content[2]); + $srcprtspan = add_title_attribute($textss, $rule_content[3]); + $dstspan = add_title_attribute($textss, $rule_content[5]); + $dstprtspan = add_title_attribute($textss, $rule_content[6]); + $protocol = $rule_content[1]; //protocol field + $source = truncate($rule_content[2], 14); //source field + $source_port = truncate($rule_content[3], 10); //source port field + $destination = truncate($rule_content[5], 14); //destination field + $destination_port = truncate($rule_content[6], 10); //destination port field + $message = suricata_get_msg($v['rule']); + $sid_tooltip = gettext("View the raw text for this rule"); + + echo " + + + + + + + + + + "; + $counter++; + } + } + unset($rulem, $v); ?> + +
 
{$textss} + + {$textse} + + {$textss}{$gid}{$textse} + + {$textss}{$sid}{$textse} + + {$textss}{$v['action']}{$textse} + + {$textss}{$protocol}{$textse} + + {$srcspan}{$source} + + {$srcprtspan}{$source_port} + + {$dstspan}{$destination} + + {$dstprtspan}{$destination_port} + + {$textss}{$message}{$textse} +
+
+ + + + + + + + + + + + + + + + + + + + + +
+
" . + gettext("Total Rules: {$counter}") . "    " . + gettext("Enabled: {$enable_cnt}") . "    " . + gettext("Disabled: {$disable_cnt}"); ?>
+
+
+
+
+ + + + + diff --git a/config/suricata/suricata_rules_edit.php b/config/suricata/suricata_rules_edit.php new file mode 100644 index 00000000..0dc4c57b --- /dev/null +++ b/config/suricata/suricata_rules_edit.php @@ -0,0 +1,154 @@ + + + + + + + + +
+ + + + +
+ + + + + + + + + + + +
Suricata: Rules Viewer
+ + +  ' . $displayfile; ?>     +
+
+ +
+
+
+
+ + + diff --git a/config/suricata/suricata_rules_flowbits.php b/config/suricata/suricata_rules_flowbits.php new file mode 100644 index 00000000..ca424344 --- /dev/null +++ b/config/suricata/suricata_rules_flowbits.php @@ -0,0 +1,306 @@ + 0) { + $rules_map = suricata_load_rules_map("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}"); + } + else + $savemsg = gettext("There are no flowbit-required rules necessary for the current enforcing rule set."); +} +else + $input_errors[] = gettext("Auto-Flowbit rule generation is disabled for this interface!"); + +if ($_GET['act'] == "addsuppress" && is_numeric($_GET['sidid']) && is_numeric($_GET['gen_id'])) { + $descr = suricata_get_msg($rules_map[$_GET['gen_id']][$_GET['sidid']]['rule']); + if (empty($descr)) + $suppress = "suppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n"; + else + $suppress = "# {$descr}\nsuppress gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}\n"; + if (!is_array($config['installedpackages']['suricata']['suppress'])) + $config['installedpackages']['suricata']['suppress'] = array(); + if (!is_array($config['installedpackages']['suricata']['suppress']['item'])) + $config['installedpackages']['suricata']['suppress']['item'] = array(); + $a_suppress = &$config['installedpackages']['suricata']['suppress']['item']; + $found_list = false; + + if (empty($a_nat[$id]['suppresslistname']) || $a_nat[$id]['suppresslistname'] == 'default') { + $s_list = array(); + $s_list['uuid'] = uniqid(); + $s_list['name'] = $a_nat[$id]['interface'] . "suppress" . "_" . $s_list['uuid']; + $s_list['descr'] = "Auto-generated list for Alert suppression"; + $s_list['suppresspassthru'] = base64_encode($suppress); + $a_suppress[] = $s_list; + $a_nat[$id]['suppresslistname'] = $s_list['name']; + $found_list = true; + } else { + /* If we get here, a Suppress List is defined for the interface so see if we can find it */ + foreach ($a_suppress as $a_id => $alist) { + if ($alist['name'] == $a_nat[$id]['suppresslistname']) { + $found_list = true; + if (!empty($alist['suppresspassthru'])) { + $tmplist = base64_decode($alist['suppresspassthru']); + $tmplist .= "\n{$suppress}"; + $alist['suppresspassthru'] = base64_encode($tmplist); + $a_suppress[$a_id] = $alist; + } + else { + $alist['suppresspassthru'] = base64_encode($suppress); + $a_suppress[$a_id] = $alist; + } + } + } + } + if ($found_list) { + write_config(); + $rebuild_rules = false; + sync_suricata_package_config(); + suricata_reload_config($a_nat[$id]); + $savemsg = gettext("An entry to suppress the Alert for 'gen_id {$_GET['gen_id']}, sig_id {$_GET['sidid']}' has been added to Suppress List '{$a_nat[$id]['suppresslistname']}'."); + } + else { + /* We did not find the defined list, so notify the user with an error */ + $input_errors[] = gettext("Suppress List '{$a_nat[$id]['suppresslistname']}' is defined for this interface, but it could not be found!"); + } +} + +function truncate($string, $length) { + + /******************************** + * This function truncates the * + * passed string to the length * + * specified adding ellipsis if * + * truncation was necessary. * + ********************************/ + if (strlen($string) > $length) + $string = substr($string, 0, ($length - 3)) . "..."; + return $string; +} + +/* Load up an array with the current Suppression List GID,SID values */ +$supplist = suricata_load_suppress_sigs($a_nat[$id]); + +$if_friendly = suricata_get_friendly_interface($a_nat[$id]['interface']); +$pgtitle = gettext("Suricata: Interface {$if_friendly} - Flowbit Rules"); +include_once("head.inc"); + +?> + + + +' . $pgtitle . '

';} +if ($input_errors) print_input_errors($input_errors); +if ($savemsg) + print_info_box($savemsg); +?> +
+
+ + + + +
+ + + + + + + + + + + + + + + + + 20): ?> + + + + +
+
+ + + + + + + + + + + + + + +
/> +
" . + gettext("Note: ") . "". gettext("the icon is only ") . + gettext("displayed for flowbit rules without the \"noalert\" option."); ?>
+
+ + + + + + + + + + + + + + + + + + + + + $rulem) { + foreach ($rulem as $k2 => $v) { + $sid = suricata_get_sid($v['rule']); + $gid = suricata_get_gid($v['rule']); + + // Pick off the first section of the rule (prior to the start of the MSG field), + // and then use a REGX split to isolate the remaining fields into an array. + $tmp = substr($v['rule'], 0, strpos($v['rule'], "(")); + $tmp = trim(preg_replace('/^\s*#+\s*/', '', $tmp)); + $rule_content = preg_split('/[\s]+/', $tmp); + + $protocol = $rule_content[1]; //protocol + $source = truncate($rule_content[2], 14); //source + $destination = truncate($rule_content[5], 14); //destination + $message = suricata_get_msg($v['rule']); + $flowbits = implode("; ", suricata_get_flowbits($v['rule'])); + if (strstr($flowbits, "noalert")) + $supplink = ""; + else { + if (!isset($supplist[$gid][$sid])) { + $supplink = ""; + $supplink .= ""; + } + else { + $supplink = ""; + } + } + + // Use "echo" to write the table HTML row-by-row. + echo "" . + "" . + "" . + "" . + "" . + "" . + "" . + ""; + $count++; + } + } + unset($rulem, $v); + ?> + +
{$sid} {$supplink}{$protocol}{$source}{$destination}{$flowbits}{$message}
+
+ /> + +
+
+
+
+ + + diff --git a/config/suricata/suricata_rulesets.php b/config/suricata/suricata_rulesets.php new file mode 100644 index 00000000..7ea34786 --- /dev/null +++ b/config/suricata/suricata_rulesets.php @@ -0,0 +1,596 @@ + 0) { + $btn_view_flowb_rules = " title=\"" . gettext("View flowbit-required rules") . "\""; + } + else + $btn_view_flowb_rules = " disabled"; +} +else + $btn_view_flowb_rules = " disabled"; + +// If a Snort VRT policy is enabled and selected, remove all Snort VRT +// rules from the configured rule sets to allow automatic selection. +if ($a_nat[$id]['ips_policy_enable'] == 'on') { + if (isset($a_nat[$id]['ips_policy'])) { + $disable_vrt_rules = "disabled"; + $enabled_sets = explode("||", $a_nat[$id]['rulesets']); + + foreach ($enabled_sets as $k => $v) { + if (substr($v, 0, 6) == "suricata_") + unset($enabled_sets[$k]); + } + $a_nat[$id]['rulesets'] = implode("||", $enabled_sets); + } +} +else + $disable_vrt_rules = ""; + +/* alert file */ +if ($_POST["Submit"]) { + + if ($_POST['ips_policy_enable'] == "on") { + $a_nat[$id]['ips_policy_enable'] = 'on'; + $a_nat[$id]['ips_policy'] = $_POST['ips_policy']; + } + else { + $a_nat[$id]['ips_policy_enable'] = 'off'; + unset($a_nat[$id]['ips_policy']); + } + + $enabled_items = ""; + if (is_array($_POST['toenable'])) + $enabled_items = implode("||", $_POST['toenable']); + else + $enabled_items = $_POST['toenable']; + + $a_nat[$id]['rulesets'] = $enabled_items; + + if ($_POST['autoflowbits'] == "on") + $a_nat[$id]['autoflowbitrules'] = 'on'; + else { + $a_nat[$id]['autoflowbitrules'] = 'off'; + if (file_exists("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}")) + @unlink("{$suricatadir}suricata_{$suricata_uuid}_{$if_real}/rules/{$flowbit_rules_file}"); + } + + write_config(); + + /*************************************************/ + /* Update the suricata.yaml file and rebuild the */ + /* rules for this interface. */ + /*************************************************/ + $rebuild_rules = true; + suricata_generate_yaml($a_nat[$id]); + $rebuild_rules = false; + + header("Location: /suricata/suricata_rulesets.php?id=$id"); + exit; +} + +if ($_POST['unselectall']) { + $a_nat[$id]['rulesets'] = ""; + + if ($_POST['ips_policy_enable'] == "on") { + $a_nat[$id]['ips_policy_enable'] = 'on'; + $a_nat[$id]['ips_policy'] = $_POST['ips_policy']; + } + else { + $a_nat[$id]['ips_policy_enable'] = 'off'; + unset($a_nat[$id]['ips_policy']); + } + + write_config(); + sync_suricata_package_config(); + + header("Location: /suricata/suricata_rulesets.php?id=$id"); + exit; +} + +if ($_POST['selectall']) { + $rulesets = array(); + + if ($_POST['ips_policy_enable'] == "on") { + $a_nat[$id]['ips_policy_enable'] = 'on'; + $a_nat[$id]['ips_policy'] = $_POST['ips_policy']; + } + else { + $a_nat[$id]['ips_policy_enable'] = 'off'; + unset($a_nat[$id]['ips_policy']); + } + + if ($emergingdownload == 'on') { + $files = glob("{$suricatadir}rules/" . ET_OPEN_FILE_PREFIX . "*.rules"); + foreach ($files as $file) + $rulesets[] = basename($file); + } + elseif ($etpro == 'on') { + $files = glob("{$suricatadir}rules/" . ET_PRO_FILE_PREFIX . "*.rules"); + foreach ($files as $file) + $rulesets[] = basename($file); + } + + if ($snortcommunitydownload == 'on') { + $files = glob("{$suricatadir}rules/" . GPL_FILE_PREFIX . "community.rules"); + foreach ($files as $file) + $rulesets[] = basename($file); + } + + /* Include the Snort VRT rules only if enabled and no IPS policy is set */ + if ($snortdownload == 'on' && $a_nat[$id]['ips_policy_enable'] == 'off') { + $files = glob("{$suricatadir}rules/" . VRT_FILE_PREFIX . "*.rules"); + foreach ($files as $file) + $rulesets[] = basename($file); + } + + $a_nat[$id]['rulesets'] = implode("||", $rulesets); + + write_config(); + sync_suricata_package_config(); + + header("Location: /suricata/suricata_rulesets.php?id=$id"); + exit; +} + +$enabled_rulesets_array = explode("||", $a_nat[$id]['rulesets']); + +$if_friendly = suricata_get_friendly_interface($pconfig['interface']); +$pgtitle = gettext("Suricata IDS: Interface {$if_friendly} - Categories"); +include_once("head.inc"); +?> + + + +' . $pgtitle . '

';} + +/* Display message */ +if ($input_errors) { + print_input_errors($input_errors); // TODO: add checks +} + +if ($savemsg) { + print_info_box($savemsg); +} + +?> + +
+ + +'; + echo ' + + + +
+
'; + $menu_iface=($if_friendly?substr($if_friendly,0,5)." ":"Iface "); + $tab_array = array(); + $tab_array[] = array($menu_iface . gettext("Settings"), false, "/suricata/suricata_interfaces_edit.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Categories"), true, "/suricata/suricata_rulesets.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Rules"), false, "/suricata/suricata_rules.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Flow/Stream"), false, "/suricata/suricata_flow_stream.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("App Parsers"), false, "/suricata/suricata_app_parsers.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Variables"), false, "/suricata/suricata_define_vars.php?id={$id}"); + $tab_array[] = array($menu_iface . gettext("Barnyard2"), false, "/suricata/suricata_barnyard.php?id={$id}"); + display_top_tabs($tab_array); +?> +
+
+ + + + + + + + + + + + + + + + +

+ ',$suricatadir,''); ?>

+ ' . gettext("Updates") . + '' . gettext(" tab to download the rules configured on the ") . + '' . gettext("Global") . + '' . gettext(" tab."); ?> +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \n"; + if (!empty($emergingrules[$j])) { + $file = $emergingrules[$j]; + echo "\n"; + echo "\n"; + } else + echo "\n"; + + if (!empty($snortrules[$j])) { + $file = $snortrules[$j]; + echo "\n"; + echo "\n"; + } else + echo "\n"; + echo "\n"; + } + ?> +

+ + + + + + + + + + + + + + + + + +
/> +   
  +
/> +   
  + " . gettext("Note: ") . "" . gettext("Auto-enabled rules generating unwanted alerts should have their GID:SID added to the Suppression List for the interface."); ?> +
+

+ + + + + + + + + + + + + + + + + +
+ onClick="enable_change()"/>   +
  + " . gettext("Note: ") . "" . gettext("You must be using the Snort VRT rules to use this option."); ?> +
+   
  +
+

+ + + + + + + +
"/>"/>"/>
+
+
+ />
"; + if(is_array($enabled_rulesets_array)) { + if(in_array($file, $enabled_rulesets_array)) + $CHECKED = " checked=\"checked\""; + else + $CHECKED = ""; + } else + $CHECKED = ""; + echo " \n\n"; + echo "\n"; + if (empty($CHECKED)) + echo $file; + else + echo "{$file}\n"; + echo "
"; + if(is_array($enabled_rulesets_array)) { + if (!empty($disable_vrt_rules)) + $CHECKED = $disable_vrt_rules; + elseif(in_array($file, $enabled_rulesets_array)) + $CHECKED = " checked=\"checked\""; + else + $CHECKED = ""; + } else + $CHECKED = ""; + echo " \n\n"; + echo "\n"; + if (empty($CHECKED) || $CHECKED == "disabled") + echo $file; + else + echo "{$file}\n"; + echo "
+
 
+ "/>
+
+
+
+ + + + + + diff --git a/config/suricata/suricata_select_alias.php b/config/suricata/suricata_select_alias.php new file mode 100644 index 00000000..f1fd4b93 --- /dev/null +++ b/config/suricata/suricata_select_alias.php @@ -0,0 +1,226 @@ + + + + +
+ + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + +

+
+ + + + + + + + + + + + + + + + + + "; + $textse = ""; + $disable = true; + $tooltip = gettext("Aliases representing a FQDN host cannot be used in Suricata configurations."); + } + else { + $textss = ""; + $textse = ""; + $disable = ""; + $selectablealias = true; + $tooltip = gettext("Selected entry will be imported. Click to toggle selection."); + } + ?> + + + + + + + + + + +
+ +
+ 10) { + echo "..."; + } + ?> + +   +
+
+ "/> +
+ "/>    + "/> +
+
+
+
+
+ + + diff --git a/config/suricata/suricata_suppress.php b/config/suricata/suricata_suppress.php new file mode 100644 index 00000000..58839dce --- /dev/null +++ b/config/suricata/suricata_suppress.php @@ -0,0 +1,172 @@ + + + + +' . $pgtitle . '

';} +if ($input_errors) { + print_input_errors($input_errors); +} + +?> + +
+ + + + + + + +
+ +
+ + + + + + + + + + + + + + + + + + +
+ +   + + + + + + +
">')">">
+
+ + + + + +
 ">
+
+
+

+



+

+
+ + + diff --git a/config/suricata/suricata_suppress_edit.php b/config/suricata/suricata_suppress_edit.php new file mode 100644 index 00000000..c2c23f10 --- /dev/null +++ b/config/suricata/suricata_suppress_edit.php @@ -0,0 +1,213 @@ + + + + +' . $pgtitle . '

';} + +if ($input_errors) print_input_errors($input_errors); +if ($savemsg) + print_info_box($savemsg); + +?> +
+ + + +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + +
Add the name and description of the file.

+    +

+
+ +   +
+ suppress gen_id 1, sig_id 1852, track by_src, ip 10.1.1.54
+ event_filter gen_id 1, sig_id 1851, type limit, + track by_src, count 1, seconds 60
+ rate_filter gen_id 135, sig_id 1, track by_src, + count 100, seconds 1, new_action log, timeout 10
+
   + +
+
+
+
+ + + + diff --git a/config/suricata/suricata_uninstall.php b/config/suricata/suricata_uninstall.php new file mode 100644 index 00000000..808aefec --- /dev/null +++ b/config/suricata/suricata_uninstall.php @@ -0,0 +1,133 @@ + diff --git a/config/suricata/suricata_yaml_template.inc b/config/suricata/suricata_yaml_template.inc new file mode 100644 index 00000000..e62c48eb --- /dev/null +++ b/config/suricata/suricata_yaml_template.inc @@ -0,0 +1,302 @@ + %A:%P" + filetype: regular + + - pcap-log: + enabled: {$pcap_log_enabled} + filename: log.pcap + limit: {$pcap_log_limit_size}mb + max-files: {$pcap_log_max_files} + mode: normal + + - tls-log: + enabled: {$tls_log_enabled} + filename: tls.log + extended: {$tls_log_extended} + certs-log-dir: certs + + - stats: + enabled: {$stats_log_enabled} + filename: stats.log + interval: {$stats_upd_interval} + append: {$stats_log_append} + + - syslog: + enabled: {$alert_syslog} + identity: suricata + facility: auth + level: Info + + - drop: + enabled: no + filename: drop.log + append: yes + filetype: regular + + - file-store: + enabled: {$file_store_enabled} + log-dir: files + force-magic: no + force-md5: no + waldo: file.waldo + + - file-log: + enabled: {$json_log_enabled} + filename: files-json.log + append: {$json_log_append} + filetype: regular + force-magic: {$json_log_magic} + force-md5: {$json_log_md5} + +# Magic file. The extension .mgc is added to the value here. +magic-file: {$suricatacfgdir}/magic + +# Specify a threshold config file +threshold-file: {$suricatacfgdir}/threshold.config + +detect-engine: + - profile: {$detect_eng_profile} + - sgh-mpm-context: {$sgh_mpm_ctx} + - inspection-recursion-limit: {$inspection_recursion_limit} + - rule-reload: true + - delayed-detect: yes + +# Suricata is multi-threaded. Here the threading can be influenced. +threading: + set-cpu-affinity: no + detect-thread-ratio: 1.5 + +mpm-algo: ac + +pattern-matcher: + - b2gc: + search-algo: B2gSearchBNDMq + hash-size: low + bf-size: medium + - b2gm: + search-algo: B2gSearchBNDMq + hash-size: low + bf-size: medium + - b2g: + search-algo: B2gSearchBNDMq + hash-size: low + bf-size: medium + - b3g: + search-algo: B3gSearchBNDMq + hash-size: low + bf-size: medium + - wumanber: + hash-size: low + bf-size: medium + +# Defrag settings: +defrag: + memcap: {$frag_memcap} + hash-size: {$frag_hash_size} + trackers: {$ip_max_trackers} + max-frags: {$ip_max_frags} + prealloc: yes + timeout: {$ip_frag_timeout} + +# Flow settings: +flow: + memcap: {$flow_memcap} + hash-size: {$flow_hash_size} + prealloc: {$flow_prealloc} + emergency-recovery: {$flow_emerg_recovery} + prune-flows: {$flow_prune} + +# Specific timeouts for flows. +flow-timeouts: + default: + new: 30 + established: 300 + closed: 0 + emergency-new: 10 + emergency-established: 100 + emergency-closed: 0 + tcp: + new: {$flow_tcp_new_timeout} + established: {$flow_tcp_established_timeout} + closed: {$flow_tcp_closed_timeout} + emergency-new: {$flow_tcp_emerg_new_timeout} + emergency-established: {$flow_tcp_emerg_established_timeout} + emergency-closed: {$flow_tcp_emerg_closed_timeout} + udp: + new: {$flow_udp_new_timeout} + established: {$flow_udp_established_timeout} + emergency-new: {$flow_udp_emerg_new_timeout} + emergency-established: {$flow_udp_emerg_established_timeout} + icmp: + new: {$flow_icmp_new_timeout} + established: {$flow_icmp_established_timeout} + emergency-new: {$flow_icmp_emerg_new_timeout} + emergency-established: {$flow_icmp_emerg_established_timeout} + +stream: + memcap: {$stream_memcap} + checksum-validation: no + inline: auto + max-sessions: {$stream_max_sessions} + prealloc-sessions: {$stream_prealloc_sessions} + midstream: {$stream_enable_midstream} + async-oneside: {$stream_enable_async} + +reassembly: + memcap: {$reassembly_memcap} + depth: {$reassembly_depth} + toserver-chunk-size: {$reassembly_to_server_chunk} + toclient-chunk-size: {$reassembly_to_client_chunk} + +# Host table is used by tagging and per host thresholding subsystems. +host: + hash-size: 4096 + prealloc: 1000 + memcap: 16777216 + +# Host specific policies for defragmentation and TCP stream reassembly. +host-os-policy: + {$host_os_policy} + +# Logging configuration. This is not about logging IDS alerts, but +# IDS output about what its doing, errors, etc. +logging: + + # This value is overriden by the SC_LOG_LEVEL env var. + default-log-level: info + default-log-format: "%t - <%d> -- " + + # Define your logging outputs. + outputs: + - console: + enabled: yes + - file: + enabled: yes + filename: {$suricatalogdir}suricata_{$if_real}{$suricata_uuid}/suricata.log + - syslog: + enabled: {$suricata_use_syslog} + facility: auth + format: "[%i] <%d> -- " + +pcap: + - interface: {$if_real} + checksum-checks: auto + +# For FreeBSD ipfw(8) divert(4) support. +# ipfw add 100 divert 8000 ip from any to any +# +# The 8000 above should be the same number you passed on the command +# line, i.e. -d 8000 +# +#ipfw: + +default-rule-path: {$suricatacfgdir}/rules +rule-files: + - {$rules_files} + +classification-file: {$suricatacfgdir}/classification.config +reference-config-file: {$suricatacfgdir}/reference.config + +# Holds variables that would be used by the engine. +vars: + + # Holds the address group vars that would be passed in a Signature. + address-groups: + HOME_NET: "[{$home_net}]" + EXTERNAL_NET: "{$external_net}" + {$addr_vars} + + # Holds the port group vars that would be passed in a Signature. + port-groups: + {$port_vars} + +# Set the order of alerts bassed on actions +action-order: + - pass + - drop + - reject + - alert + +# IP Reputation +#reputation-categories-file: {$suricatacfgdir}/iprep/categories.txt +#default-reputation-path: {$suricatacfgdir}/iprep +#reputation-files: +# - reputation.list + +# Limit for the maximum number of asn1 frames to decode (default 256) +asn1-max-frames: {$asn1_max_frames} + +engine-analysis: + rules-fast-pattern: yes + rules: yes + +#recursion and match limits for PCRE where supported +pcre: + match-limit: 3500 + match-limit-recursion: 1500 + +########################################################################### +# Configure libhtp. +libhtp: + default-config: + {$http_hosts_default_policy} + + {$http_hosts_policy} + +coredump: + max-dump: unlimited + +EOD; + +?> -- cgit v1.2.3