Configurable auto-blocking timeout values.
authorMichael Rash <mbr@cipherdyne.org>
Wed, 2 Jan 2013 01:56:00 +0000 (20:56 -0500)
committerMichael Rash <mbr@cipherdyne.org>
Wed, 2 Jan 2013 01:56:00 +0000 (20:56 -0500)
Oscar Marley suggested configurable auto-blocking timeout values depending on
the danger level that a scan or attack achieves.  This resulted in the
implementation of the AUTO_BLOCK_DL*_TIMEOUT variables.

12 files changed:
CREDITS
psad
psad.conf
test/conf/auto_blocking.conf
test/conf/default_psad.conf
test/conf/disable_ipv6_detection.conf
test/conf/enable_ack_detection.conf
test/conf/ignore_tcp.conf
test/conf/ignore_udp.conf
test/conf/require_DROP_syslog_prefix_str.conf
test/conf/require_missing_syslog_prefix_str.conf
test/test-psad.pl

diff --git a/CREDITS b/CREDITS
index 462de9b..de29bdc 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -485,3 +485,8 @@ Pui Edylie
       to the corresponding Snort 'msg' field.  Added the FWSNORT_RULES_DIR
       variable to have psad read Snort rules from any installed fwsnort
       instance.
+
+Oscar Marley
+    - Suggested configurable auto-blocking timeout values depending on the
+      danger level that a scan or attack achieves.  This resulted in the
+      implementation of the AUTO_BLOCK_DL*_TIMEOUT variables.
diff --git a/psad b/psad
index 7c9e8c6..d96fa1c 100755 (executable)
--- a/psad
+++ b/psad
@@ -278,6 +278,7 @@ my $scan_ip_pairs = 0;
 my %auto_dl = ();
 my %auto_dl_ip_objs = ();
 my %auto_assigned_msg = ();
+my $PERMANENT = 0;
 
 ### cache the source ips that we have automatically blocked
 ### (if ENABLE_AUTO_IDS == 'Y')
@@ -912,7 +913,6 @@ MAIN: for (;;) {
         ### Extract data and summarize scan packets, assign danger level,
         ### send email/syslog alerts.
         &check_scan(\@fw_packets);
-
     }
 
     ### log top scans data
