diff options
Diffstat (limited to 'config/snort')
-rwxr-xr-x | config/snort/snort.inc | 296 | ||||
-rwxr-xr-x | config/snort/snort.xml | 4 | ||||
-rwxr-xr-x | config/snort/snort_alerts.php | 53 | ||||
-rw-r--r-- | config/snort/snort_blocked.php | 6 | ||||
-rwxr-xr-x | config/snort/snort_check_for_rule_updates.php | 71 | ||||
-rwxr-xr-x | config/snort/snort_define_servers.php | 55 | ||||
-rw-r--r-- | config/snort/snort_interfaces_suppress.php | 49 | ||||
-rwxr-xr-x | config/snort/snort_preprocessors.php | 26 | ||||
-rwxr-xr-x | config/snort/snort_rules.php | 19 |
9 files changed, 434 insertions, 145 deletions
diff --git a/config/snort/snort.inc b/config/snort/snort.inc index f1f5ad9b..d69f6237 100755 --- a/config/snort/snort.inc +++ b/config/snort/snort.inc @@ -47,7 +47,7 @@ global $rebuild_rules; /* package version */ $snort_version = "2.9.4.6"; -$pfSense_snort_version = "2.5.9"; +$pfSense_snort_version = "2.6.0"; $snort_package_version = "Snort {$snort_version} pkg v. {$pfSense_snort_version}"; // Define SNORTDIR and SNORTLIBDIR constants according to FreeBSD version (PBI support or no PBI) @@ -83,6 +83,101 @@ $rebuild_rules = false; if (!is_array($config['installedpackages']['snortglobal'])) $config['installedpackages']['snortglobal'] = array(); +function snort_get_alias_value($alias) { + /***************************************************/ + /* This function returns the value of the passed */ + /* Alias, or an empty string if the value cannot */ + /* be determined. */ + /* */ + /* On Entry: $alias ==> Alias to be evaluated */ + /* Returns: Alias value as a string or an empty */ + /* string */ + /***************************************************/ + + global $config; + + $entries = array(); + $tmp = ""; + + // If no Aliases are defined in the configuration, + // return an empty string. + if (empty($config['aliases'])) + return $tmp; + + // See if we were passed a valid Alias and return + // an empty string if not. + if (!is_alias($alias)) + return $tmp; + + // We have a valid Alias, so find its value or + // values and return as a string. + return snort_unpack_alias($alias); +} + +function snort_unpack_alias($alias) { + + /**************************************************/ + /* This function unpacks an Alias to determine */ + /* the actual values it represents. Any nested */ + /* Aliases encountered are also unpacked via */ + /* recursive calls to this function. */ + /* */ + /* Fully-qualified-domain-name (FQDN) aliases */ + /* are detected and resolved via a pfctl() call. */ + /**************************************************/ + + global $config; + $value = ""; + + // Find the matching Alias entry in config + foreach ($config['aliases']['alias'] as $aliased) { + if($aliased['name'] == $alias) { + $addr = array(); + $addr = explode(" ", trim($aliased['address'])); + foreach ($addr as $a) { + if (!is_alias($a) && !empty($a)) { + if (is_ipaddr($a) || is_subnet($a) || is_port($a)) + // If address, subnet or port, we found the final value + $value .= $a . " "; + elseif (is_hostname($a)) { + // Found a FQDN value for this Alias, so resolve it + $entries = array(); + exec("/sbin/pfctl -t " . escapeshellarg($alias) . " -T show", $entries); + $value .= trim(implode(" ", $entries)); + } + else + continue; + } + elseif (is_alias($a)) + // Found a nested Alias, so recursively resolve it + $value .= snort_unpack_alias($a) . " "; + } + return trim($value); + } + } + return $value; +} + +function snort_is_single_addr_alias($alias) { + /***************************************************/ + /* This function evaluates the passed Alias to */ + /* determine if it represents a single IP address, */ + /* or a network in CIDR form, and returns TRUE if */ + /* the condition is met, and FALSE if not. */ + /* */ + /* On Entry: $alias ==> Alias to be evaluated */ + /* Returns: TRUE if Alias represents a single */ + /* IP address or network, and FALSE */ + /* if not. */ + /***************************************************/ + + /* If spaces in expanded Alias, it's not a single entity */ + if (strpos(snort_get_alias_value($alias), " ") !== false) + return false; + else + return true; +} + function snort_get_blocked_ips() { $blocked_ips = ""; exec('/sbin/pfctl -t snort2c -T show', $blocked_ips); @@ -164,8 +259,13 @@ function snort_load_suppress_sigs($snortcfg, $track_by=false) { 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 (!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 */ @@ -176,8 +276,17 @@ function snort_load_suppress_sigs($snortcfg, $track_by=false) { $sigid = $matches[2]; $whichip = trim($matches[3]); $ip = $matches[4]; - if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip)) + 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)) { @@ -185,8 +294,17 @@ function snort_load_suppress_sigs($snortcfg, $track_by=false) { $sigid = $matches[2]; $whichip = trim($matches[3]); $ip = trim($matches[4]); - if (!empty($genid) && !empty($sigid) && !empty($whichip) && !empty($ip)) + 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"; + } } } } @@ -241,7 +359,7 @@ function snort_build_list($snortcfg, $listname = "", $whitelist = false) { $vips = $list['vips']; $vpns = $list['vpnips']; if (!empty($list['address']) && is_alias($list['address'])) { - $home_net = explode(" ", trim(filter_expand_alias($list['address']))); + $home_net = explode(" ", trim(snort_get_alias_value($list['address']))); } } @@ -1769,24 +1887,33 @@ function snort_modify_sids(&$rule_map, $snortcfg) { unset($enablesid, $disablesid); } -/* Start of main config files */ -/* open snort.sh for writing" */ function snort_create_rc() { + + /*********************************************************/ + /* This function builds the /usr/local/etc/rc.d/snort.sh */ + /* shell script for starting and stopping Snort. The */ + /* script is rebuilt on each package sync operation and */ + /* after any changes to snort.conf saved in the GUI. */ + /*********************************************************/ + global $config, $g; $snortdir = SNORTDIR; $rcdir = RCFILEPREFIX; + // If no interfaces are configured for Snort, exit if (!is_array($config['installedpackages']['snortglobal']['rule'])) return; - - $snortconf =& $config['installedpackages']['snortglobal']['rule']; - /* do not start config build if rules is empty */ + $snortconf = $config['installedpackages']['snortglobal']['rule']; if (empty($snortconf)) return; + // At least one interface is configured, so OK $start_snort_iface_start = array(); $start_snort_iface_stop = array(); + + // Loop thru each configured interface and build + // the shell script. foreach ($snortconf as $value) { $snort_uuid = $value['uuid']; $if_real = snort_get_real_interface($value['interface']); @@ -1794,7 +1921,7 @@ function snort_create_rc() { $start_barnyard = <<<EOE if [ ! -f {$g['varrun_path']}/barnyard2_{$if_real}{$snort_uuid}.pid ]; then - pid=`/bin/pgrep -xf '/usr/local/bin/barnyard2 -r {$snort_uuid} -f snort_{$snort_uuid}_{$if_real}.u2 --pid-path {$g['varrun_path']} --nolock-pidfile -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/barnyard2.conf -d /var/log/snort/snort_{$if_real}{$snort_uuid} -D -q' > {$g['varrun_path']}/barnyard2_{$if_real}{$snort_uuid}.pid` + pid=`/bin/pgrep -f "barnyard2 -r {$snort_uuid} "` else pid=`/bin/pgrep -F {$g['varrun_path']}/barnyard2_{$if_real}{$snort_uuid}.pid` fi @@ -1835,9 +1962,9 @@ EOE; /bin/rm /var/run/barnyard2_{$if_real}{$snort_uuid}.pid fi else - pid=`/bin/pgrep -xf '/usr/local/bin/barnyard2 -r {$snort_uuid} -f snort_{$snort_uuid}_{$if_real}.u2 --pid-path {$g['varrun_path']} --nolock-pidfile -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/barnyard2.conf -d /var/log/snort/snort_{$if_real}{$snort_uuid} -D -q'` + pid=`/bin/pgrep -f "barnyard2 -r {$snort_uuid} "` if [ ! -z \$pid ]; then - /bin/pkill -xf '/usr/local/bin/barnyard2 -r {$snort_uuid} -f snort_{$snort_uuid}_{$if_real}.u2 --pid-path {$g['varrun_path']} --nolock-pidfile -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/barnyard2.conf -d /var/log/snort/snort_{$if_real}{$snort_uuid} -D -q' + /bin/pkill -f "barnyard2 -r {$snort_uuid} " time=0 timeout=30 while kill -0 \$pid 2>/dev/null; do sleep 1 @@ -1860,10 +1987,11 @@ EOE; ###### For Each Iface # Start snort and barnyard2 if [ ! -f {$g['varrun_path']}/snort_{$if_real}{$snort_uuid}.pid ]; then - pid=`/bin/pgrep -xf '/usr/local/bin/snort -R {$snort_uuid} -D -q -l /var/log/snort/snort_{$if_real}{$snort_uuid} --pid-path {$g['varrun_path']} --nolock-pidfile -G {$snort_uuid} -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/snort.conf -i {$if_real}'` + pid=`/bin/pgrep -f "snort -R {$snort_uuid} "` else pid=`/bin/pgrep -F {$g['varrun_path']}/snort_{$if_real}{$snort_uuid}.pid` fi + if [ ! -z \$pid ]; then /usr/bin/logger -p daemon.info -i -t SnortStartup "Snort SOFT RESTART for {$value['descr']}({$snort_uuid}_{$if_real})..." /bin/pkill -HUP \$pid @@ -1895,10 +2023,10 @@ EOE; /bin/rm /var/run/snort_{$if_real}{$snort_uuid}.pid fi else - pid=`/bin/pgrep -xf '/usr/local/bin/snort -R {$snort_uuid} -D -q -l /var/log/snort/snort_{$if_real}{$snort_uuid} --pid-path {$g['varrun_path']} --nolock-pidfile -G {$snort_uuid} -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/snort.conf -i {$if_real}'` + pid=`/bin/pgrep -f "snort -R {$snort_uuid} "` if [ ! -z \$pid ]; then /usr/bin/logger -p daemon.info -i -t SnortStartup "Snort STOP for {$value['descr']}({$snort_uuid}_{$if_real})..." - /bin/pkill -xf '/usr/local/bin/snort -R {$snort_uuid} -D -q -l /var/log/snort/snort_{$if_real}{$snort_uuid} --pid-path {$g['varrun_path']} --nolock-pidfile -G {$snort_uuid} -c {$snortdir}/snort_{$snort_uuid}_{$if_real}/snort.conf -i {$if_real}' + /bin/pkill -f "snort -R {$snort_uuid} " time=0 timeout=30 while kill -0 \$pid 2>/dev/null; do sleep 1 @@ -1925,7 +2053,7 @@ EOE; # This file was automatically generated # by the pfSense service handler. # Code added to protect from double starts on pfSense bootup -######## Begining of Main snort.sh +######## Start of main snort.sh rc_start() { {$rc_start} @@ -2236,6 +2364,10 @@ function snort_prepare_rule_files($snortcfg, $snortcfgdir) { log_error('[Snort] Enabling any flowbit-required rules for: ' . snort_get_friendly_interface($snortcfg['interface']) . '...'); $fbits = snort_resolve_flowbits($all_rules, $enabled_rules); + /* Check for and disable any flowbit-required rules the user has */ + /* manually forced to a disabled state. */ + snort_modify_sids($fbits, $snortcfg); + /* Check for and disable any flowbit-required rules dependent upon */ /* disabled preprocessors if this option is enabled for the interface. */ if ($snortcfg['preproc_auto_rule_disable'] == "on") { @@ -2548,14 +2680,15 @@ function snort_generate_conf($snortcfg) { $ssh_port = "22"; $snort_ports = array( "dns_ports" => "53", "smtp_ports" => "25", "mail_ports" => "25,143,465,691", - "http_ports" => "80,901,3128,8080,9000", "oracle_ports" => "1521", "mssql_ports" => "1433", - "telnet_ports" => "23","snmp_ports" => "161", "ftp_ports" => "21", + "http_ports" => "36,80,81,82,83,84,85,86,87,88,89,90,311,383,591,593,631,901,1220,1414,1741,1830,2301,2381,2809,3037,3057,3128,3443,3702,4343,4848,5250,6080,6988,7000,7001,7144,7145,7510,7777,7779,8000,8008,8014,8028,8080,8085,8088,8090,8118,8123,8180,8181,8222,8243,8280,8300,8500,8800,8888,8899,9000,9060,9080,9090,9091,9443,9999,10000,11371,34443,34444,41080,50000,50002,55555", + "oracle_ports" => "1024:", "mssql_ports" => "1433", + "telnet_ports" => "23","snmp_ports" => "161", "ftp_ports" => "21,2100,3535", "ssh_ports" => $ssh_port, "pop2_ports" => "109", "pop3_ports" => "110", "imap_ports" => "143", "sip_proxy_ports" => "5060:5090,16384:32768", - "sip_ports" => "5060,5061", "auth_ports" => "113", "finger_ports" => "79", + "sip_ports" => "5060,5061, 5600", "auth_ports" => "113", "finger_ports" => "79", "irc_ports" => "6665,6666,6667,6668,6669,7000", "smb_ports" => "139,445", "nntp_ports" => "119", "rlogin_ports" => "513", "rsh_ports" => "514", - "ssl_ports" => "443,465,563,636,989,990,992,993,994,995", + "ssl_ports" => "443,465,563,636,989,992,993,994,995,7801,7802,7900,7901,7902,7903,7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920", "file_data_ports" => "\$HTTP_PORTS,110,143", "shellcode_ports" => "!80", "sun_rpc_ports" => "111,32770,32771,32772,32773,32774,32775,32776,32777,32778,32779", "DCERPC_NCACN_IP_TCP" => "139,445", "DCERPC_NCADG_IP_UDP" => "138,1024:", @@ -2568,7 +2701,7 @@ function snort_generate_conf($snortcfg) { $portvardef = ""; foreach ($snort_ports as $alias => $avalue) { if (!empty($snortcfg["def_{$alias}"]) && is_alias($snortcfg["def_{$alias}"])) - $snort_ports[$alias] = filter_expand_alias($snortcfg["def_{$alias}"]); + $snort_ports[$alias] = snort_get_alias_value($snortcfg["def_{$alias}"]); $snort_ports[$alias] = preg_replace('/\s+/', ',', trim($snort_ports[$alias])); $portvardef .= "portvar " . strtoupper($alias) . " [" . $snort_ports[$alias] . "]\n"; } @@ -2633,19 +2766,23 @@ preprocessor http_inspect_server: server default profile {$http_server_profile} EOD; /* def ftp_preprocessor */ + $telnet_ports = str_replace(",", " ", $snort_ports['telnet_ports']); + $ftp_ports = str_replace(",", " ", $snort_ports['ftp_ports']); $ftp_preprocessor = <<<EOD -# ftp preprocessor # +# ftp_telnet preprocessor # preprocessor ftp_telnet: global \ inspection_type stateless preprocessor ftp_telnet_protocol: telnet \ - normalize \ - ayt_attack_thresh 200 + normalize ports { {$telnet_ports} } \ + ayt_attack_thresh 20 \ + detect_anomalies -preprocessor ftp_telnet_protocol: \ - ftp server default \ +preprocessor ftp_telnet_protocol: ftp server default \ def_max_param_len 100 \ - ports { 21 } \ + ports { $ftp_ports } \ + telnet_cmds yes \ + ignore_telnet_erase_cmds yes \ ftp_cmds { USER PASS ACCT CWD SDUP SMNT QUIT REIN PORT PASV TYPE STRU MODE } \ ftp_cmds { RETR STOR STOU APPE ALLO REST RNFR RNTO ABOR DELE RMD MKD PWD } \ ftp_cmds { LIST NLST SITE SYST STAT HELP NOOP } \ @@ -2676,12 +2813,14 @@ preprocessor ftp_telnet_protocol: \ preprocessor ftp_telnet_protocol: ftp client default \ max_resp_len 256 \ bounce yes \ + ignore_telnet_erase_cmds yes \ telnet_cmds yes EOD; $pop_ports = str_replace(",", " ", $snort_ports['pop3_ports']); $pop_preproc = <<<EOD +# POP preprocessor # preprocessor pop: \ ports { {$pop_ports} } \ memcap 1310700 \ @@ -2693,6 +2832,7 @@ EOD; $imap_ports = str_replace(",", " ", $snort_ports['imap_ports']); $imap_preproc = <<<EOD +# IMAP preprocessor # preprocessor imap: \ ports { {$imap_ports} } \ memcap 1310700 \ @@ -2711,10 +2851,12 @@ preprocessor SMTP: \ inspection_type stateful \ normalize cmds \ ignore_tls_data \ - valid_cmds { MAIL RCPT HELP HELO ETRN EHLO EXPN VRFY ATRN SIZE BDAT DEBUG EMAL ESAM ESND ESOM EVFY IDENT NOOP RSET SEND SAML SOML AUTH TURN ETRN PIPELINING \ -CHUNKING DATA DSN RSET QUIT ONEX QUEU STARTTLS TICK TIME TURNME VERB X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUEU XSTA XTRN XUSR } \ - normalize_cmds { MAIL RCPT HELP HELO ETRN EHLO EXPN VRFY ATRN SIZE BDAT DEBUG EMAL ESAM ESND ESOM EVFY IDENT NOOP RSET SEND SAML SOML AUTH TURN ETRN \ -PIPELINING CHUNKING DATA DSN RSET QUIT ONEX QUEU STARTTLS TICK TIME TURNME VERB X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUEU XSTA XTRN XUSR } \ + valid_cmds { MAIL RCPT HELP HELO ETRN EHLO EXPN VRFY ATRN SIZE BDAT DEBUG EMAL ESAM ESND ESOM EVFY IDENT NOOP RSET \ + SEND SAML SOML AUTH TURN ETRN PIPELINING CHUNKING DATA DSN RSET QUIT ONEX QUEU STARTTLS TICK TIME \ + TURNME VERB X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUEU XSTA XTRN XUSR } \ + normalize_cmds { MAIL RCPT HELP HELO ETRN EHLO EXPN VRFY ATRN SIZE BDAT DEBUG EMAL ESAM ESND ESOM EVFY IDENT NOOP \ + RSET SEND SAML SOML AUTH TURN ETRN PIPELINING CHUNKING DATA DSN RSET QUIT ONEX QUEU STARTTLS TICK \ + TIME TURNME VERB X-EXPS X-LINK2STATE XADR XAUTH XCIR XEXCH50 XGEN XLICENSE XQUEU XSTA XTRN XUSR } \ max_header_line_len 1000 \ max_response_line_len 512 \ alt_max_command_line_len 260 { MAIL } \ @@ -2752,12 +2894,12 @@ EOD; $sf_pscan_sense_level = $snortcfg['pscan_sense_level']; $sf_pscan_ignore_scanners = "\$HOME_NET"; if (!empty($snortcfg['pscan_ignore_scanners']) && is_alias($snortcfg['pscan_ignore_scanners'])) { - $sf_pscan_ignore_scanners = filter_expand_alias($snortcfg['pscan_ignore_scanners']); + $sf_pscan_ignore_scanners = snort_get_alias_value($snortcfg['pscan_ignore_scanners']); $sf_pscan_ignore_scanners = preg_replace('/\s+/', ',', trim($sf_pscan_ignore_scanners)); } $sf_portscan = <<<EOD -# sf Portscan # +# sf Portscan preprocessor # preprocessor sfportscan: scan_type { {$sf_pscan_type} } \ proto { {$sf_pscan_protocol} } \ memcap { {$sf_pscan_memcap} } \ @@ -2766,21 +2908,34 @@ preprocessor sfportscan: scan_type { {$sf_pscan_type} } \ EOD; - $sun_rpc_ports = str_replace(",", " ", $snort_ports['sun_rpc_ports']); + /* def ssh_preproc */ + $ssh_ports = str_replace(",", " ", $snort_ports['ssh_ports']); + $ssh_preproc = <<<EOD +# SSH preprocessor # +preprocessor ssh: server_ports { {$ssh_ports} } \ + autodetect \ + max_client_bytes 19600 \ + max_encrypted_packets 20 \ + max_server_version_len 100 \ + enable_respoverflow enable_ssh1crc32 \ + enable_srvoverflow enable_protomismatch + +EOD; + /* def other_preprocs */ + $sun_rpc_ports = str_replace(",", " ", $snort_ports['sun_rpc_ports']); $other_preprocs = <<<EOD - # Other preprocs # preprocessor rpc_decode: {$sun_rpc_ports} no_alert_multiple_requests no_alert_large_fragments no_alert_incomplete -# Back Orifice +# Back Orifice preprocessor # preprocessor bo EOD; /* def dce_rpc_2 */ $dce_rpc_2 = <<<EOD -# DCE/RPC 2 # +# DCE/RPC 2 # preprocessor dcerpc2: memcap 102400, events [co] preprocessor dcerpc2_server: default, policy WinXP, \ detect [smb [{$snort_ports['smb_ports']}], tcp 135, udp 135, rpc-over-http-server 593], \ @@ -2791,11 +2946,39 @@ EOD; $sip_ports = str_replace(",", " ", $snort_ports['sip_ports']); $sip_preproc = <<<EOD -# SIP preprocessor -preprocessor sip: ports { {$sip_ports} }, max_call_id_len 300, \ - max_from_len 100, max_to_len 200, max_via_len 1000, \ - max_requestName_len 50, max_uri_len 100, ignore_call_channel,\ - max_content_len 1000 +# SIP preprocessor # +preprocessor sip: max_sessions 40000, \ + ports { {$sip_ports} }, \ + methods { invite \ + cancel \ + ack \ + bye \ + register \ + options \ + refer \ + subscribe \ + update \ + join \ + info \ + message \ + notify \ + benotify \ + do \ + qauth \ + sprack \ + publish \ + service \ + unsubscribe \ + prack }, \ + max_call_id_len 80, \ + max_from_len 256, \ + max_to_len 256, \ + max_via_len 1024, \ + max_requestName_len 50, \ + max_uri_len 512, \ + ignore_call_channel, \ + max_content_len 2048, \ + max_contact_len 512 EOD; @@ -2837,10 +3020,13 @@ preprocessor gtp: ports { {$gtp_ports} } EOD; - $def_ssl_ports_ignore = str_replace(",", " ", $snort_ports['ssl_ports']); + /* def ssl_preprocessor */ + $ssl_ports = str_replace(",", " ", $snort_ports['ssl_ports']); $ssl_preproc = <<<EOD -# Ignore SSL and Encryption # -preprocessor ssl: ports { {$def_ssl_ports_ignore} }, trustservers, noinspect_encrypted +# SSL preprocessor # +preprocessor ssl: \ + ports { {$ssl_ports} }, \ + trustservers, noinspect_encrypted EOD; @@ -2872,7 +3058,7 @@ EOD; $vardef = ""; foreach ($snort_servers as $alias => $avalue) { if (!empty($snortcfg["def_{$alias}"]) && is_alias($snortcfg["def_{$alias}"])) { - $avalue = filter_expand_alias($snortcfg["def_{$alias}"]); + $avalue = snort_get_alias_value($snortcfg["def_{$alias}"]); $avalue = str_replace(" ", ",", trim($avalue)); } $vardef .= "var " . strtoupper($alias) . " [{$avalue}]\n"; @@ -2885,7 +3071,7 @@ EOD; "ssl_preproc" => "ssl_preproc", "dnp3_preproc" => "dnp3_preproc", "modbus_preproc" => "modbus_preproc" ); $snort_preproc = array ( - "perform_stat", "http_inspect", "other_preprocs", "ftp_preprocessor", "smtp_preprocessor", "ssl_preproc", "sip_preproc", "gtp_preproc", + "perform_stat", "http_inspect", "other_preprocs", "ftp_preprocessor", "smtp_preprocessor", "ssl_preproc", "sip_preproc", "gtp_preproc", "ssh_preproc", "sf_portscan", "dce_rpc_2", "dns_preprocessor", "sensitive_data", "pop_preproc", "imap_preproc", "dnp3_preproc", "modbus_preproc" ); $default_disabled_preprocs = array( @@ -3071,7 +3257,7 @@ EOD; # snort configuration file # generated automatically by the pfSense subsystems do not modify manually -# Define Local Network # +# Define Local Network # var HOME_NET [{$home_net}] var EXTERNAL_NET [{$external_net}] @@ -3079,16 +3265,16 @@ var EXTERNAL_NET [{$external_net}] var RULE_PATH {$snortcfgdir}/rules var PREPROC_RULE_PATH {$snortcfgdir}/preproc_rules -# Define Servers # +# Define Servers # {$vardef} -# Define Server Ports # +# Define Server Ports # {$portvardef} # Configure quiet startup mode # config quiet -# Configure the snort decoder # +# Configure the snort decoder # config checksum_mode: {$cksumcheck} config disable_decode_alerts config disable_tcpopt_experimental_alerts @@ -3098,14 +3284,14 @@ config disable_tcpopt_alerts config disable_ipopt_alerts config disable_decode_drops -# Enable the GTP decoder # +# Enable the GTP decoder # config enable_gtp # Configure PCRE match limitations config pcre_match_limit: 3500 config pcre_match_limit_recursion: 1500 -# Configure the detection engine # +# Configure the detection engine # config detection: {$cfg_detect_settings} config event_queue: max_queue 8 log 5 order_events content_length @@ -3134,7 +3320,7 @@ preprocessor frag3_global: {$frag3_memcap}, {$frag3_max_frags}{$frag3_disabled} preprocessor frag3_engine: {$frag3_policy} detect_anomalies {$frag3_timeout} {$frag3_overlap_limit} {$frag3_min_frag_len} preprocessor stream5_global:{$stream5_reassembly} track_tcp {$stream5_track_tcp}, track_udp {$stream5_track_udp}, track_icmp {$stream5_track_icmp}, max_tcp 262144, max_udp 131072, max_active_responses 2, min_response_seconds 5{$stream5_mem_cap} -preprocessor stream5_tcp: {$stream5_policy}, {$stream5_overlap_limit}, {$stream5_tcp_timeout}, ports both all{$stream5_max_queued_bytes_type}{$stream5_max_queued_segs_type}{$stream5_require_3whs}{$stream5_no_reassemble_async}$stream5_dont_store_lg_pkts +preprocessor stream5_tcp: {$stream5_policy}, {$stream5_overlap_limit}, {$stream5_tcp_timeout}, ports both all{$stream5_max_queued_bytes_type}{$stream5_max_queued_segs_type}{$stream5_require_3whs}{$stream5_no_reassemble_async}{$stream5_dont_store_lg_pkts} preprocessor stream5_udp: {$stream5_udp_timeout} preprocessor stream5_icmp: {$stream5_icmp_timeout} diff --git a/config/snort/snort.xml b/config/snort/snort.xml index ed731f74..3d4c8016 100755 --- a/config/snort/snort.xml +++ b/config/snort/snort.xml @@ -47,7 +47,7 @@ <faq>Currently there are no FAQ items provided.</faq> <name>Snort</name> <version>2.9.4.6</version> - <title>Services:2.9.4.6 pkg v. 2.5.9</title> + <title>Services:2.9.4.6 pkg v. 2.6.0</title> <include_file>/usr/local/pkg/snort/snort.inc</include_file> <menu> <name>Snort</name> @@ -59,7 +59,7 @@ <name>snort</name> <rcfile>snort.sh</rcfile> <executable>snort</executable> - <description>Snort is the most widely deployed IDS/IPS technology worldwide.</description> + <description>Snort IDS/IPS Daemon</description> </service> <tabs> </tabs> diff --git a/config/snort/snort_alerts.php b/config/snort/snort_alerts.php index c296f81b..0295ed2f 100755 --- a/config/snort/snort_alerts.php +++ b/config/snort/snort_alerts.php @@ -90,8 +90,8 @@ function snort_add_supplist_entry($suppress) { /* 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['name'] = $a_instance[$instanceid]['interface'] . "suppress"; $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; @@ -108,6 +108,10 @@ function snort_add_supplist_entry($suppress) { $alist['suppresspassthru'] = base64_encode($tmplist); $a_suppress[$a_id] = $alist; } + else { + $alist['suppresspassthru'] = base64_encode($suppress); + $a_suppress[$a_id] = $alist; + } } } } @@ -243,7 +247,6 @@ if ($_POST['download']) { readfile("$file"); @unlink("/tmp/{$file_name}"); } - header("Location: /snort/snort_alerts.php?instance={$instanceid}"); exit; } @@ -263,7 +266,7 @@ include_once("fbegin.inc"); /* refresh every 60 secs */ if ($pconfig['arefresh'] == 'on') - echo "<meta http-equiv=\"refresh\" content=\"60;url=/snort/snort_alerts.php\" />\n"; + echo "<meta http-equiv=\"refresh\" content=\"60;url=/snort/snort_alerts.php?instance={$instanceid}\" />\n"; ?> <?php if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';} @@ -300,7 +303,7 @@ if ($pconfig['arefresh'] == 'on') <tr> <td width="22%" class="vncell"><?php echo gettext('Instance to inspect'); ?></td> <td width="78%" class="vtable"> - <select name="instance" id="instance" class="formselect" onChange="document.getElementById('formalert').submit()"> + <select name="instance" id="instance" class="formselect" onChange="document.getElementById('formalert').method='get';document.getElementById('formalert').submit()"> <?php foreach ($a_instance as $id => $instance) { $selected = ""; @@ -396,19 +399,26 @@ if (file_exists("/var/log/snort/snort_{$if_real}{$snort_uuid}/alert")) { $alert_ip_src = $fields[6]; /* Add zero-width space as soft-break opportunity after each colon if we have an IPv6 address */ $alert_ip_src = str_replace(":", ":​", $alert_ip_src); + /* Add Reverse DNS lookup icon */ + $alert_ip_src .= "<br/><a href='/diag_dns.php?host={$fields[6]}&instance={$instanceid}'>"; + $alert_ip_src .= "<img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' "; + $alert_ip_src .= "title='" . gettext("Resolve host via reverse DNS lookup") . "'></a>"; + /* Add icons for auto-adding to Suppress List if appropriate */ if (!snort_is_alert_globally_suppressed($supplist, $fields[1], $fields[2]) && !isset($supplist[$fields[1]][$fields[2]]['by_src'][$fields[6]])) { - $alert_ip_src .= "<br/><a href='?instance={$instanceid}&act=addsuppress_srcip&sidid={$fields[2]}&gen_id={$fields[1]}&descr={$alert_descr_url}&ip=" . trim(urlencode($fields[6])) . "'>"; + $alert_ip_src .= " <a href='?instance={$instanceid}&act=addsuppress_srcip&sidid={$fields[2]}&gen_id={$fields[1]}&descr={$alert_descr_url}&ip=" . trim(urlencode($fields[6])) . "'>"; $alert_ip_src .= "<img src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; - $alert_ip_src .= "title='" . gettext("Add this gen_id:sig_id track by_src IP to Suppress List") . "'></a>"; + $alert_ip_src .= "title='" . gettext("Add this alert to the Suppress List and track by_src IP") . "'></a>"; } elseif (isset($supplist[$fields[1]][$fields[2]]['by_src'][$fields[6]])) { - $alert_ip_src .= "<br/><img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; - $alert_ip_src .= "title='" . gettext("This gen_id:sig_id track by_src IP already in Suppress List") . "'/>"; + $alert_ip_src .= " <img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; + $alert_ip_src .= "title='" . gettext("This alert track by_src IP is already in the Suppress List") . "'/>"; } + /* Add icon for auto-removing from Blocked Table if required */ if (isset($tmpblocked[$fields[6]])) { - $alert_ip_src .= " <a href='?instance={$id}&todelete=" . trim(urlencode($fields[6])) . "'> - <img title=\"" . gettext("Remove host from Blocked Table") . "\" border=\"0\" width='12' height='12' name='todelete' id='todelete' alt=\"Remove from Blocked Hosts\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"/></a>"; + $alert_ip_src .= " "; + $alert_ip_src .= "<a href='?instance={$id}&todelete=" . trim(urlencode($fields[6])) . "'> + <img title=\"" . gettext("Remove host from Blocked Table") . "\" border=\"0\" width='12' height='12' name='todelete' id='todelete' alt=\"Remove from Blocked Hosts\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"></a>"; } /* IP SRC Port */ $alert_src_p = $fields[7]; @@ -416,19 +426,26 @@ if (file_exists("/var/log/snort/snort_{$if_real}{$snort_uuid}/alert")) { $alert_ip_dst = $fields[8]; /* 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 icon */ + $alert_ip_dst .= "<br/><a href='/diag_dns.php?host={$fields[8]}&instance={$instanceid}'>"; + $alert_ip_dst .= "<img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' "; + $alert_ip_dst .= "title='" . gettext("Resolve host via reverse DNS lookup") . "'></a>"; + /* Add icons for auto-adding to Suppress List if appropriate */ if (!snort_is_alert_globally_suppressed($supplist, $fields[1], $fields[2]) && !isset($supplist[$fields[1]][$fields[2]]['by_dst'][$fields[8]])) { - $alert_ip_dst .= "<br/><a href='?instance={$instanceid}&act=addsuppress_dstip&sidid={$fields[2]}&gen_id={$fields[1]}&descr={$alert_descr_url}&ip=" . trim(urlencode($fields[8])) . "'>"; + $alert_ip_dst .= " <a href='?instance={$instanceid}&act=addsuppress_dstip&sidid={$fields[2]}&gen_id={$fields[1]}&descr={$alert_descr_url}&ip=" . trim(urlencode($fields[8])) . "'>"; $alert_ip_dst .= "<img src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; - $alert_ip_dst .= "title='" . gettext("Add this gen_id:sig_id track by_dst IP to Suppress List") . "'></a>"; + $alert_ip_dst .= "title='" . gettext("Add this alert to the Suppress List and track by_dst IP") . "'></a>"; } elseif (isset($supplist[$fields[1]][$fields[2]]['by_dst'][$fields[8]])) { - $alert_ip_dst .= "<br/><img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; - $alert_ip_dst .= "title='" . gettext("This gen_id:sig_id track by_dst IP already in Suppress List") . "'/>"; + $alert_ip_dst .= " <img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; + $alert_ip_dst .= "title='" . gettext("This alert track by_dst IP is already in the Suppress List") . "'/>"; } + /* Add icon for auto-removing from Blocked Table if required */ if (isset($tmpblocked[$fields[8]])) { - $alert_ip_dst .= " <a href='?instance={$id}&todelete=" . trim(urlencode($fields[8])) . "'> - <img title=\"" . gettext("Remove host from Blocked Table") . "\" border=\"0\" width='12' height='12' name='todelete' id='todelete' alt=\"Remove from Blocked Hosts\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"/></a>"; + $alert_ip_dst .= " "; + $alert_ip_dst .= "<a href='?instance={$id}&todelete=" . trim(urlencode($fields[8])) . "'> + <img title=\"" . gettext("Remove host from Blocked Table") . "\" border=\"0\" width='12' height='12' name='todelete' id='todelete' alt=\"Remove from Blocked Hosts\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"></a>"; } /* IP DST Port */ $alert_dst_p = $fields[9]; @@ -437,11 +454,11 @@ if (file_exists("/var/log/snort/snort_{$if_real}{$snort_uuid}/alert")) { if (!snort_is_alert_globally_suppressed($supplist, $fields[1], $fields[2])) { $sidsupplink = "<a href='?instance={$instanceid}&act=addsuppress&sidid={$fields[2]}&gen_id={$fields[1]}&descr={$alert_descr_url}'>"; $sidsupplink .= "<img src='../themes/{$g['theme']}/images/icons/icon_plus.gif' width='12' height='12' border='0' "; - $sidsupplink .= "title='" . gettext("Add this gen_id:sig_id to Suppress List") . "'></a>"; + $sidsupplink .= "title='" . gettext("Add this alert to the Suppress List") . "'></a>"; } else { $sidsupplink = "<img src='../themes/{$g['theme']}/images/icons/icon_plus_d.gif' width='12' height='12' border='0' "; - $sidsupplink .= "title='" . gettext("This gen_id:sig_id already in Suppress List") . "'/>"; + $sidsupplink .= "title='" . gettext("This alert is already in the Suppress List") . "'/>"; } $alert_class = $fields[11]; diff --git a/config/snort/snort_blocked.php b/config/snort/snort_blocked.php index 56edfbc5..a81b03d7 100644 --- a/config/snort/snort_blocked.php +++ b/config/snort/snort_blocked.php @@ -94,7 +94,7 @@ if ($_POST['download']) @unlink("/tmp/{$file_name}"); exec("/bin/rm -fr /tmp/snort_blocked"); } else - $savemsg = "An error occurred while createing archive"; + $savemsg = "An error occurred while creating archive"; } else $savemsg = "No content on snort block list"; } @@ -257,7 +257,9 @@ if ($pconfig['brefresh'] == 'on') /* use one echo to do the magic*/ echo "<tr> <td align=\"center\" valign=\"middle\" class=\"listr\">{$counter}</td> - <td valign=\"middle\" class=\"listr\">{$tmp_ip}</td> + <td valign=\"middle\" class=\"listr\">{$tmp_ip} <a href='/diag_dns.php?host={$blocked_ip}'> + <img src='../themes/{$g['theme']}/images/icons/icon_log.gif' width='11' height='11' border='0' + title='" . gettext("Resolve host via reverse DNS lookup") . "'></a></td> <td valign=\"middle\" class=\"listr\">{$blocked_desc}</td> <td align=\"center\" valign=\"middle\" class=\"listr\"><a href='snort_blocked.php?todelete=" . trim(urlencode($blocked_ip)) . "'> <img title=\"" . gettext("Delete host from Blocked Table") . "\" border=\"0\" name='todelete' id='todelete' alt=\"Delete host from Blocked Table\" src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"></a></td> diff --git a/config/snort/snort_check_for_rule_updates.php b/config/snort/snort_check_for_rule_updates.php index c40d6ff4..30da4b74 100755 --- a/config/snort/snort_check_for_rule_updates.php +++ b/config/snort/snort_check_for_rule_updates.php @@ -42,6 +42,8 @@ if (!defined("VRT_DNLD_URL")) define("VRT_DNLD_URL", "https://www.snort.org/reg-rules/"); if (!defined("ET_VERSION")) define("ET_VERSION", "2.9.0"); +if (!defined("ET_BASE_DNLD_URL")) + define("ET_BASE_DNLD_URL", "http://rules.emergingthreats.net/"); if (!defined("ET_DNLD_FILENAME")) define("ET_DNLD_FILENAME", "emerging.rules.tar.gz"); if (!defined("GPLV2_DNLD_FILENAME")) @@ -88,6 +90,10 @@ $snort_rule_url = VRT_DNLD_URL; $emergingthreats_filename = ET_DNLD_FILENAME; $emergingthreats_filename_md5 = ET_DNLD_FILENAME . ".md5"; $emerging_threats_version = ET_VERSION; +$emergingthreats_url = ET_BASE_DNLD_URL; +// If using Sourcefire VRT rules with ET, then we should use the open-nogpl ET rules +$emergingthreats_url .= $vrt_enabled == "on" ? "open-nogpl/" : "open/"; +$emergingthreats_url .= "snort-" . ET_VERSION . "/"; /* Snort GPLv2 Community Rules filenames and URL */ $snort_community_rules_filename = GPLV2_DNLD_FILENAME; @@ -141,6 +147,18 @@ function snort_download_file_url($url, $file_out) { 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 */ @@ -200,26 +218,26 @@ $last_curl_error = ""; /* download md5 sig from snort.org */ if ($snortdownload == 'on') { if ($pkg_interface <> "console") - update_status(gettext("Downloading Snort VRT md5 file...")); - error_log(gettext("\tDownloading Snort VRT md5 file...\n"), 3, $snort_rules_upd_log); + update_status(gettext("Downloading Snort VRT md5 file {$snort_filename_md5}...")); + error_log(gettext("\tDownloading Snort VRT md5 file '{$snort_filename_md5}'...\n"), 3, $snort_rules_upd_log); $rc = snort_download_file_url("{$snort_rule_url}{$snort_filename_md5}/{$oinkid}/", "{$tmpfname}/{$snort_filename_md5}"); if ($rc === true) { if ($pkg_interface <> "console") - update_status(gettext("Done downloading snort.org md5.")); + update_status(gettext("Done downloading {$snort_filename_md5}.")); error_log("\tChecking Snort VRT md5 file...\n", 3, $snort_rules_upd_log); } else { error_log(gettext("\tSnort VRT md5 download failed.\n"), 3, $snort_rules_upd_log); if ($rc == 403) { $snort_err_msg = gettext("Too many attempts or Oinkcode not authorized for this Snort version.\n"); - $snort_err_msg .= gettext("\tFree Registered User accounts may download Snort VRT Rules once every 15 minutes.\n"); - $snort_err_msg .= gettext("\tPaid Subscriber accounts have no download limits.\n"); + $snort_err_msg .= gettext("\tFree Registered Users may download VRT Rules once every 15 minutes.\n"); + $snort_err_msg .= gettext("\tPaid Subscribers have no download limits.\n"); } else $snort_err_msg = gettext("Server returned error code '{$rc}'."); if ($pkg_interface <> "console") { update_status(gettext("Snort VRT md5 error ... Server returned error code {$rc} ...")); - update_output_window(gettext("Snort VRT rules will not be updated.\n{$snort_err_msg}")); + update_output_window(gettext("Snort VRT rules will not be updated.\n\t{$snort_err_msg}")); } log_error(gettext("[Snort] Snort VRT md5 download failed...")); log_error(gettext("[Snort] Server returned error code '{$rc}'...")); @@ -249,13 +267,15 @@ if ($snortdownload == 'on') { /* download snortrules file */ if ($snortdownload == 'on') { if ($pkg_interface <> "console") - update_status(gettext("There is a new set of Snort VRT rules posted. Downloading...")); + update_status(gettext("There is a new set of Snort VRT rules posted. Downloading {$snort_filename}...")); log_error(gettext("[Snort] There is a new set of Snort VRT rules posted. Downloading...")); - error_log(gettext("\tThere is a new set of Snort VRT rules posted. Downloading...\n"), 3, $snort_rules_upd_log); + error_log(gettext("\tThere is a new set of Snort VRT rules posted.\n"), 3, $snort_rules_upd_log); + error_log(gettext("\tDownloading file '{$snort_filename}'...\n"), 3, $snort_rules_upd_log); $rc = snort_download_file_url("{$snort_rule_url}{$snort_filename}/{$oinkid}/", "{$tmpfname}/{$snort_filename}"); if ($rc === true) { if ($pkg_interface <> "console") update_status(gettext("Done downloading Snort VRT rules file.")); + log_error("[Snort] Snort VRT rules file update downloaded successfully"); error_log(gettext("\tDone downloading rules file.\n"),3, $snort_rules_upd_log); if (trim(file_get_contents("{$tmpfname}/{$snort_filename_md5}")) != trim(md5_file("{$tmpfname}/{$snort_filename}"))){ if ($pkg_interface <> "console") @@ -285,8 +305,8 @@ if ($snortdownload == 'on') { /* download md5 sig from Snort GPLv2 Community Rules */ if ($snortcommunityrules == 'on') { if ($pkg_interface <> "console") - update_status(gettext("Downloading Snort GPLv2 Community Rules md5 file...")); - error_log(gettext("\tDownloading Snort GPLv2 Community Rules md5 file...\n"), 3, $snort_rules_upd_log); + update_status(gettext("Downloading Snort GPLv2 Community Rules md5 file {$snort_community_rules_filename_md5}...")); + error_log(gettext("\tDownloading Snort GPLv2 Community Rules md5 file '{$snort_community_rules_filename_md5}'...\n"), 3, $snort_rules_upd_log); $rc = snort_download_file_url("{$snort_community_rules_url}{$snort_community_rules_filename_md5}", "{$tmpfname}/{$snort_community_rules_filename_md5}"); if ($rc === true) { if ($pkg_interface <> "console") @@ -320,9 +340,10 @@ if ($snortcommunityrules == 'on') { /* download Snort GPLv2 Community rules file */ if ($snortcommunityrules == "on") { if ($pkg_interface <> "console") - update_status(gettext("There is a new set of Snort GPLv2 Community Rules posted. Downloading...")); + update_status(gettext("There is a new set of Snort GPLv2 Community Rules posted. Downloading {$snort_community_rules_filename} ...")); log_error(gettext("[Snort] There is a new set of Snort GPLv2 Community Rules posted. Downloading...")); - error_log(gettext("\tThere is a new set of Snort GPLv2 Community Rules posted. Downloading...\n"), 3, $snort_rules_upd_log); + error_log(gettext("\tThere is a new set of Snort GPLv2 Community Rules posted.\n"), 3, $snort_rules_upd_log); + error_log(gettext("\tDownloading file '{$snort_community_rules_filename}'...\n"), 3, $snort_rules_upd_log); $rc = snort_download_file_url("{$snort_community_rules_url}{$snort_community_rules_filename}", "{$tmpfname}/{$snort_community_rules_filename}"); /* Test for a valid rules file download. Turn off Snort Community update if download failed. */ @@ -398,15 +419,11 @@ if ($snortcommunityrules == 'on') { if ($emergingthreats == 'on') { if ($pkg_interface <> "console") update_status(gettext("Downloading EmergingThreats md5 file...")); - error_log(gettext("\tDownloading EmergingThreats md5 file...\n"), 3, $snort_rules_upd_log); - /* If using Sourcefire VRT rules with ET, then we should use the open-nogpl ET rules. */ - if ($vrt_enabled == "on") - $rc = snort_download_file_url("http://rules.emergingthreats.net/open-nogpl/snort-{$emerging_threats_version}/{$emergingthreats_filename_md5}", "{$tmpfname}/{$emergingthreats_filename_md5}"); - else - $rc = snort_download_file_url("http://rules.emergingthreats.net/open/snort-{$emerging_threats_version}/{$emergingthreats_filename_md5}", "{$tmpfname}/{$emergingthreats_filename_md5}"); + error_log(gettext("\tDownloading EmergingThreats md5 file '{$emergingthreats_filename_md5}'...\n"), 3, $snort_rules_upd_log); + $rc = snort_download_file_url("{$emergingthreats_url}{$emergingthreats_filename_md5}", "{$tmpfname}/{$emergingthreats_filename_md5}"); if ($rc === true) { if ($pkg_interface <> "console") - update_status(gettext("Done downloading EmergingThreats md5")); + update_status(gettext("Done downloading EmergingThreats md5 file {$emergingthreats_filename_md5}")); error_log(gettext("\tChecking EmergingThreats md5.\n"), 3, $snort_rules_upd_log); if (file_exists("{$snortdir}/{$emergingthreats_filename_md5}") && $emergingthreats == "on") { /* Check if were up to date emergingthreats.net */ @@ -436,15 +453,11 @@ if ($emergingthreats == 'on') { /* download emergingthreats rules file */ if ($emergingthreats == "on") { if ($pkg_interface <> "console") - update_status(gettext("There is a new set of EmergingThreats rules posted. Downloading...")); + update_status(gettext("There is a new set of EmergingThreats rules posted. Downloading {$emergingthreats_filename}...")); log_error(gettext("[Snort] There is a new set of EmergingThreats rules posted. Downloading...")); - error_log(gettext("\tThere is a new set of EmergingThreats rules posted. Downloading...\n"), 3, $snort_rules_upd_log); - - /* If using Sourcefire VRT rules with ET, then we should use the open-nogpl ET rules. */ - if ($vrt_enabled == "on") - $rc = snort_download_file_url("http://rules.emergingthreats.net/open-nogpl/snort-{$emerging_threats_version}/{$emergingthreats_filename}", "{$tmpfname}/{$emergingthreats_filename}"); - else - $rc = snort_download_file_url("http://rules.emergingthreats.net/open/snort-{$emerging_threats_version}/{$emergingthreats_filename}", "{$tmpfname}/{$emergingthreats_filename}"); + error_log(gettext("\tThere is a new set of EmergingThreats rules posted.\n"), 3, $snort_rules_upd_log); + error_log(gettext("\tDownloading file '{$emergingthreats_filename}'...\n"), 3, $snort_rules_upd_log); + $rc = snort_download_file_url("{$emergingthreats_url}{$emergingthreats_filename}", "{$tmpfname}/{$emergingthreats_filename}"); /* Test for a valid rules file download. Turn off ET update if download failed. */ if ($rc === true) { @@ -562,10 +575,10 @@ if ($snortdownload == 'on') { $nosorules = false; if ($snort_arch == 'i386'){ exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir}/tmp so_rules/precompiled/{$freebsd_version_so}/i386/{$snort_version}/"); - exec("/bin/cp {$snortdir}/tmp/so_rules/precompiled/{$freebsd_version_so}/i386/{$snort_version}/* {$snortlibdir}/dynamicrules/"); + exec("/bin/cp {$snortdir}/tmp/so_rules/precompiled/{$freebsd_version_so}/i386/{$snort_version}/*.so {$snortlibdir}/dynamicrules/"); } elseif ($snort_arch == 'amd64') { exec("/usr/bin/tar xzf {$tmpfname}/{$snort_filename} -C {$snortdir}/tmp so_rules/precompiled/{$freebsd_version_so}/x86-64/{$snort_version}/"); - exec("/bin/cp {$snortdir}/tmp/so_rules/precompiled/{$freebsd_version_so}/x86-64/{$snort_version}/* {$snortlibdir}/dynamicrules/"); + exec("/bin/cp {$snortdir}/tmp/so_rules/precompiled/{$freebsd_version_so}/x86-64/{$snort_version}/*.so {$snortlibdir}/dynamicrules/"); } else $nosorules = true; exec("rm -r {$snortdir}/tmp/so_rules"); diff --git a/config/snort/snort_define_servers.php b/config/snort/snort_define_servers.php index 371bbecd..2a6d47ff 100755 --- a/config/snort/snort_define_servers.php +++ b/config/snort/snort_define_servers.php @@ -48,17 +48,17 @@ if (!is_array($config['installedpackages']['snortglobal']['rule'])) { } $a_nat = &$config['installedpackages']['snortglobal']['rule']; -/* NOTE: KEEP IN SYNC WITH SNORT.INC since global do not work quite well with package */ +/* NOTE: KEEP IN SYNC WITH SNORT.INC since globals do not work well with package */ /* define servers and ports snortdefservers */ $snort_servers = array ( -"dns_servers" => "\$HOME_NET", "smtp_servers" => "\$HOME_NET", "http_servers" => "\$HOME_NET", -"www_servers" => "\$HOME_NET", "sql_servers" => "\$HOME_NET", "telnet_servers" => "\$HOME_NET", -"snmp_servers" => "\$HOME_NET", "ftp_servers" => "\$HOME_NET", "ssh_servers" => "\$HOME_NET", -"pop_servers" => "\$HOME_NET", "imap_servers" => "\$HOME_NET", "sip_proxy_ip" => "\$HOME_NET", -"sip_servers" => "\$HOME_NET", "rpc_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" + "dns_servers" => "\$HOME_NET", "smtp_servers" => "\$HOME_NET", "http_servers" => "\$HOME_NET", + "www_servers" => "\$HOME_NET", "sql_servers" => "\$HOME_NET", "telnet_servers" => "\$HOME_NET", + "snmp_servers" => "\$HOME_NET", "ftp_servers" => "\$HOME_NET", "ssh_servers" => "\$HOME_NET", + "pop_servers" => "\$HOME_NET", "imap_servers" => "\$HOME_NET", "sip_proxy_ip" => "\$HOME_NET", + "sip_servers" => "\$HOME_NET", "rpc_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 */ @@ -67,21 +67,23 @@ if(is_array($config['system']['ssh']) && isset($config['system']['ssh']['port']) else $ssh_port = "22"; $snort_ports = array( -"dns_ports" => "53", "smtp_ports" => "25", "mail_ports" => "25,143,465,691", -"http_ports" => "80", "oracle_ports" => "1521", "mssql_ports" => "1433", -"telnet_ports" => "23","snmp_ports" => "161", "ftp_ports" => "21", -"ssh_ports" => $ssh_port, "pop2_ports" => "109", "pop3_ports" => "110", -"imap_ports" => "143", "sip_proxy_ports" => "5060:5090,16384:32768", -"sip_ports" => "5060,5061", "auth_ports" => "113", "finger_ports" => "79", -"irc_ports" => "6665,6666,6667,6668,6669,7000", "smb_ports" => "139,445", -"nntp_ports" => "119", "rlogin_ports" => "513", "rsh_ports" => "514", -"ssl_ports" => "443,465,563,636,989,990,992,993,994,995", "GTP_PORTS" => "2123,2152,3386", -"file_data_ports" => "\$HTTP_PORTS,110,143", "shellcode_ports" => "!80", -"sun_rpc_ports" => "111,32770,32771,32772,32773,32774,32775,32776,32777,32778,32779", -"DCERPC_NCACN_IP_TCP" => "139,445", "DCERPC_NCADG_IP_UDP" => "138,1024:", -"DCERPC_NCACN_IP_LONG" => "135,139,445,593,1024:", "DCERPC_NCACN_UDP_LONG" => "135,1024:", -"DCERPC_NCACN_UDP_SHORT" => "135,593,1024:", "DCERPC_NCACN_TCP" => "2103,2105,2107", -"DCERPC_BRIGHTSTORE" => "6503,6504", "DNP3_PORTS" => "20000", "MODBUS_PORTS" => "502" + "dns_ports" => "53", "smtp_ports" => "25", "mail_ports" => "25,465,587,691", + "http_ports" => "36,80,81,82,83,84,85,86,87,88,89,90,311,383,591,593,631,901,1220,1414,1741,1830,2301,2381,2809,3037,3057,3128,3443,3702,4343,4848,5250,6080,6988,7000,7001,7144,7145,7510,7777,7779,8000,8008,8014,8028,8080,8085,8088,8090,8118,8123,8180,8181,8222,8243,8280,8300,8500,8800,8888,8899,9000,9060,9080,9090,9091,9443,9999,10000,11371,34443,34444,41080,50000,50002,55555", + "oracle_ports" => "1024:", "mssql_ports" => "1433", + "telnet_ports" => "23","snmp_ports" => "161", "ftp_ports" => "21,2100,3535", + "ssh_ports" => $ssh_port, "pop2_ports" => "109", "pop3_ports" => "110", + "imap_ports" => "143", "sip_proxy_ports" => "5060:5090,16384:32768", + "sip_ports" => "5060,5061,5600", "auth_ports" => "113", "finger_ports" => "79", + "irc_ports" => "6665,6666,6667,6668,6669,7000", "smb_ports" => "139,445", + "nntp_ports" => "119", "rlogin_ports" => "513", "rsh_ports" => "514", + "ssl_ports" => "443,465,563,636,989,992,993,994,995,7801,7802,7900,7901,7902,7903,7904,7905,7906,7907,7908,7909,7910,7911,7912,7913,7914,7915,7916,7917,7918,7919,7920", + "file_data_ports" => "\$HTTP_PORTS,110,143", "shellcode_ports" => "!80", + "sun_rpc_ports" => "111,32770,32771,32772,32773,32774,32775,32776,32777,32778,32779", + "DCERPC_NCACN_IP_TCP" => "139,445", "DCERPC_NCADG_IP_UDP" => "138,1024:", + "DCERPC_NCACN_IP_LONG" => "135,139,445,593,1024:", "DCERPC_NCACN_UDP_LONG" => "135,1024:", + "DCERPC_NCACN_UDP_SHORT" => "135,593,1024:", "DCERPC_NCACN_TCP" => "2103,2105,2107", + "DCERPC_BRIGHTSTORE" => "6503,6504", "DNP3_PORTS" => "20000", "MODBUS_PORTS" => "502", + "GTP_PORTS" => "2123,2152,3386" ); $pconfig = $a_nat[$id]; @@ -220,7 +222,8 @@ if ($savemsg) </tr> <?php foreach ($snort_ports as $key => $server): - $server = substr($server, 0, 20); + if (strlen($server) > 40) + $server = substr($server, 0, 40) . "..."; $label = strtoupper($key); $value = ""; if (!empty($pconfig["def_{$key}"])) @@ -229,7 +232,7 @@ if ($savemsg) <tr> <td width='22%' valign='top' class='vncell'><?php echo gettext("Define"); ?> <?=$label;?></td> <td width="78%" class="vtable"> - <input name="def_<?=$key;?>" type="text" size="40" autocomplete="off" class="formfldalias" id="def_<?=$key;?>" + <input name="def_<?=$key;?>" type="text" size="40" autocomplete="off" class="formfldalias" id="def_<?=$key;?>" value="<?=$value;?>"> <br/> <span class="vexpl"><?php echo gettext("Default value:"); ?> "<?=$server;?>" <br/> <?php echo gettext("Leave " . "blank for default value."); ?></span> diff --git a/config/snort/snort_interfaces_suppress.php b/config/snort/snort_interfaces_suppress.php index 780a6e92..7eed6dd3 100644 --- a/config/snort/snort_interfaces_suppress.php +++ b/config/snort/snort_interfaces_suppress.php @@ -37,6 +37,8 @@ require_once("guiconfig.inc"); require_once("/usr/local/pkg/snort/snort.inc"); +if (!is_array($config['installedpackages']['snortglobal']['rule'])) + $config['installedpackages']['snortglobal']['rule'] = array(); if (!is_array($config['installedpackages']['snortglobal']['suppress'])) $config['installedpackages']['snortglobal']['suppress'] = array(); if (!is_array($config['installedpackages']['snortglobal']['suppress']['item'])) @@ -44,14 +46,41 @@ if (!is_array($config['installedpackages']['snortglobal']['suppress']['item'])) $a_suppress = &$config['installedpackages']['snortglobal']['suppress']['item']; $id_gen = count($config['installedpackages']['snortglobal']['suppress']['item']); + +function snort_suppresslist_used($supplist) { + + /****************************************************************/ + /* This function tests if the passed Suppress List is currently */ + /* assigned to an interface. It returns TRUE if the list is */ + /* in use. */ + /* */ + /* Returns: TRUE if list is in use, else FALSE */ + /****************************************************************/ + + global $config; + + $snortconf = $config['installedpackages']['snortglobal']['rule']; + if (empty($snortconf)) + return false; + foreach ($snortconf as $value) { + if ($value['suppresslistname'] == $supplist) + return true; + } + return false; +} + if ($_GET['act'] == "del") { if ($a_suppress[$_GET['id']]) { /* make sure rule is not being referenced by any nat or filter rules */ - - unset($a_suppress[$_GET['id']]); - write_config(); - header("Location: /snort/snort_interfaces_suppress.php"); - exit; + if (snort_suppresslist_used($a_suppress[$_GET['id']]['name'])) { + $input_errors[] = gettext("ERROR -- Suppress List is currently assigned to an interface and cannot be removed!"); + } + else { + unset($a_suppress[$_GET['id']]); + write_config(); + header("Location: /snort/snort_interfaces_suppress.php"); + exit; + } } } @@ -65,6 +94,10 @@ include_once("head.inc"); <?php include_once("fbegin.inc"); if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';} +if ($input_errors) { + print_input_errors($input_errors); +} + ?> <form action="/snort/snort_interfaces_suppress.php" method="post"><?php if ($savemsg) print_info_box($savemsg); ?> @@ -107,12 +140,12 @@ if($pfsense_stable == 'yes'){echo '<p class="pgtitle">' . $pgtitle . '</p>';} <td valign="middle"><a href="snort_interfaces_suppress_edit.php?id=<?=$i;?>"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_e.gif" - width="17" height="17" border="0" title="<?php echo gettext("edit whitelist"); ?>"></a></td> + width="17" height="17" border="0" title="<?php echo gettext("edit Suppress List"); ?>"></a></td> <td><a href="/snort/snort_interfaces_suppress.php?act=del&id=<?=$i;?>" - onclick="return confirm('<?php echo gettext("Do you really want to delete this whitelist? All elements that still use it will become invalid (e.g. snort rules will fall back to the default whitelist)!"); ?>')"><img + onclick="return confirm('<?php echo gettext("Do you really want to delete this Suppress List?"); ?>')"><img src="/themes/<?= $g['theme']; ?>/images/icons/icon_x.gif" - width="17" height="17" border="0" title="<?php echo gettext("delete whitelist"); ?>"></a></td> + width="17" height="17" border="0" title="<?php echo gettext("delete Suppress List"); ?>"></a></td> </tr> </table> </td> diff --git a/config/snort/snort_preprocessors.php b/config/snort/snort_preprocessors.php index 3f88efaa..6c839846 100755 --- a/config/snort/snort_preprocessors.php +++ b/config/snort/snort_preprocessors.php @@ -109,6 +109,7 @@ if (isset($id) && $a_nat[$id]) { $pconfig['dnp3_preproc'] = $a_nat[$id]['dnp3_preproc']; $pconfig['modbus_preproc'] = $a_nat[$id]['modbus_preproc']; $pconfig['gtp_preproc'] = $a_nat[$id]['gtp_preproc']; + $pconfig['ssh_preproc'] = $a_nat[$id]['ssh_preproc']; $pconfig['preproc_auto_rule_disable'] = $a_nat[$id]['preproc_auto_rule_disable']; $pconfig['protect_preproc_rules'] = $a_nat[$id]['protect_preproc_rules']; $pconfig['frag3_detection'] = $a_nat[$id]['frag3_detection']; @@ -153,6 +154,8 @@ if (isset($id) && $a_nat[$id]) { $pconfig['sip_preproc'] = 'on'; if (empty($pconfig['other_preprocs'])) $pconfig['other_preprocs'] = 'on'; + if (empty($pconfig['ssh_preproc'])) + $pconfig['ssh_preproc'] = 'on'; if (empty($pconfig['http_inspect_memcap'])) $pconfig['http_inspect_memcap'] = "150994944"; if (empty($pconfig['frag3_overlap_limit'])) @@ -258,6 +261,7 @@ if ($_POST['ResetAll']) { $pconfig['dnp3_preproc'] = "off"; $pconfig['modbus_preproc'] = "off"; $pconfig['gtp_preproc'] = "off"; + $pconfig['ssh_preproc'] = "on"; $pconfig['preproc_auto_rule_disable'] = "off"; $pconfig['protect_preproc_rules'] = "off"; $pconfig['frag3_detection'] = "on"; @@ -334,6 +338,7 @@ elseif ($_POST['Submit']) { $natent['sip_preproc'] = $_POST['sip_preproc'] ? 'on' : 'off'; $natent['modbus_preproc'] = $_POST['modbus_preproc'] ? 'on' : 'off'; $natent['gtp_preproc'] = $_POST['gtp_preproc'] ? 'on' : 'off'; + $natent['ssh_preproc'] = $_POST['ssh_preproc'] ? 'on' : 'off'; $natent['preproc_auto_rule_disable'] = $_POST['preproc_auto_rule_disable'] ? 'on' : 'off'; $natent['protect_preproc_rules'] = $_POST['protect_preproc_rules'] ? 'on' : 'off'; $natent['frag3_detection'] = $_POST['frag3_detection'] ? 'on' : 'off'; @@ -1221,6 +1226,12 @@ include_once("head.inc"); <?php echo gettext("The GTP preprocessor decodes GPRS Tunneling Protocol traffic and detects intrusion attempts."); ?></td> </tr> <tr> + <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable SSH Detection"); ?></td> + <td width="78%" class="vtable"><input name="ssh_preproc" type="checkbox" value="on" + <?php if ($pconfig['ssh_preproc']=="on") echo "checked"; ?>> + <?php echo gettext("The SSH preprocessor detects various Secure Shell exploit attempts."); ?></td> + </tr> + <tr> <td width="22%" valign="top" class="vncell"><?php echo gettext("Enable DNS Detection"); ?></td> <td width="78%" class="vtable"><input name="dns_preprocessor" type="checkbox" value="on" <?php if ($pconfig['dns_preprocessor']=="on") echo "checked"; ?>> @@ -1445,6 +1456,21 @@ function enable_change_all() { document.iform.stream5_icmp_timeout.disabled=endis; } +function wopen(url, name, w, h) +{ +// Fudge factors for window decoration space. +// In my tests these work well on all platforms & browsers. + w += 32; + h += 96; + var win = window.open(url, + name, + 'width=' + w + ', height=' + h + ', ' + + 'location=no, menubar=no, ' + + 'status=no, toolbar=no, scrollbars=yes, resizable=yes'); + win.resizeTo(w, h); + win.focus(); +} + // Set initial state of form controls enable_change_all(); diff --git a/config/snort/snort_rules.php b/config/snort/snort_rules.php index 7853b955..c9d90597 100755 --- a/config/snort/snort_rules.php +++ b/config/snort/snort_rules.php @@ -511,9 +511,9 @@ if ($savemsg) { </tr> <tr> <td class="vexpl" valign="middle"><?php echo "<a href='?id={$id}&openruleset={$currentruleset}&act=enable_all'> - <img src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\" width=\"15\" height=\"15\" - onmouseout='this.src=\"../themes/{$g['theme']}/images/icons/icon_x.gif\"' - onmouseover='this.src=\"../themes/{$g['theme']}/images/icons/icon_x_mo.gif\"' border='0' + <img src=\"../themes/{$g['theme']}/images/icons/icon_plus.gif\" width=\"15\" height=\"15\" + onmouseout='this.src=\"../themes/{$g['theme']}/images/icons/icon_plus.gif\"' + onmouseover='this.src=\"../themes/{$g['theme']}/images/icons/icon_plus_mo.gif\"' border='0' title='" . gettext("Click to enable all rules in the selected category") . "'></a>"?> <?php echo gettext("Enable all rules in the current Category"); ?></td> </tr> @@ -559,7 +559,7 @@ if ($savemsg) { <tbody> <?php - $counter = 0; + $counter = $enable_cnt = $disable_cnt = 0; foreach ($rules_map as $k1 => $rulem) { foreach ($rulem as $k2 => $v) { $sid = snort_get_sid($v['rule']); @@ -568,19 +568,23 @@ if ($savemsg) { $textss = "<span class=\"gray\">"; $textse = "</span>"; $iconb = "icon_reject_d.gif"; + $disable_cnt++; } elseif (($v['disabled'] == 1) && (!isset($enablesid[$sid]))) { $textss = "<span class=\"gray\">"; $textse = "</span>"; $iconb = "icon_block_d.gif"; + $disable_cnt++; } elseif (isset($enablesid[$sid])) { $textss = $textse = ""; $iconb = "icon_reject.gif"; + $enable_cnt++; } else { $textss = $textse = ""; $iconb = "icon_block.gif"; + $enable_cnt++; } // Pick off the first section of the rule (prior to the start of the MSG field), @@ -653,7 +657,12 @@ if ($savemsg) { <td> <table width="100%" border="0" cellspacing="0" cellpadding="1"> <tr> - <td class="vexpl" colspan="2" height="30" valign="middle"><?php echo gettext("Rule Count: {$counter}"); ?></td> + <td width="16"></td> + <td class="vexpl" height="35" valign="top"> + <strong><?php echo gettext("--- Category Rules Summary ---") . "</strong><br/>" . + gettext("Total Rules: {$counter}") . " " . + gettext("Enabled: {$enable_cnt}") . " " . + gettext("Disabled: {$disable_cnt}"); ?></td> </tr> <tr> <td width="16"><img src="../themes/<?= $g['theme']; ?>/images/icons/icon_block.gif" |