Changeset 1667

Show
Ignore:
Timestamp:
11/16/06 23:09:15 (2 years ago)
Author:
mbr
Message:

merged 1648:1666 from the sigdevel branch into the trunk

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • psad/trunk/Psad/lib/Psad.pm

    r1643 r1667  
    224224    my ($msg, $file) = @_; 
    225225    open F, ">> $file" or croak "[*] Could not open $file: $!"; 
    226     print F scalar localtime(), " $msg"; 
     226    print F scalar localtime(), " pid: $$ $msg"; 
    227227    close F; 
    228228    return; 
  • psad/trunk/install.pl

    r1597 r1667  
    670670            if ($line =~ /^\s*(\S+)\s+_?CHANGE.?ME_?\;/) { 
    671671                my $var = $1; 
    672                 ### only two possible vars are set to _CHANGEME_ by 
    673                 ### default as of psad-1.3 
    674                 if ($var eq 'HOME_NET') { 
    675                     &logr("[-] HOME_NET is not defined in $file.\n"); 
    676                     &set_home_net($file); 
    677                 } elsif ($var eq 'HOSTNAME') { 
     672                ### only the HOSTNAME variable is set to _CHANGEME_ by 
     673                ### default as of psad-1.6.0 
     674                if ($var eq 'HOSTNAME') { 
    678675                    &logr("[-] set_hostname() failed.  Edit the HOSTNAME " . 
    679676                        " variable in $file\n"); 
     
    981978sub set_home_net() { 
    982979    my $file = shift; 
     980 
     981    ### first see if the admin will accept the default 'any' value 
     982    return if &query_use_home_net_default(); 
    983983 
    984984    ### get all interfaces; even those that are down since they may 
     
    10751075    } 
    10761076    return; 
     1077} 
     1078 
     1079sub query_use_home_net_default() { 
     1080    &logr( 
     1081"[+] By default, psad matches Snort rules against any IP addresses, but psad\n"); 
     1082    &logr( 
     1083"    offers the ability to restrict signature matches to specific networks\n"); 
     1084    &logr( 
     1085"    with a similar concept to the HOME_NET variable in Snort.  Would you like\n"); 
     1086    &logr( 
     1087"    limit the networks psad uses to enumerate the home network(s)?\n"); 
     1088 
     1089    my $ans = ''; 
     1090    while ($ans ne 'y' && $ans ne 'n') { 
     1091        &logr("(y/[n])?  "); 
     1092        $ans = <STDIN>; 
     1093        $ans = 'n' if $ans eq "\n"; 
     1094        chomp $ans; 
     1095    } 
     1096    if ($ans eq 'y') { 
     1097        return 0; 
     1098    } 
     1099    return 1; 
    10771100} 
    10781101 
  • psad/trunk/psad

    r1641 r1667  
    7373#               for the current interval. 
    7474#   flags     - Keeps track of tcp flags. 
    75 #   curr_sig  - Current signature. 
     75#   sid       - Signature tracking 
    7676#   abs_sp    - Absolute starting port. 
    7777#   abs_ep    - Absolute ending port. 
     
    8282# 
    8383#  Sample tcp packet (rejected by Netfilter... --log-prefix = "DROP ") 
     84# 
    8485#  Mar 11 13:15:52 orthanc kernel: DROP IN=lo OUT= MAC=00:00:00:00:00:00:00:00: 
    8586#  00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=60 TOS=0x00 PREC=0x00 
     
    8788# 
    8889#  Sample icmp packet rejected by Netfilter INPUT chain: 
     90# 
    8991#  Nov 27 15:45:51 orthanc kernel: DROP IN=eth1 OUT= MAC=00:a0:cc:e2:1f:f2:00: 
    9092#  20:78:10:70:e7:08:00 SRC=192.168.10.20 DST=192.168.10.1 LEN=84 TOS=0x00 
     
    9294# 
    9395#  Sample icmp packet logged through FORWARD chain: 
     96# 
    9497#  Aug 20 21:23:32 orthanc kernel: SID365 IN=eth2 OUT=eth1 SRC=192.168.20.25 
    9598#  DST=192.168.10.15 LEN=84 TOS=0x00 PREC=0x00 TTL=63 ID=0 DF PROTO=ICMP TYPE=8 
     
    226229### (http://www.cipherdyne.org/fwsnort/) will automatically 
    227230### build such a ruleset from snort signatures. 
    228 my %snort_msgs = (); 
     231my %fwsnort_sigs = (); 
    229232 
    230233### Cache snort classification.config file for class priorities 
     
    238241my %snort_ref_baseurl = (); 
    239242 
    240 ### cache all scan signatures (initialized by default) 
     243### cache all scan signatures from /etc/psad/signatures file 
    241244my %sigs = (); 
    242  
    243 ### cache signature messages, danger levels, etc.  All of these 
    244 ### signatures come from the /etc/psad/signatures file. 
    245 my %sigs_attr = (); 
    246  
    247 ### cache all signatures that have been derived from Snort rules 
    248 ### (these signatures also come from /etc/psad/signatures, but conform 
    249 ### to the new signature format in psad-1.5.0 
    250 my %derived_sigs = (); 
    251 my %derived_sigs_attr = (); 
     245my %sig_search = (); 
    252246 
    253247### cache Netfilter prefixes 
     
    426420    'T' => $tcp_timestamp_type 
    427421); 
     422 
     423### These are not directly support by psad because they 
     424### do not appear in Netfilter logs; however, several of 
     425### these options are supported if fwsnort is also running. 
     426my @unsupported_snort_opts = qw( 
     427    pcre 
     428    fragbits 
     429    content-list 
     430    rpc 
     431    byte_test 
     432    byte_jump 
     433    distance 
     434    within 
     435    flowbits 
     436    rawbytes 
     437    regex 
     438    isdataat 
     439    uricontent 
     440    content 
     441    offset 
     442    replace 
     443    resp 
     444    flowbits 
     445    ip_proto 
     446);  ### the ip_proto keyword could be supported, but would require 
     447    ### refactoring parse_NF_pkt_str(). 
     448 
     449### for Snort signature sp/dp matching 
     450my @port_types = ( 
     451    {'sp' => 'norm', 'dp' => 'norm'}, 
     452    {'sp' => 'norm', 'dp' => 'neg'}, 
     453    {'sp' => 'neg',  'dp' => 'norm'}, 
     454    {'sp' => 'neg',  'dp' => 'neg'}, 
     455); 
     456 
     457### packet parsing return values 
     458my $PKT_ERROR   = 0; 
     459my $PKT_SUCCESS = 1; 
     460my $PKT_IGNORE  = 2; 
     461 
     462### header lengths 
     463my $TCP_HEADER_LEN  = 20;  ### excludes options 
     464my $UDP_HEADER_LEN  = 8; 
     465my $ICMP_HEADER_LEN = 4; 
     466my $IP_HEADER_LEN   = 20;  ### excludes options 
    428467 
    429468### save a copy of the command line arguments 
     
    9621001 
    9631002    my $pkt_ctr = 0; 
    964     my $print_scale_factor = 0; 
    965  
    966     if ($analyze_msgs) { 
    967         if ($#$fw_packets_aref < 100) { 
    968             $print_scale_factor = $#$fw_packets_aref; 
    969         } else { 
    970             $print_scale_factor = int($#$fw_packets_aref/10); 
    971             if ($print_scale_factor < 100) { 
    972                 $print_scale_factor -= $print_scale_factor % 10; 
    973             } elsif ($print_scale_factor < 1000) { 
    974                 $print_scale_factor -= $print_scale_factor % 100; 
    975             } elsif ($print_scale_factor < 10000) { 
    976                 $print_scale_factor -= $print_scale_factor % 1000; 
    977             } elsif ($print_scale_factor < 100000) { 
    978                 $print_scale_factor -= $print_scale_factor % 10000; 
    979             } elsif ($print_scale_factor < 1000000) { 
    980                 $print_scale_factor -= $print_scale_factor % 100000; 
    981             } else { 
    982                 $print_scale_factor = 50000; 
    983             } 
    984         } 
    985         $print_scale_factor++ if $print_scale_factor == 0; 
    986     } 
    987  
    988     #  Mar 11 13:15:52 orthanc kernel: DROP IN=lo OUT= MAC=00:00:00:00:00:00:00:00: 
    989     #  00:00:00:00:08:00 SRC=127.0.0.1 DST=127.0.0.1 LEN=60 TOS=0x00 PREC=0x00 
    990     #  TTL=64 ID=0 DF PROTO=TCP SPT=44847 DPT=35 WINDOW=32304 RES=0x00 SYN URGP=0 
    991  
    992     PKT: for my $pkt (@$fw_packets_aref) { 
    993         my $src = ''; 
    994         my $dst = ''; 
    995         my $len = -1; 
    996         my $tos = ''; 
    997         my $ttl = -1; 
    998         my $id  = -1; 
    999         my $proto = ''; 
    1000         my $sp    = -1; 
    1001         my $dp    = -1; 
    1002         my $win   = -1; 
    1003         my $type  = -1; 
    1004         my $code  = -1; 
    1005         my $seq   = -1; 
    1006         my $flags = ''; 
    1007         my $frag_bit = 0; 
    1008         my $sid   = 0; 
    1009         my $chain    = ''; 
    1010         my $intf     = ''; 
    1011         my $src_mac  = ''; 
    1012         my $dst_mac  = ''; 
    1013         my $tcp_options = ''; 
    1014         my $dshield_str = ''; 
    1015         my $syslog_host = ''; 
    1016         my $log_prefix  = ''; 
    1017  
    1018         print STDERR $pkt, "\n" if $debug; 
     1003 
     1004    my $print_scale_factor = &get_scale_factor($#$fw_packets_aref); 
     1005 
     1006    ### loop through all of the packet log messages we have just acquired 
     1007    ### from Netfilter/iptables 
     1008 
     1009    PKT: for my $pkt_str (@$fw_packets_aref) { 
     1010 
     1011        ### main packet data structure 
     1012        my %pkt = ( 
     1013 
     1014            ### data link layer 
     1015            'src_mac' => '', 
     1016            'dst_mac' => '', 
     1017            'intf'    => '',   ### FIXME in and out interfaces? 
     1018 
     1019            ### network layer 
     1020            'src'    => '', 
     1021            'dst'    => '', 
     1022            'proto'  => '', 
     1023            'ip_id'  => -1, 
     1024            'ttl'    => -1, 
     1025            'tos'    => '', 
     1026            'ip_len' => -1, 
     1027            'itype'  => -1, 
     1028            'icode'  => -1, 
     1029            'icmp_seq' => -1, 
     1030            'icmp_id'  => -1, 
     1031            'frag_bit' => 0, 
     1032 
     1033            ### transport layer 
     1034            'sp'  => -1, 
     1035            'dp'  => -1, 
     1036            'win' => -1, 
     1037            'flags' => -1, 
     1038            'tcp_seq' => -1, 
     1039            'tcp_ack' => -1, 
     1040            'tcp_opt' => '', 
     1041            'udp_len' => -1, 
     1042 
     1043            ### extra fields for psad internals (DShield reporting, fwsnort 
     1044            ### sid matching, Netfilter logging prefixes and chains, etc.) 
     1045            'fwsnort_sid' => 0, 
     1046            'chain'       => '', 
     1047            'log_prefix'  => '', 
     1048            'dshield_str' => '', 
     1049            'syslog_host' => '', 
     1050        ); 
     1051 
    10191052 
    10201053        if ($analyze_msgs) { 
     
    10251058        } 
    10261059 
    1027         ### see if we need to ignore this packet based on the 
    1028         ### IGNORE_PROTOCOLS config keyword. 
    1029         if (%ignore_protocols) { 
    1030             for my $proto (keys %ignore_protocols) { 
    1031                 next PKT if $pkt =~ /\sPROTO=$proto\s/; 
    1032             } 
    1033         } 
    1034  
    1035         ### get the in/out interface and Netfilter chain 
    1036         if ($pkt =~ /IN=(\S+)\s+OUT=\s/) { 
    1037             $intf = $1; 
    1038             $chain = 'INPUT'; 
    1039         } elsif ($pkt =~ /IN=(\S+)\s+OUT=\S/) { 
    1040             $intf = $1; 
    1041             $chain = 'FORWARD'; 
    1042         } elsif ($pkt =~ /IN=\s+OUT=(\S+)/) { 
    1043             $intf = $1; 
    1044             $chain = 'OUTPUT'; 
    1045         } 
    1046  
    1047         if ($pkt =~ /\sMAC=(\S+)/) { 
    1048             my $mac_str = $1; 
    1049             if ($mac_str =~ /^((?:\w{2}\:){6})((?:\w{2}\:){6})/) { 
    1050                 $dst_mac = $1; 
    1051                 $src_mac = $2; 
    1052             } 
    1053         } 
    1054         if ($src_mac) { 
    1055             $src_mac =~ s/:$//; 
    1056             print STDERR "[+] src mac addr: $src_mac\n" if $debug; 
    1057         } 
    1058         if ($dst_mac) { 
    1059             $dst_mac =~ s/:$//; 
    1060             print STDERR "[+] dst mac addr: $dst_mac\n" if $debug; 
    1061         } 
    1062  
    1063         unless ($intf and $chain) { 
    1064             print STDERR "[-] err packet: could not determine ", 
    1065                 "interface and chain.\n" if $debug; 
    1066             push @err_pkts, $pkt; 
     1060        ### main parsing routine for the Netfilter packet logging message 
     1061        my $pkt_parse_rv = &parse_NF_pkt_str(\%pkt, $pkt_str); 
     1062        if ($pkt_parse_rv == $PKT_ERROR) { 
     1063            push @err_pkts, $pkt_str; 
    10671064            next PKT; 
    1068         } 
    1069  
    1070         if (%ignore_interfaces) { 
    1071             for my $ignore_intf (keys %ignore_interfaces) { 
    1072                 next PKT if $intf eq $ignore_intf; 
    1073             } 
    1074         } 
    1075  
    1076         ### get the syslog logging host for this packet 
    1077         if ($pkt =~ /(\S+)\s+kernel:/) { 
    1078             $syslog_host = $1; 
    1079         } elsif ($pkt =~ /^\s*\S+\s+\S+\s+\S+\s+(\S+)/) { 
    1080             ### parsed packet from the beginning where the time portion 
    1081             ### of the syslog message is 
    1082             $syslog_host = $1; 
    1083         } 
    1084  
    1085         ### try to extract a snort sid (generated by fwsnort) from 
    1086         ### the packet 
    1087         unless ($no_snort_sids) { 
    1088             if ($pkt =~ /$config{'SNORT_SID_STR'}(\d+)/) { 
    1089                 $sid = $1; 
    1090             } 
    1091         } 
    1092  
    1093         unless ($sid or $config{'FW_SEARCH_ALL'} eq 'Y') { 
    1094             ### note that this is not _too_ strict since people 
    1095             ### have different ways of writing --log-prefix strings 
    1096             my $matched = 0; 
    1097             for my $fw_search_str (@fw_search) { 
    1098                 $matched = 1 if $pkt =~ /$fw_search_str/; 
    1099             } 
    1100             next PKT unless $matched; 
    1101         } 
    1102  
    1103         ### see if there is a logging prefix (used for scan email alert even 
    1104         ### if we are running with FW_SEARCH_ALL = Y).  Note that sometimes 
    1105         ### there is a buffering issue in the kernel ring buffer that is used 
    1106         ### to hold the Netfilter log message, so we want to get only the 
    1107         ### very last possible candidate for the log prefix (this is why the 
    1108         ### "kernel:" string is preceded by .*). 
    1109         if ($pkt =~ /.*kernel:\s+(.*?)\s*IN=/) { 
    1110             $log_prefix = $1; 
    1111             if ($log_prefix =~ /\S/) { 
    1112                 if ($config{'IGNORE_LOG_PREFIXES'} ne 'NONE') { 
    1113                     next PKT if $log_prefix 
    1114                             =~ m|$config{'IGNORE_LOG_PREFIXES'}|; 
    1115                 } 
    1116                 $ipt_prefixes{$log_prefix}++; 
    1117             } 
    1118         } 
    1119  
    1120         ### May 18 22:21:26 orthanc kernel: DROP IN=eth2 OUT= 
    1121         ### MAC=00:60:1d:23:d0:01:00:60:1d:23:d3:0e:08:00 SRC=192.168.20.25 
    1122         ### DST=192.168.20.1 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=47300 DF 
    1123         ### PROTO=TCP SPT=34111 DPT=6345 WINDOW=5840 RES=0x00 SYN URGP=0 
    1124         if ($pkt =~ /SRC=(\S+)\s+DST=(\S+)\s+LEN=(\d+)\s+TOS=(\S+) 
    1125                     \s*.*\s+TTL=(\d+)\s+ID=(\d+)\s*.*\s+PROTO=TCP\s+ 
    1126                     SPT=(\d+)\s+DPT=(\d+)\s.*\s*WINDOW=(\d+)\s+ 
    1127                     (.*)\s+URGP=/x) { 
    1128             ($src, $dst, $len, $tos, $ttl, $id, $sp, $dp, $win, $flags) = 
    1129                 ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10); 
    1130  
    1131             ### the reserve bits are not reported by ulogd, but normal 
    1132             ### Netfilter syslog messages contain them. 
    1133             $flags =~ s/\s*RES=\S+\s*//; 
    1134  
    1135             $proto = 'tcp'; 
    1136  
    1137             $flags = 'NULL' unless $flags;  ### default to NULL 
    1138             if (!$sid && $config{'IGNORE_CONNTRACK_BUG_PKTS'} eq 'Y' && 
    1139                     ($flags =~ /ACK/ || $flags =~ /RST/)) { 
    1140 #                    $dp > 1024 && ($flags =~ /ACK/ || 
    1141                 ### FIXME: ignore TCP packets that have the ACK or RST 
    1142                 ### bits set (unless we matched a snort sid) since 
    1143                 ### _usually_ we see these packets as a result of the 
    1144                 ### Netfilter connection tracking bug.  Also, note that 
    1145                 ### no signatures make use of the RST flag. 
    1146                 print STDERR "[-] err packet: matched ACK or RST flag.\n" 
    1147                     if $debug; 
    1148                 next PKT; 
    1149             } 
    1150             ### per page 595 of the Camel book, "if /blah1|blah2/" 
    1151             ### can be slower than "if /blah1/ || /blah2/ 
    1152             unless ($flags !~ /WIN/ && 
    1153                     $flags =~ /ACK/ || 
    1154                     $flags =~ /SYN/ || 
    1155                     $flags =~ /RST/ || 
    1156                     $flags =~ /URG/ || 
    1157                     $flags =~ /PSH/ || 
    1158                     $flags =~ /FIN/ || 
    1159                     $flags eq 'NULL') { 
    1160                 print STDERR "[-] err packet: bad tcp flags.\n" if $debug; 
    1161                 push @err_pkts, $pkt; 
    1162                 next PKT; 
    1163             } 
    1164             $frag_bit = 1 if $pkt =~ /\sDF\s+PROTO/; 
    1165             ### don't pickup IP options if --log-ip-options is used 
    1166             ### (they appear before the PROTO= field). 
    1167             if ($pkt =~ /URGP=\S+\s+OPT\s+\((\S+)\)/) { 
    1168                 $tcp_options = $1; 
    1169             } 
    1170  
    1171             ### make sure we have a "reasonable" packet (note that nmap 
    1172             ### can scan port 0 and Netfilter can report this fact) 
    1173             unless ($src and $dst and $len >= 0 and $tos and $ttl >= 0 
    1174                     and $id >= 0 and $proto and $sp >= 0 and $dp >= 0 
    1175                     and $win >= 0 and $flags) { 
    1176                 push @err_pkts, $pkt; 
    1177                 next PKT; 
    1178             } 
    1179  
    1180             ### see if we need to ignore this packet based on the 
    1181             ### IGNORE_PORTS config keyword 
    1182             if (%ignore_ports) { 
    1183                 next PKT if &ignore_port($dp, $proto); 
    1184             } 
    1185  
     1065        } elsif ($pkt_parse_rv == $PKT_IGNORE) { 
     1066            next PKT; 
     1067        } 
     1068 
     1069        if ($pkt{'proto'} eq 'tcp') { 
    11861070            $tcp_ctr++; 
    1187  
    1188             if ($config{'ENABLE_DSHIELD_ALERTS'} eq 'Y' 
    1189                     and not $benchmark 
    1190                     and not $analyze_msgs) { 
    1191                 my $dflags = $flags; 
    1192                 $dflags =~ s/\s/,/g; 
    1193                 $dshield_str = "$src\t$sp\t$dst\t$dp\t$proto\t$dflags"; 
    1194             } 
    1195         ### May 18 22:21:26 orthanc kernel: DROP IN=eth2 OUT= 
    1196         ### MAC=00:60:1d:23:d0:01:00:60:1d:23:d3:0e:08:00 
    1197         ### SRC=192.168.20.25 DST=192.168.20.1 LEN=28 TOS=0x00 PREC=0x00 
    1198         ### TTL=40 ID=47523 PROTO=UDP SPT=57339 DPT=305 LEN=8 
    1199         } elsif ($pkt =~ /SRC=(\S+)\s+DST=(\S+)\s+LEN=(\d+)\s+TOS=(\S+) 
    1200                           \s.*TTL=(\d+)\s+ID=(\d+)\s*.*\s+PROTO=UDP\s+ 
    1201                           SPT=(\d+)\s+DPT=(\d+)/x) { 
    1202             ($src, $dst, $len, $tos, $ttl, $id, $sp, $dp) = 
    1203                 ($1,$2,$3,$4,$5,$6,$7,$8); 
    1204             $proto = 'udp'; 
    1205  
    1206             ### make sure we have a "reasonable" packet (note that nmap 
    1207             ### can scan port 0 and Netfilter can report this fact) 
    1208             unless ($src and $dst and $len >= 0 and $tos and $ttl >= 0 
    1209                     and $id >= 0 and $proto and $sp >= 0 and $dp >= 0) { 
    1210                 push @err_pkts, $pkt; 
    1211                 next PKT; 
    1212             } 
    1213  
    1214             ### see if we need to ignore this packet based on the 
    1215             ### IGNORE_PORTS config keyword 
    1216             if (%ignore_ports) { 
    1217                 next PKT if &ignore_port($dp, $proto); 
    1218             } 
    1219  
     1071        } elsif ($pkt{'proto'} eq 'udp') { 
    12201072            $udp_ctr++; 
    1221  
    1222             if ($config{'ENABLE_DSHIELD_ALERTS'} eq 'Y' 
    1223                     and not $benchmark 
    1224                     and not $analyze_msgs) { 
    1225                 $dshield_str = "$src\t$sp\t$dst\t$dp\t$proto"; 
    1226             } 
    1227         } elsif ($pkt =~ /SRC=(\S+)\s+DST=(\S+)\s+LEN=(\d+).* 
    1228                           TTL=(\d+).*PROTO=ICMP\s+TYPE=(\d+)\s+ 
    1229                           CODE=(\d+)\s+ID=(\d+)\s+SEQ=(\d+)/x) { 
    1230             ($src, $dst, $len, $ttl, $type, $code, $id, $seq) = 
    1231                 ($1,$2,$3,$4,$5,$6,$7,$8); 
    1232             $proto = 'icmp'; 
    1233             unless ($src and $dst and $len >= 0 and $ttl >= 0 and $proto 
    1234                     and $type >= 0 and $code >= 0 and $id >= 0 
    1235                     and $seq >= 0) { 
    1236                 push @err_pkts, $pkt; 
    1237                 next PKT; 
    1238             } 
     1073        } elsif ($pkt{'proto'} eq 'icmp') { 
    12391074            $icmp_ctr++; 
    1240  
    1241             if ($config{'ENABLE_DSHIELD_ALERTS'} eq 'Y' 
    1242                     and not $benchmark 
    1243                     and not $analyze_msgs) { 
    1244                 $dshield_str = "$src\t$type\t$dst\t$code\t$proto"; 
    1245             } 
    1246         } else { 
    1247             ### Sometimes the Netfilter log entry gets messed up due to 
    1248             ### buffering issues so we write it to the error log. 
    1249             print STDERR "[-] err packet: no regex match.\n" if $debug; 
    1250             push @err_pkts, $pkt; 
    1251             next PKT; 
    12521075        } 
    12531076 
    12541077        ### If we made it here then we correctly matched packets 
    12551078        ### that the firewall logged. 
    1256         print STDERR "[+] valid packet: $src -> $dst $proto\n" if $debug; 
     1079        print STDERR "[+] valid packet: $pkt{'src'} -> $pkt{'dst'} ", 
     1080            "$pkt{'proto'}\n" if $debug; 
    12571081 
    12581082        ### initialize the danger level to 0 if it is not already defined 
     
    12601084        ### different destination IP, so the danger level represents the 
    12611085        ### aggregate danger level). 
    1262         unless (defined $scan_dl{$src}) { 
    1263             $scan_dl{$src} = 0; 
    1264             $scan{$src}{$dst}{'alerted'} = 0 
     1086        unless (defined $scan_dl{$pkt{'src'}}) { 
     1087            $scan_dl{$pkt{'src'}} = 0; 
     1088            $scan{$pkt{'src'}}{$pkt{'dst'}}{'alerted'} = 0 
    12651089                if $config{'ALERT_ALL'} eq 'N'; 
    12661090        } 
     
    12701094        ### -1 if there is no auto-assigned danger level. 
    12711095        unless ($no_auto_dl) { 
    1272             my $rv = &assign_auto_danger_level($src, $proto, $dp); 
    1273             if ($debug) { 
    1274                 print STDERR "[+] assign_auto_danger_level() returned: $rv\n"; 
    1275             } 
     1096            my $rv = &assign_auto_danger_level($pkt{'src'}, $pkt{'proto'}, 
     1097                        $pkt{'dp'}); 
     1098 
     1099            print STDERR "[+] assign_auto_danger_level() returned: $rv\n" 
     1100                if $debug; 
    12761101            if ($rv == 0) { 
    1277                 print STDERR "[+] ignoring $src $proto $dp scan.\n" if $debug; 
     1102                print STDERR "[+] ignoring $pkt{'src'} $pkt{'proto'} ", 
     1103                    "$pkt{'dp'} scan.\n" if $debug; 
    12781104                next PKT; 
    12791105            } 
     
    12861112                and not $benchmark 
    12871113                and not $analyze_msgs 
    1288                 and $dshield_str) { 
    1289             if ($pkt =~ /^\s*(\w+)\s+(\d+)\s+(\S+)/) { 
     1114                and $pkt{'dshield_str'}) { 
     1115            if ($pkt_str =~ /^\s*(\w+)\s+(\d+)\s+(\S+)/) { 
    12901116                my $month   = Decode_Month($1); 
    12911117                my $day     = sprintf("%.2d", $2); 
     
    12931119                push @dshield_data, "$year-$month-$day $time_24 " . 
    12941120                    "$timezone\t$config{'DSHIELD_USER_ID'}\t1" . 
    1295                     "\t$dshield_str\n"; 
     1121                    "\t$pkt{'dshield_str'}\n"; 
    12961122            } 
    12971123        } 
     
    12991125        ### see if we need to timeout any old scans 
    13001126        if ($config{'ENABLE_PERSISTENCE'} eq 'N') { 
    1301             if (defined $scan{$src}{$dst}{'s_time'}) { 
    1302                 if ((time() - $scan{$src}{$dst}{'s_time'}) 
     1127            if (defined $scan{$pkt{'src'}}{$pkt{'dst'}}{'s_time'}) { 
     1128                if ((time() - $scan{$pkt{'src'}}{$pkt{'dst'}}{'s_time'}) 
    13031129                        >= $config{'SCAN_TIMEOUT'}) { 
    1304                     delete $scan{$src}{$dst}; 
     1130                    delete $scan{$pkt{'src'}}{$pkt{'dst'}}; 
    13051131                } 
    13061132            } 
     
    13081134 
    13091135        ### record the absolute starting time of the scan 
    1310         unless (defined $scan{$src}{$dst}{'s_time'}) { 
     1136        unless (defined $scan{$pkt{'src'}}{$pkt{'dst'}}{'s_time'}) { 
    13111137            if ($analyze_msgs) { 
    1312                 if ($pkt =~ /^(.*?)\s+\S+\s+kernel:/) { 
    1313                     $scan{$src}{$dst}{'s_time'} = $1; 
    1314                 } elsif ($pkt =~ /^\s*(\S+\s+\S+\s+\S+)/) { 
    1315                     $scan{$src}{$dst}{'s_time'} = $1; 
     1138                if ($pkt_str =~ /^(.*?)\s+\S+\s+kernel:/) { 
     1139                    $scan{$pkt{'src'}}{$pkt{'dst'}}{'s_time'} = $1; 
     1140                } elsif ($pkt_str =~ /^\s*(\S+\s+\S+\s+\S+)/) { 
     1141                    $scan{$pkt{'src'}}{$pkt{'dst'}}{'s_time'} = $1; 
    13161142                } else { 
    1317                     die "[*] Could not extract time from packet: $pkt\n", 
     1143                    die "[*] Could not extract time from packet: $pkt_str\n", 
    13181144                        "    Please send a bug report to: ", 
    13191145                        "mbr\@cipherdyne.org\n"; 
    13201146                } 
    13211147            } else { 
    1322                 $scan{$src}{$dst}{'s_time'} = time(); 
     1148                $scan{$pkt{'src'}}{$pkt{'dst'}}{'s_time'} = time(); 
    13231149            } 
    13241150        } 
    13251151 
    13261152        ### increment hash values 
    1327         $scan{$src}{$dst}{'absnum'}++; 
    1328         $scan{$src}{$dst}{'chain'}{$chain}{$intf}{$proto}++; 
    1329         $curr_scan{$src}{$dst}{$proto}{'pkts'}++; 
    1330         $curr_scan{$src}{$dst}{$proto}{'flags'}{$flags}++ 
    1331             if $flags; 
     1153        $scan{$pkt{'src'}}{$pkt{'dst'}}{'absnum'}++; 
     1154        $scan{$pkt{'src'}}{$pkt{'dst'}}{'chain'} 
     1155            {$pkt{'chain'}}{$pkt{'intf'}}{$pkt{'proto'}}++; 
     1156        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'pkts'}++; 
     1157        $curr_scan{$pkt{'src'}}{$pkt{'dst'}} 
     1158            {$pkt{'proto'}}{'flags'}{$pkt{'flags'}}++ if $pkt{'flags'}; 
    13321159 
    13331160        ### keep track of MAC addresses 
    1334         $curr_scan{$src}{$dst}{'s_mac'} = $src_mac
    1335         $curr_scan{$src}{$dst}{'d_mac'} = $dst_mac
     1161        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{'s_mac'} = $pkt{'src_mac'}
     1162        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{'d_mac'} = $pkt{'dst_mac'}
    13361163 
    13371164        ### keep track of which syslog daemon reported the message. 
    1338         $curr_scan{$src}{$dst}{'syslog_host'}{$syslog_host} = '' 
    1339             if $syslog_host
    1340  
    1341         if ($log_prefix) { 
     1165        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{'syslog_host'} 
     1166            {$pkt{'syslog_host'}} = '' if $pkt{'syslog_host'}
     1167 
     1168        if ($pkt{'log_prefix'}) { 
    13421169            ### see if the logging prefix matches the blocking 
    13431170            ### regex, and if not the IP will not be blocked 
     
    13461173                    and $config{'AUTO_BLOCK_REGEX'} ne 'NONE') { 
    13471174                ### we require a match 
    1348                 if (not defined $auto_block_regex_match{$src
    1349                     and $log_prefix =~ /$config{'AUTO_BLOCK_REGEX'}/) { 
    1350                     $auto_block_regex_match{$src} = ''; 
     1175                if (not defined $auto_block_regex_match{$pkt{'src'}
     1176                    and $pkt{'log_prefix'} =~ /$config{'AUTO_BLOCK_REGEX'}/) { 
     1177                    $auto_block_regex_match{$pkt{'src'}} = ''; 
    13511178                } 
    13521179            } 
    13531180        } else { 
    1354             $log_prefix = '*noprfx*'; 
     1181            $pkt{'log_prefix'} = '*noprfx*'; 
    13551182        } 
    13561183 
    13571184        ### keep track of Netfilter chain and logging prefix 
    1358         $curr_scan{$src}{$dst}{$proto}{'chain'} 
    1359                 {$chain}{$log_prefix}++; 
    1360  
    1361         unless ($proto eq 'icmp') { 
     1185        $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'chain'} 
     1186                {$pkt{'chain'}}{$pkt{'log_prefix'}}++; 
     1187 
     1188        if ($pkt{'proto'} eq 'tcp' or $pkt{'proto'} eq 'udp') { 
    13621189            ### initialize the start and end port for the scanned port range 
    1363             if (not defined $curr_scan{$src}{$dst}{$proto}{'strtp'}) { 
     1190            if (not defined $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'strtp'}) { 
    13641191                ### make sure the initial start port is not too low 
    1365                 $curr_scan{$src}{$dst}{$proto}{'strtp'} = 65535; 
     1192                $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'strtp'} = 65535; 
    13661193                ### make sure the initial end port is not too high 
    1367                 $curr_scan{$src}{$dst}{$proto}{'endp'} = 0; 
    1368             } 
    1369             if (not defined $scan{$src}{$dst}{$proto}{'abs_sp'}) { 
     1194                $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'endp'} = 0; 
     1195            } 
     1196            if (not defined $scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'abs_sp'}) { 
    13701197                ### This is the absolute starting port since the 
    13711198                ### first packet was detected.  Make sure the initial 
    13721199                ### start port is not too low 
    1373                 $scan{$src}{$dst}{$proto}{'abs_sp'} = 65535; 
     1200                $scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'abs_sp'} = 65535; 
    13741201                ### make sure the initial end port is not too high 
    1375                 $scan{$src}{$dst}{$proto}{'abs_ep'} = 0; 
     1202                $scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'abs_ep'} = 0; 
    13761203            } 
    13771204 
    13781205            ### see if the destination port lies outside our current range 
    13791206            ### and change if needed 
    1380             ($curr_scan{$src}{$dst}{$proto}{'strtp'}, 
    1381                     $curr_scan{$src}{$dst}{$proto}{'endp'}) = 
    1382                 &check_range($dp
    1383                     $curr_scan{$src}{$dst}{$proto}{'strtp'}, 
    1384                     $curr_scan{$src}{$dst}{$proto}{'endp'}); 
    1385             ($scan{$src}{$dst}{$proto}{'abs_sp'}, 
    1386                     $scan{$src}{$dst}{$proto}{'abs_ep'}) = 
    1387                 &check_range($dp
    1388                     $scan{$src}{$dst}{$proto}{'abs_sp'}, 
    1389                     $scan{$src}{$dst}{$proto}{'abs_ep'}); 
    1390         } 
    1391  
    1392         print STDERR Dumper $scan{$src}{$dst} if $debug and $verbose; 
     1207            ($curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'strtp'}, 
     1208                    $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'endp'}) = 
     1209                &check_range($pkt{'dp'}
     1210                    $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'strtp'}, 
     1211                    $curr_scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'endp'}); 
     1212            ($scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'abs_sp'}, 
     1213                    $scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'abs_ep'}) = 
     1214                &check_range($pkt{'dp'}
     1215                    $scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'abs_sp'}, 
     1216                    $scan{$pkt{'src'}}{$pkt{'dst'}}{$pkt{'proto'}}{'abs_ep'}); 
     1217        } 
     1218 
     1219        print STDERR Dumper $scan{$pkt{'src'}}{$pkt{'dst'}} if $debug and $verbose; 
    13931220 
    13941221        ### attempt to passively guess the remote operating 
     
    14011228            ### and if we have been unsuccessful in guessing 
    14021229            ### the OS after 100 packets don't keep trying. 
    1403             if ($proto eq 'tcp' and $flags =~ /SYN/) { 
    1404                 if ($tcp_options) {  ### got the tcp options portion of the header 
     1230            if ($pkt{'proto'} eq 'tcp' and $pkt{'flags'} =~ /SYN/) { 
     1231                if ($pkt{'tcp_opt'}) {  ### got the tcp options portion of the header 
    14051232 
    14061233                    ### p0f based fingerprinting 
    1407                     &p0f($src, $len, $frag_bit, $ttl, $win, $tcp_options); 
    1408  
    1409                 } elsif (not defined $posf{$src}{'guess'} 
    1410                         and $scan{$src}{$dst}{'absnum'} < 100) { 
    1411                     &posf($src, $len, $tos, $ttl, $id, $win) 
    1412                 } 
    1413             } 
    1414         } 
    1415  
    1416         if ($sid and not $no_snort_sids) { 
    1417             ### found a snort sid in the packet log message 
    1418             my $dl = &add_snort_sid($src, $dst, 
    1419                 $chain, $proto, $sid); 
    1420             $curr_sids_dl{$src} = $dl if $dl; 
    1421         } else { 
    1422             ### attempt to match any tcp/udp/icmp signatures in the 
    1423             ### main signatures hash 
    1424             unless ($no_signatures) { 
    1425                 my $dl = &match_sigs($src, $dst, $chain, $sp, 
    1426                     $dp, $proto, $flags, $len, $ttl, 
    1427                     $type, $code, $id, $seq); 
    1428                 $curr_sigs_dl{$src} = $dl if $dl; 
     1234                    &p0f($pkt{'src'}, $pkt{'ip_len'}, $pkt{'frag_bit'}, 
     1235                            $pkt{'ttl'}, $pkt{'win'}, $pkt{'tcp_opt'}); 
     1236 
     1237                } elsif (not defined $posf{$pkt{'src'}}{'guess'} 
     1238                        and $scan{$pkt{'src'}}{$pkt{'dst'}}{'absnum'} < 100) { 
     1239                    &posf($pkt{'src'}, $pkt{'ip_len'}, $pkt{'tos'}, 
     1240                            $pkt{'ttl'}, $pkt{'ip_id'}, $pkt{'win'}) 
     1241                } 
     1242            } 
     1243        } 
     1244 
     1245        unless ($no_snort_sids) { 
     1246            if ($pkt{'fwsnort_sid'}) { 
     1247 
     1248                ### found a snort sid in the packet log message 
     1249                my $dl = &add_snort_sid(\%pkt); 
     1250 
     1251                $curr_sids_dl{$pkt{'src'}} = $dl if $dl; 
     1252 
     1253            } else { 
     1254                ### attempt to match any tcp/udp/icmp signatures in the 
     1255                ### main signatures hash 
     1256                unless ($no_signatures) { 
     1257 
     1258                    my $dl = &match_sigs(\%pkt); 
     1259 
     1260                    $curr_sigs_dl{$pkt{'src'}} = $dl if $dl; 
     1261                } 
    14291262            } 
    14301263        } 
     
    14621295} 
    14631296 
     1297sub parse_NF_pkt_str() { 
     1298    my ($pkt_hr, $pkt_str) = @_; 
     1299 
     1300    print STDERR $pkt_str, "\n" if $debug; 
     1301 
     1302    ### see if there is a logging prefix (used for scan email alert even 
     1303    ### if we are running with FW_SEARCH_ALL = Y).  Note that sometimes 
     1304    ### there is a buffering issue in the kernel ring buffer that is used 
     1305    ### to hold the Netfilter log message, so we want to get only the 
     1306    ### very last possible candidate for the log prefix (this is why the 
     1307    ### "kernel:" string is preceded by .*). 
     1308    if ($pkt_str =~ /.*kernel:\s+(.*?)\s*IN=/) { 
     1309        $pkt_hr->{'log_prefix'} = $1; 
     1310        if ($pkt_hr->{'log_prefix'} =~ /\S/) { 
     1311            if ($config{'IGNORE_LOG_PREFIXES'} ne 'NONE') { 
     1312                return $PKT_IGNORE if $pkt_hr->{'log_prefix'} 
     1313                        =~ m|$config{'IGNORE_LOG_PREFIXES'}|; 
     1314            } 
     1315            $ipt_prefixes{$pkt_hr->{'log_prefix'}}++; 
     1316        } 
     1317    } 
     1318 
     1319    ### get the in/out interface and Netfilter chain 
     1320    if ($pkt_str =~ /IN=(\S+)\s+OUT=\s/) { 
     1321        $pkt_hr->{'intf'} = $1; 
     1322        $pkt_hr->{'chain'} = 'INPUT'; 
     1323    } elsif ($pkt_str =~ /IN=(\S+)\s+OUT=\S/) { 
     1324        $pkt_hr->{'intf'} = $1; 
     1325        $pkt_hr->{'chain'} = 'FORWARD'; 
     1326    } elsif ($pkt_str =~ /IN=\s+OUT=(\S+)/) { 
     1327        $pkt_hr->{'intf'} = $1; 
     1328        $pkt_hr->{'chain'} = 'OUTPUT'; 
     1329    } 
     1330 
     1331    if ($pkt_str =~ /\sMAC=(\S+)/) { 
     1332        my $mac_str = $1; 
     1333        if ($mac_str =~ /^((?:\w{2}\:){6})((?:\w{2}\:){6})/) { 
     1334            $pkt_hr->{'dst_mac'} = $1; 
     1335            $pkt_hr->{'src_mac'} = $2; 
     1336        } 
     1337    } 
     1338    if ($pkt_hr->{'src_mac'}) { 
     1339        $pkt_hr->{'src_mac'} =~ s/:$//; 
     1340        print STDERR "[+] src mac addr: $pkt_hr->{'src_mac'}\n" if $debug; 
     1341    } 
     1342    if ($pkt_hr->{'dst_mac'}) { 
     1343        $pkt_hr->{'dst_mac'} =~ s/:$//; 
     1344        print STDERR "[+] dst mac addr: $pkt_hr->{'dst_mac'}\n" if $debug; 
     1345    } 
     1346 
     1347    unless ($pkt_hr->{'intf'} and $pkt_hr->{'chain'}) { 
     1348        print STDERR "[-] err packet: could not determine ", 
     1349            "interface and chain.\n" if $debug; 
     1350        return $PKT_ERROR; 
     1351    } 
     1352 
     1353    if (%ignore_interfaces) { 
     1354        for my $ignore_intf (keys %ignore_interfaces) { 
     1355            return $PKT_IGNORE if $pkt_hr->{'intf'} eq $ignore_intf; 
     1356        } 
     1357    } 
     1358 
     1359    ### get the syslog logging host for this packet 
     1360    if ($pkt_str =~ /(\S+)\s+kernel:/) { 
     1361        $pkt_hr->{'syslog_host'} = $1; 
     1362    } elsif ($pkt_str =~ /^\s*\S+\s+\S+\s+\S+\s+(\S+)/) { 
     1363        ### parsed packet from the beginning where the time portion 
     1364        ### of the syslog message is 
     1365        $pkt_hr->{'syslog_host'} = $1; 
     1366    } 
     1367 
     1368    ### try to extract a snort sid (generated by fwsnort) from 
     1369    ### the packet 
     1370    unless ($no_snort_sids) { 
     1371        if ($pkt_str =~ /$config{'SNORT_SID_STR'}(\d+)/) { 
     1372            $pkt_hr->{'fwsnort_sid'} = $1; 
     1373        } 
     1374    } 
     1375 
     1376    unless ($pkt_hr->{'fwsnort_sid'} or $config{'FW_SEARCH_ALL'} eq 'Y') { 
     1377        ### note that this is not _too_ strict since people 
     1378        ### have different ways of writing --log-prefix strings 
     1379        my $matched = 0; 
     1380        for my $fw_search_str (@fw_search) { 
     1381            $matched = 1 if $pkt_str =~ /$fw_search_str/; 
     1382        } 
     1383        return $PKT_IGNORE unless $matched; 
     1384    } 
     1385 
     1386    ### May 18 22:21:26 orthanc kernel: DROP IN=eth2 OUT= 
     1387    ### MAC=00:60:1d:23:d0:01:00:60:1d:23:d3:0e:08:00 SRC=192.168.20.25 
     1388    ### DST=192.168.20.1 LEN=60 TOS=0x10 PREC=0x00 TTL=64 ID=47300 DF 
     1389    ### PROTO=TCP SPT=34111 DPT=6345 WINDOW=5840 RES=0x00 SYN URGP=0 
     1390 
     1391    if ($pkt_str =~ /SRC=($ip_re)\s+DST=($ip_re)\s+LEN=(\d+)\s+TOS=(\S+) 
     1392                \s*.*\s+TTL=(\d+)\s+ID=(\d+)\s*.*\s+PROTO=TCP\s+ 
     1393                SPT=(\d+)\s+DPT=(\d+)\s.*\s*WINDOW=(\d+)\s+ 
     1394                (.*)\s+URGP=/x) { 
     1395 
     1396        ($pkt_hr->{'src'}, $pkt_hr->{'dst'}, $pkt_hr->{'ip_len'}, 
     1397            $pkt_hr->{'tos'}, $pkt_hr->{'ttl'}, $pkt_hr->{'ip_id'}, 
     1398            $pkt_hr->{'sp'}, $pkt_hr->{'dp'}, $pkt_hr->{'win'}, 
     1399            $pkt_hr->{'flags'}) 
     1400                = ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10); 
     1401 
     1402        ### the reserve bits are not reported by ulogd, but normal 
     1403        ### Netfilter syslog messages contain them. 
     1404        $pkt_hr->{'flags'} =~ s/\s*RES=\S+\s*//; 
     1405 
     1406        $pkt_hr->{'proto'} = 'tcp'; 
     1407 
     1408        ### default to NULL 
     1409        $pkt_hr->{'flags'} = 'NULL' unless $pkt_hr->{'flags'}; 
     1410 
     1411        if (not $pkt_hr->{'fwsnort_sid'} 
     1412                and $config{'IGNORE_CONNTRACK_BUG_PKTS'} eq 'Y' && 
     1413                ($pkt_hr->{'flags'} =~ /ACK/ || $pkt_hr->{'flags'} =~ /RST/)) { 
     1414 
     1415            ###                 $dp > 1024 && ($pkt_hr->{'flags'} =~ /ACK/ || 
     1416 
     1417            ### FIXME: ignore TCP packets that have the ACK or RST 
     1418            ### bits set (unless we matched a snort sid) since 
     1419            ### _usually_ we see these packets as a result of the 
     1420            ### Netfilter connection tracking bug.  Also, note that 
     1421            ### no signatures make use of the RST flag. 
     1422 
     1423            print STDERR "[-] err packet: matched ACK or RST flag.\n" 
     1424                if $debug; 
     1425            return $PKT_IGNORE; 
     1426        } 
     1427 
     1428        ### per page 595 of the Camel book, "if /blah1|blah2/" 
     1429        ### can be slower than "if /blah1/ || /blah2/ 
     1430        unless ($pkt_hr->{'flags'} !~ /WIN/ && 
     1431                $pkt_hr->{'flags'} =~ /ACK/ || 
     1432                $pkt_hr->{'flags'} =~ /SYN/ || 
     1433                $pkt_hr->{'flags'} =~ /RST/ || 
     1434                $pkt_hr->{'flags'} =~ /URG/ || 
     1435                $pkt_hr->{'flags'} =~ /PSH/ || 
     1436                $pkt_hr->{'flags'} =~ /FIN/ || 
     1437                $pkt_hr->{'flags'} eq 'NULL') { 
     1438 
     1439            print STDERR "[-] err packet: bad tcp flags.\n" if $debug; 
     1440            return $PKT_ERROR; 
     1441        } 
     1442        $pkt_hr->{'frag_bit'} = 1 if $pkt_str =~ /\sDF\s+PROTO/; 
     1443 
     1444        ### don't pickup IP options if --log-ip-options is used