@@ -940,9 +940,7 @@ MAIN: for (;;) {
         ### Timeout any auto-blocked IPs that are past due (need to
         ### check the timeouts against existing IPs in the scan hash
         ### even if new packets are not found).
-        if ($config{'AUTO_BLOCK_TIMEOUT'} > 0) {
-            &timeout_auto_blocked_ips();
-        }
+        &timeout_auto_blocked_ips();
 
         ### see if we need to add any IP address from the domain
         ### socket
@@ -1450,6 +1448,11 @@ sub check_scan() {
         if $config{'ENABLE_AUTO_IDS'} eq 'Y'
             and (not $analyze_mode or $analyze_mode_auto_block);
 
+    if ($config{'ENABLE_AUTO_IDS'} eq 'Y' and $analyze_mode_auto_block) {
+        sleep $config{'AUTO_BLOCK_TIMEOUT'} + 1;
+        &timeout_auto_blocked_ips();
+    }
+
     if ($log_scan_ip_pair_max) {
         &sys_log("scan IP pairs threshold reached");
     }
@@ -3306,6 +3309,8 @@ sub psad_init() {
         exit $rv;
     }
 
+    &dump_conf() if $test_mode;
+
     ### make sure all necessary configuration variables
     ### are defined
     &required_vars();
@@ -6006,12 +6011,17 @@ sub exec_external_script() {
 }
 
 sub renew_auto_blocked_ips() {
+
+    ### note that if we are renewing IP blocking rules, we just use
+    ### the AUTO_BLOCK_TIMEOUT value initially and then the AUTO_BLOCK_DLN...
+    ### values will take over as psad gets up and running
     my $timeout_str = '.';
     if ($config{'AUTO_BLOCK_TIMEOUT'} > 0) {
         $timeout_str = "for $config{'AUTO_BLOCK_TIMEOUT'} seconds.";
     } else {
         $timeout_str = '(unlimited time).';
     }
+
     if ($config{'IPTABLES_BLOCK_METHOD'} eq 'Y'
             and -e $config{'AUTO_BLOCK_IPT_FILE'}) {
         open B, "< $config{'AUTO_BLOCK_IPT_FILE'}" or
@@ -6288,12 +6298,7 @@ sub ipt_block() {
     my $block_success   = 0;
     my $already_blocked = 0;
 
-    my $timeout_str = '';
-    if ($config{'AUTO_BLOCK_TIMEOUT'} > 0) {
-        $timeout_str = "for $config{'AUTO_BLOCK_TIMEOUT'} seconds";
-    } else {
-        $timeout_str = '(unlimited timeout)';
-    }
+    my ($timeout, $timeout_str) = &get_block_timeout($scan_dl{$ip});
 
     if ($config{'IPTABLES_PREREQ_CHECK'} > 1) {
         $iptables_prereq_check++;
@@ -6831,12 +6836,8 @@ sub auto_psad_response() {
 
             next SRC if defined $auto_blocked_ips{$src};
 
-            my $timeout_str = '';
-            if ($config{'AUTO_BLOCK_TIMEOUT'} > 0) {
-                $timeout_str = "for $config{'AUTO_BLOCK_TIMEOUT'} seconds.";
-            } else {
-                $timeout_str = '(unlimited timeout).';
-            }
+            my ($timeout, $timeout_str) = &get_block_timeout($dl);
+
             ### we have seen at least one packet logged by the firewall
             ### at this point
             if ($config{'IPTABLES_BLOCK_METHOD'} eq 'Y') {
@@ -6896,12 +6897,35 @@ sub auto_block_ignore_ip() {
     return 0;
 }
 
+sub get_block_timeout() {
+    my $dl = shift;
+
+    my $timeout = $config{'AUTO_BLOCK_DL1_TIMEOUT'};
+    if ($dl == 2) {
+        $timeout = $config{'AUTO_BLOCK_DL2_TIMEOUT'};
+    } elsif ($dl == 3) {
+        $timeout = $config{'AUTO_BLOCK_DL3_TIMEOUT'};
+    } elsif ($dl == 4) {
+        $timeout = $config{'AUTO_BLOCK_DL4_TIMEOUT'};
+    } elsif ($dl == 5) {
+        $timeout = $config{'AUTO_BLOCK_DL5_TIMEOUT'};
+    }
+
+    my $timeout_str = "for $timeout seconds";
+    $timeout_str = '(unlimited timeout)' if $timeout == $PERMANENT;
+
+    return ($timeout, $timeout_str);
+}
+
 sub timeout_auto_blocked_ips() {
-    print STDERR "[+] timeout_auto_block_ips()\n" if $debug;
-    return if $config{'AUTO_BLOCK_TIMEOUT'} == 0;
+
+    print STDERR "[+] timeout_auto_block_ips()\n" if $debug or $test_mode;
+
     for my $ip (keys %auto_blocked_ips) {
-        if ((time() - $auto_blocked_ips{$ip})
-                > $config{'AUTO_BLOCK_TIMEOUT'}) {
+        my ($timeout, $timeout_str) = &get_block_timeout($scan_dl{$ip});
+        next if $timeout == $PERMANENT;
+
+        if ((time() - $auto_blocked_ips{$ip}) > $timeout) {
 
             ### remove all Netfiler blocking rules for $ip
             if ($config{'IPTABLES_BLOCK_METHOD'} eq 'Y') {
@@ -8934,9 +8958,9 @@ sub print_blocked_ip_status() {
             ### older versions do not have the timestamp
             if ($line =~ /^\s*\S+\s+(\d+)/) {
                 $timestamp = $1;
-                if ($config{'AUTO_BLOCK_TIMEOUT'} > 0) {
-                    $time_remain = $config{'AUTO_BLOCK_TIMEOUT'}
-                        - (time() - $timestamp);
+                my ($timeout, $timeout_str) = &get_block_timeout($scan_dl{$ip});
+                if ($timeout > 0) {
+                    $time_remain = $timeout - (time() - $timestamp);
                     $time_remain = 0 if $time_remain < 0;
 
                     push @print_lines,  "      $ip ($time_remain ",
@@ -10944,6 +10968,9 @@ sub required_vars() {
         ENABLE_WHOIS_FORCE_SRC_IP ENABLE_IPV6_DETECTION
         PERSISTENCE_CTR_THRESHOLD MAX_SCAN_IP_PAIRS INSTALL_ROOT
         ICMP6_TYPES_FILE PROTOCOL_SCAN_THRESHOLD PROTOCOLS_FILE
+        AUTO_BLOCK_DL1_TIMEOUT AUTO_BLOCK_DL2_TIMEOUT
+        AUTO_BLOCK_DL3_TIMEOUT AUTO_BLOCK_DL4_TIMEOUT
+        AUTO_BLOCK_DL5_TIMEOUT
     ));
     &defined_vars(\@required_vars);
     return;
index ee144fe..fe7b105 100644 (file)
--- a/psad.conf
+++ b/psad.conf
@@ -339,6 +339,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index 8657f0f..f35bc68 100644 (file)
@@ -331,12 +331,21 @@ ENABLE_AUTO_IDS             Y;
 
 ### Block all traffic from offending IP if danger
 ### level >= to this value
-AUTO_IDS_DANGER_LEVEL       5;
+AUTO_IDS_DANGER_LEVEL       3;
 
 ### Set the auto-blocked timeout in seconds (the default
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index 6ba4c25..29104f3 100644 (file)
@@ -337,6 +337,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index 9afa3c6..152a957 100644 (file)
@@ -337,6 +337,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index e27a1c0..9d7bedd 100644 (file)
@@ -337,6 +337,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index d229131..e883839 100644 (file)
@@ -337,6 +337,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index 51e3653..ca136de 100644 (file)
@@ -337,6 +337,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index a871525..594246e 100644 (file)
@@ -337,6 +337,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index eeb8479..599ae22 100644 (file)
@@ -337,6 +337,15 @@ AUTO_IDS_DANGER_LEVEL       5;
 ### is one hour).
 AUTO_BLOCK_TIMEOUT          3600;
 
+### Set the auto-blocked timeout in seconds for each danger
+### level - zero means to block permanently.  Each of these
+### can be set independently
+AUTO_BLOCK_DL1_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL2_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL3_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL4_TIMEOUT      $AUTO_BLOCK_TIMEOUT;
+AUTO_BLOCK_DL5_TIMEOUT      0;   ### permanent
+
 ### Enable regex checking on log prefixes for active response
 ENABLE_AUTO_IDS_REGEX       N;
 
index 4f31351..9b50c4b 100755 (executable)
@@ -46,6 +46,7 @@ my $default_conf   = "$conf_dir/default_psad.conf";
 my $ignore_udp_conf = "$conf_dir/ignore_udp.conf";
 my $ignore_tcp_conf = "$conf_dir/ignore_tcp.conf";
 my $auto_blocking_conf = "$conf_dir/auto_blocking.conf";
+my $auto_dl5_blocking_conf = "$conf_dir/auto_min_dl5_blocking.conf";
 my $require_prefix_conf = "$conf_dir/require_DROP_syslog_prefix_str.conf";
 my $require_missing_prefix_conf = "$conf_dir/require_missing_syslog_prefix_str.conf";
 my $enable_ack_detection_conf = "$conf_dir/enable_ack_detection.conf";
@@ -492,17 +493,40 @@ my @tests = (
     {
         'category'  => 'operations',
         'detail'    => 'DL5 IPv4 <BLOCK> SYN scan',
-        'err_msg'   => 'did not set SYN scan source to DL5',
+        'err_msg'   => 'did not block scan src',
         'positive_output_matches' => [qr/Top\s\d+\sattackers/i,
                 qr/scanned\sports.*?1000\-1500/i,
                 qr/IP\sstatus/i,
                 qr/192\.168\.10\.55,\sDL\:\s5/,
                 qr/DROP\s.*192\.168\.10\.55/,
                 qr/Flushing\sand\sdeleting\spsad\schains/,
+                qr/unlimited\stime/,
          ],
         'match_all' => $MATCH_ALL_RE,
         'function'  => \&generic_exec,
         'cmdline'   => "$psadCmd --test-mode -A --analysis-write-data --auto-dl $dl5_ipv4_auto_dl_file " .
+                "-m $scans_dir/" .  &fw_type() . "/$syn_scan_file -c $auto_dl5_blocking_conf " .
+                "$normal_root_override_str --analysis-auto-block",
+        'auto_block_test' => $YES,
+        'exec_err'  => $NO,
+        'fatal'     => $NO
+    },
+    {
+        'category'  => 'operations',
+        'detail'    => 'IPv4 <BLOCK> SYN scan',
+        'err_msg'   => 'did not block scan src',
+        'positive_output_matches' => [qr/Top\s\d+\sattackers/i,
+                qr/scanned\sports.*?1000\-1500/i,
+                qr/IP\sstatus/i,
+                qr/192\.168\.10\.55,\sDL\:\s3/,
+                qr/DROP\s.*192\.168\.10\.55/,
+                qr/Flushing\sand\sdeleting\spsad\schains/,
+                qr/for\s3\sseconds/,
+                qr/removed\siptables\sblock/,
+         ],
+        'match_all' => $MATCH_ALL_RE,
+        'function'  => \&generic_exec,
+        'cmdline'   => "$psadCmd --test-mode -A --analysis-write-data " .
                 "-m $scans_dir/" .  &fw_type() . "/$syn_scan_file -c $auto_blocking_conf " .
                 "$normal_root_override_str --analysis-auto-block",
         'auto_block_test' => $YES,