Added detection for Errata Security's "Masscan" port scanner
authorMichael Rash <mbr@cipherdyne.org>
Mon, 30 Sep 2013 02:01:53 +0000 (22:01 -0400)
committerMichael Rash <mbr@cipherdyne.org>
Mon, 30 Sep 2013 02:01:53 +0000 (22:01 -0400)
Added detection for Errata Security's "Masscan" port scanner that was
used in an Internet-wide scan for port 22 on Sept. 12, 2013 (see:
http://blog.erratasec.com/2013/09/we-scanned-internet-for-port-22.html).
The detection strategy used by psad relies on the fact that masscan does
not appear to set the options portion of the TCP header, and if the
iptables LOG rules that generate log data for psad are built with the
--log-tcp-options switch, then no options in a SYN scan can be seen.
This is not to say that other scanning software always sets TCP options -
Scapy seems to not set options by default when issuing a SYN scan like
this either: http://www.secdev.org/projects/scapy/doc/usage.html#syn-scans
There is a new psad.conf variable "EXPECT_TCP_OPTIONS" to assist with
Masscan detection as well.  When looking for Masscan SYN scans, psad
requires at least one TCP options field to be populated within a LOG
message (so that it knows --log-tcp-options has been set for at least
some logged traffic), and after seeing this then SYN packets with no
options are attributed to Masscan traffic.  All usual psad threshold
variables continue to apply however, so (by default) a single Masscan
SYN packet will not trigger a psad alert.  Masscan detection can be
disabled altogether by setting EXPECT_TCP_OPTIONS to "N", and this will
not affect any other psad detection techniques such as passive OS
fingerprinting, etc.

ChangeLog
psad
psad.conf

index e081a52..b547363 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,4 +1,25 @@
 psad-2.2.2 (//2013):
+    - Added detection for Errata Security's "Masscan" port scanner that was
+      used in an Internet-wide scan for port 22 on Sept. 12, 2013 (see:
+      http://blog.erratasec.com/2013/09/we-scanned-internet-for-port-22.html).
+      The detection strategy used by psad relies on the fact that masscan does
+      not appear to set the options portion of the TCP header, and if the
+      iptables LOG rules that generate log data for psad are built with the
+      --log-tcp-options switch, then no options in a SYN scan can be seen.
+      This is not to say that other scanning software always sets TCP options -
+      Scapy seems to not set options by default when issuing a SYN scan like
+      this either: http://www.secdev.org/projects/scapy/doc/usage.html#syn-scans
+      There is a new psad.conf variable "EXPECT_TCP_OPTIONS" to assist with
+      Masscan detection as well.  When looking for Masscan SYN scans, psad
+      requires at least one TCP options field to be populated within a LOG
+      message (so that it knows --log-tcp-options has been set for at least
+      some logged traffic), and after seeing this then SYN packets with no
+      options are attributed to Masscan traffic.  All usual psad threshold
+      variables continue to apply however, so (by default) a single Masscan
+      SYN packet will not trigger a psad alert.  Masscan detection can be
+      disabled altogether by setting EXPECT_TCP_OPTIONS to "N", and this will
+      not affect any other psad detection techniques such as passive OS
+      fingerprinting, etc.
     - RPM bug fix to include the protocols file.
 
 psad-2.2.1 (01/02/2013):
diff --git a/psad b/psad
index 2c9bdb6..b1105f5 100755 (executable)
--- a/psad
+++ b/psad
@@ -463,6 +463,9 @@ my $tcp_win_scale_type = 3;
 my $tcp_sack_type      = 4;
 my $tcp_timestamp_type = 8;
 
+### for EXPECT_TCP_OPTIONS handling
+my $found_one_tcp_options_field = 0;
+
 my %tcp_p0f_opt_types = (
     'N' => $tcp_nop_type,
     'M' => $tcp_mss_type,
@@ -564,6 +567,7 @@ my %pkt_NF_init = (
     'fwsnort_rnum'  => 0,
     'fwsnort_estab' => 0,
     'is_topera'     => 0,  ### Topera IPv6 scanner detection, requires --log-ip-options
+    'is_masscan'    => 0,  ### Masscan detection, requires --log-tcp-options
     'chain'         => '',
     'log_prefix'    => '',
     'dshield_str'   => '',
@@ -1322,7 +1326,8 @@ sub check_scan() {
         $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{'syslog_host'}
             {$pkt{'syslog_host'}} = '' if $pkt{'syslog_host'};
 
-        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{'is_topera'} = $pkt{'is_topera'};
+        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{'is_topera'}  = $pkt{'is_topera'};
+        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{'is_masscan'} = $pkt{'is_masscan'};
 
         if ($pkt{'log_prefix'}) {
             ### see if the logging prefix matches the blocking
@@ -1773,10 +1778,22 @@ sub parse_NF_pkt_str() {
             return $PKT_ERROR;
         }
 
-        ### don't pickup IP options if --log-ip-options is used
-        ### (they appear before the PROTO= field).
+        ### look for TCP options, but don't pickup IP options if
+        ### also --log-ip-options is used (IP options appear before
+        ### the PROTO= field).
         if ($pkt_str =~ /URGP=\S+\s+OPT\s+\((\S+)\)/) {
             $pkt_hr->{'tcp_opts'} = $1;
+            $found_one_tcp_options_field = 1
+                if $config{'EXPECT_TCP_OPTIONS'} eq 'Y';
+        }
+
+        if ($pkt_hr->{'flags'}
+                and $pkt_hr->{'flags'} eq 'SYN'
+                and $found_one_tcp_options_field
+                and not $pkt_hr->{'tcp_opts'}) {
+            $pkt_hr->{'is_masscan'} = 1;
+            print STDERR "    Masscan SYN scan\n"
+                if $debug;
         }
 
         if ($pkt_str =~ /\sSEQ=(\d+)\s+ACK=(\d+)/) {
@@ -5508,6 +5525,10 @@ sub scan_logr() {
                         $scan_style_str = "Topera $flags scan";
                         printf $fh "%${log_len}s%s\n", $prefix,
                             "[$flags: $n_pkts packets, Topera $flags scan]";
+                    } elsif ($curr_scan_hr->{$src}->{$dst}->{'is_masscan'}) {
+                        $scan_style_str = "Masscan $flags scan";
+                        printf $fh "%${log_len}s%s\n", $prefix,
+                            "[$flags: $n_pkts packets, Masscan $flags scan]";
                     } else {
                         if ($nmap_opts) {
                             printf $fh "%${log_len}s%s\n", $prefix,
@@ -10995,7 +11016,7 @@ sub required_vars() {
         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 EMAIL_THROTTLE
+        AUTO_BLOCK_DL5_TIMEOUT EMAIL_THROTTLE EXPECT_TCP_OPTIONS
     ));
     &defined_vars(\@required_vars);
     return;
index 792c14d..7c33ed9 100644 (file)
--- a/psad.conf
+++ b/psad.conf
@@ -156,6 +156,15 @@ ENABLE_SIG_MSG_SYSLOG       Y;
 SIG_MSG_SYSLOG_THRESHOLD    10;
 SIG_SID_SYSLOG_THRESHOLD    10;
 
+### Expect that all logged TCP SYN packets include the options portion of the
+### TCP header (requires the --log-tcp-options argument to the iptables LOG
+### rule).  If a SYN packet is received that does not include TCP options, then
+### it may be created by a scanner such as Eratta Security's "masscan").  Note
+### that psad still does a check to see if at least one log message is seen
+### includes the OPT field before expecting the remaining messages to also
+### include this field.
+EXPECT_TCP_OPTIONS          Y;
+
 ### TTL values are decremented depending on the number of hops
 ### the packet has taken before it hits the firewall.  We will
 ### assume packets will not jump through more than 20 hops on