### regex to match IP addresses
my $ip_re = qr|(?:[0-2]?\d{1,2}\.){3}[0-2]?\d{1,2}|; ### IPv4
-my $ipv6_re = qr|(?:[a-f0-9]{4}:){7}(?:[a-f0-9]{4})|; ### IPv6
+my $ipv6_re = qr|(?:[a-f0-9]{4}:){7}(?:[a-f0-9]{4})|i; ### IPv6
### ttl values are decremented depending on the number of hops
### the packet has taken before it hits the firewall. We will
### system based on the ttl, id, len, window, and tos
### fields in tcp syn packets (this technique is based
### on the paper "Passive OS Fingerprinting: Details
- ### and Techniques" by Toby Miller).
+ ### and Techniques" by Toby Miller). Also attempt to
+ ### fingerprint with a re-implementation of Michal Zalewski's
+ ### p0f that only requires iptables log messages
unless ($no_posf) {
### make sure we have not already guessed the OS,
### and if we have been unsuccessful in guessing
} elsif (not defined $posf{$pkt{'src'}}{'guess'}
and $scan{$pkt{'src'}}{$pkt{'dst'}}{'absnum'} < 100) {
- &posf($pkt{'src'}, $pkt{'ip_len'}, $pkt{'tos'},
- $pkt{'ttl'}, $pkt{'ip_id'}, $pkt{'win'})
+ &posf(\%pkt);
}
}
}
$pkt_hr->{'d_obj'} = new NetAddr::IP($pkt_hr->{'dst'})
or return $PKT_ERROR;
- ### the reserve bits are not reported by ulogd, but normal
- ### iptables syslog messages contain them.
- $pkt_hr->{'flags'} =~ s/\s*RES=\S+\s*//;
-
} else {
print STDERR "[-] err packet: strange IPv4 TCP format\n"
if $debug;
$pkt_hr->{'proto'} = 'tcp';
+ ### the reserve bits are not reported by ulogd, but normal
+ ### iptables syslog messages contain them.
+ $pkt_hr->{'flags'} =~ s/\s*RES=\S+\s*//;
+
### default to NULL
$pkt_hr->{'flags'} = 'NULL' unless $pkt_hr->{'flags'};
}
}
- return $PKT_IGNORE if $pkt_hr->{'is_ipv6'};
-
return $PKT_SUCCESS;
}
SRC: for my $src (keys %{$sig_search{$proto}}) {
- print STDERR "[+] match_sigs() pkt src: $pkt_hr->{'src'} within sig src: $src?..."
+ print STDERR "[+] match_sigs() pkt src: $pkt_hr->{'src'} within sig src: $src ?..."
if $debug and $verbose;
if ($pkt_hr->{'s_obj'}->within($sig_ip_objs{$src})) {
DST: for my $dst (keys %{$sig_search{$proto}{$src}}) {
- print STDERR "[+] match_sigs() pkt dst: $pkt_hr->{'dst'} within sig dst: $dst?..."
+ print STDERR "[+] match_sigs() pkt dst: $pkt_hr->{'dst'} within sig dst: $dst ?..."
if $debug and $verbose;
if ($pkt_hr->{'d_obj'}->within($sig_ip_objs{$dst})) {
sub match_snort_ip_keywords() {
my ($pkt_hr, $sig_hr) = @_;
+ if ($pkt_hr->{'is_ipv6'}) {
+ ### we need to build IPv6 signature keywords
+ return 1, $NO_SIG_MATCH;
+ }
+
if (defined $sig_hr->{'ttl'} and defined $sig_hr->{'ttl_s'}) {
return 0, $NO_SIG_MATCH
unless &check_sig_int_range($pkt_hr->{'ttl'}, 'ttl', $sig_hr);
}
sub posf() {
- my ($src, $len, $tos, $ttl, $id, $win) = @_;
+ my $pkt_hr = shift;
+
+ if ($pkt_hr->{'is_ipv4'}) {
+ &posf_ipv4($pkt_hr);
+ } elsif ($pkt_hr->{'is_ipv6'}) {
+ &posf_ipv6($pkt_hr);
+ }
+ return;
+}
+
+sub posf_ipv6() {
+ my $pkt_hr = shift;
+ return;
+}
+
+sub posf_ipv4() {
+ my $pkt_hr = shift;
+
+ my $src = $pkt_hr->{'src'};
+ my $len = $pkt_hr->{'ip_len'};
+ my $tos = $pkt_hr->{'tos'};
+ my $ttl = $pkt_hr->{'ttl'};
+ my $id = $pkt_hr->{'ip_id'};
+ my $win = $pkt_hr->{'win'};
my $min_ttl;
my $max_ttl;
next if $intf_name =~ /dummy/i;
if ($line =~ /^\s+inet.*?($ip_re)\/(\d+)/i) {
push @connected_subnets, new NetAddr::IP($1, $2);
+ } elsif ($line =~ /inet6\s(\S+)/) {
+ push @connected_subnets, new6 NetAddr::IP($1);
}
}
} else {
next if $intf_name =~ /dummy/i;
if ($line =~ /^\s+inet.*?:($ip_re).*:($ip_re)/i) {
push @connected_subnets, new NetAddr::IP($1, $2);
+ } elsif ($line =~ /^\s+inet6\saddr:\s+(\S+)/) {
+ push @connected_subnets, new6 NetAddr::IP($1);
}
}
}
or $ip =~ m|($ip_re)|) {
push @arr, $1;
$sig_ip_objs{$1} = new NetAddr::IP($1);
+ } elsif ($ip =~ m|\:|) {
+ push @arr, $ip;
+ $sig_ip_objs{$ip} = new NetAddr::IP($ip)
+ or die "[*] NetAddr::IP error for $ip";
}
}
+
} elsif ($ip_str =~ m|($ip_re/$ip_re)|
or $ip_str =~ m|($ip_re/\d+)|
or $ip_str =~ m|($ip_re)|) {
push @arr, $1;
- $sig_ip_objs{$1} = new NetAddr::IP($1);
+ $sig_ip_objs{$1} = new NetAddr::IP($1)
+ or die "[*] NetAddr::IP error for $1";
+
+ } elsif ($ip_str =~ m|\:|) {
+
+ push @arr, $ip_str;
+ $sig_ip_objs{$ip_str} = new NetAddr::IP($ip_str)
+ or die "[*] NetAddr::IP error for $ip_str";
+
} elsif ($ip_str eq 'any' or $ip_str =~ m|NOT_?USED|i) {
### handle NOT_USED case from older psad versions
push @arr, 'any';
"${src_dir}/${lookup_ip}_whois");
if ($debug and $verbose) {
- print STDERR for $whois_info_ar;
+ print STDERR for @$whois_info_ar;
}
}
print STDERR "[+] scan_logr(): generating email.....\n"
if ($line =~ /inet\s+($ip_re)\/\d+\s/) {
print STDERR "[+] : Adding $1 to local_ips\n" if $debug;
$local_ips{$1} = '';
+ } elsif ($line =~ /inet6\s(\S+)/) {
+ print STDERR "[+] : Adding $1 to local_ips\n" if $debug;
+ $local_ips{$1} = '';
}
}
} else {
if ($line =~ /inet\s+.*?:($ip_re)\s/) {
print STDERR "[+] : Adding $1 to local_ips\n" if $debug;
$local_ips{$1} = '';
+ } elsif ($line =~ /inet6\s+addr:\s+(\S+)/) {
+ print STDERR "[+] : Adding $1 to local_ips\n" if $debug;
+ $local_ips{$1} = '';
}
}
}
my $src_str = "\nSRC: $src, DL: $dl, Dsts: $total_dsts" .
", Pkts: $tot_pkts, Unique sigs: $uniq_sigs";
+ my $src_obj = new NetAddr::IP($src) or die "[*] NetAddr::IP($src) error";
+ if ($src_obj->version() == 6) {
+ $src_str = "\nSRC: $src (" . $src_obj->short() . "), DL: $dl, Dsts: $total_dsts" .
+ ", Pkts: $tot_pkts, Unique sigs: $uniq_sigs";
+ }
+
unless ($analyze_mode) {
my $tot_alerts = 0;
if ($config{'ENABLE_EMAIL_LIMIT_PER_DST'} eq 'Y') {
}
$src_str .= ", Email alerts: $tot_alerts";
}
- if (&is_local($src, new NetAddr::IP($src))) {
+ if (&is_local($src, $src_obj)) {
$src_str .= ', Local IP';
}
$printed = 1;
DST: for my $dst (keys %{$scan{$src}}) {
my $dst_str = " DST: $dst";
- if (&is_local($dst, new NetAddr::IP($dst))) {
+ my $dst_obj = new NetAddr::IP($dst)
+ or die "[*] NetAddr::IP($dst) error";
+ if ($dst_obj->version() == 6) {
+ $dst_str = " DST: $dst (" . $dst_obj->short() . ')';
+ }
+ if (&is_local($dst, $dst_obj)) {
$dst_str .= ', Local IP';
}
push @lines, "$dst_str\n";
} else {
push @lines, "[+] Top attackers:\n";
}
+
my $ctr = 0;
my %pre_sort_dl = ();
+ my %ip_objs = ();
+
for my $src (sort {$scan_dl{$b} cmp $scan_dl{$a}} keys %scan_dl) {
if ($status_min_dl) {
next unless $scan_dl{$src} >= $status_min_dl;
$pre_sort_dl{$scan_dl{$src}}{$src} = '';
}
+ my $ip6_short_len = 0;
+ for my $dl qw/5 4 3 2 1/ {
+ next unless defined $pre_sort_dl{$dl};
+
+ for my $src (sort keys %{$pre_sort_dl{$dl}}) {
+ next unless defined $top_packet_counts{$src}
+ or defined $top_sig_counts{$src};
+
+ my $ip_obj = new NetAddr::IP($src)
+ or die "[*] NetAddr::IP $src error";
+
+ $ip_objs{$src} = $ip_obj;
+ if ($ip_obj->version() == 6) {
+ if (length($ip_obj->short()) > $ip6_short_len) {
+ $ip6_short_len = length($ip_obj->short());
+ }
+ }
+ }
+ }
+
for my $dl qw/5 4 3 2 1/ {
next unless defined $pre_sort_dl{$dl};
next unless defined $top_packet_counts{$src}
or defined $top_sig_counts{$src};
my $str = sprintf " %-15s DL: %d", $src, $scan_dl{$src};
+ if ($ip_objs{$src}->version() == 6) {
+ $str = sprintf " %s (%-${ip6_short_len}s) DL: %d", $src,
+ $ip_objs{$src}->short(), $scan_dl{$src};
+ }
if (defined $top_packet_counts{$src}) {
$str .= ", Packets: $top_packet_counts{$src}";
} else {
'analysis-write-data' => \$analyze_write_data, # Write data to filesystem from
# -A mode (this can take a long
# time).
+ 'analyze-write-data' => \$analyze_write_data,
'analysis-fields=s' => \$analysis_fields, # Place a criteria on various fields
# that are parsed from an iptables
# logfile.
+ 'analyze-fields=s' => \$analysis_fields,
'whois-analysis' => \$analysis_whois, # Issue whois lookups in analysis
# mode.
'email-analysis' => \$analysis_emails, # Send analysis mode emails.