#!/usr/bin/perl -Tw # $Author: hso $ # $Date: 2001/01/02 00:49:55 $ # $Revision: 1.12 $ # $RCSfile: snifob,v $ use vars qw( @default_color_set @mac_addr_color_set @src_ip_color_set @dst_ip_color_set @src_port_color_set @dst_port_color_set @time_color_set @hex_p_color_set @hex_np_color_set @keyword_color_set %foreground %background %intensity $reset $escape $s_hex_re $hex_X_re $hex_x_re $hex_smb_re $s_timestamp_re $t_timestamp_re $t_epoch_timestamp_re $num_ip_addr_re $aip_addr_re $hostname_re $fqdn_re $alphnum_hn_port_re $num_port_re $alphnum_port_re $mac_addr_re $sniffer $sniffer_options $sniffer_dump $sniffer_options_dump $using_snifoutfh $rel_version $opt_Help $opt_Nocolor $opt_Nodecode $opt_Run $opt_Drun $eol ); use strict; use Getopt::Long; ## begin user configurable # color sets @default_color_set = qw(dark cyan black); @mac_addr_color_set = qw(dark cyan blue); @src_ip_color_set = qw(bright magenta black); @dst_ip_color_set = qw(bright yellow black); @src_port_color_set = qw(dark white blue); @dst_port_color_set = qw(dark black green); @time_color_set = qw(dark green black); @hex_p_color_set = qw(bright green black); @hex_np_color_set = qw(dark blue black); @keyword_color_set = qw(bright cyan blue); $sniffer = "Not configured"; $sniffer_options = "Not configured"; #$sniffer = "/usr/local/bin/sudo /usr/local/bin/snort"; #$sniffer_options = "-A none -axvBi eth0"; #$sniffer = "/usr/local/bin/sudo /usr/local/sbin/tcpdump"; #$sniffer_options = "-vveln"; # the following should include an option or options to dump the # packet payload $sniffer_dump = "Not configured"; $sniffer_options_dump = "Not configured"; #$sniffer_dump = "/usr/local/bin/sudo /usr/local/bin/snort"; #$sniffer_options_dump = "-A none -axvdBi eth0"; #$sniffer_dump = "/usr/local/bin/sudo /usr/local/sbin/tcpdump"; #$sniffer_options_dump = "-Xvvelns 1518"; ## begin potentially evil security hole # # *NOTE*: users could set their environment to anything they # want and this program *will* run that code. This is bad # if you are using sudo with a policy for a user to only # run snifob as root. You could tighten the de-tainting # regex: /(.*)/ to fit what you're trying to accomplish to # help. # #$sniffer = $ENV{sniffer}; #$sniffer_options = $ENV{sniffer_options}; # #if ($sniffer =~ /(.*)/) { # $sniffer = $1; #} #if ($sniffer_options =~ /(.*)/) { # $sniffer_options = $1; #} # ## end potentially evil security hole ## end user configurable ## begin non user configurable ( certainly user hackable, however ;) ) ## use the source l |_| |< 3 !! # clean path for perl -T $ENV{PATH} = ""; $ENV{ENV} = ""; # signal handlers to clean up colorization $SIG{INT} = \&sig_exit_cleanup_handler; $SIG{QUIT} = \&sig_exit_cleanup_handler; $SIG{STOP} = \&sig_stop_cleanup_handler; # colors %foreground = ( black => 30, red => 31, green => 32, yellow => 33, blue => 34, magenta => 35, cyan => 36, white => 37 ); %background = ( black => 40, red => 41, green => 42, yellow => 43, blue => 44, magenta => 45, cyan => 46, white => 47 ); %intensity = ( dark => 0, bright => 1 ); # escape sequences $escape = "\033["; $reset = "00m"; # patterns $s_hex_re = '([\dA-F]{2} ){1,16}\s+.{1,16}'; $hex_X_re = '0x[\dA-Fa-f]{4}\s+[\dA-Fa-f]+'; $hex_x_re = '\s+[\dA-Fa-f]+'; $hex_smb_re = '\[[A-Fa-f\d]{3}\]( [A-Fa-f\d]{2})+'; $s_timestamp_re = '\d{2}\/\d{2}-\d{2}:\d{2}:\d{2}\.\d{6}'; $t_timestamp_re = '(\d\d:){2}\d\d\.\d+'; $t_epoch_timestamp_re = '\d+\.\d{6}'; $num_ip_addr_re = '(((2([0-4]\d|5[0-5])|[01]?\d{1,2}))\.){3}((2([0-4]\d|5[0-5])|[01]?\d{1,2}))'; # hostname_re and fqdn_re shouldn't accept (see RFC 1035) '_' (found in \w); Since some people # have used '_' in their labels/hostnames.... $hostname_re = '(([a-zA-z][A-Za-z\d_-]{1,61}[A-Za-z\d])|([a-zA-z][A-Za-z\d])|[a-zA-z])'; $fqdn_re = '((([a-zA-z][A-Za-z\d_-]{1,61}[A-Za-z\d])|([a-zA-z][A-Za-z\d])|[a-zA-z])\.)+(([a-zA-z][A-Za-z\d_-]{1,61}[A-Za-z\d])|([a-zA-z][A-Za-z\d])|[a-zA-z])'; $num_port_re = '\d{1,5}'; $alphnum_port_re = '[\w-]+'; $mac_addr_re = '([\dA-Fa-f]{1,2}:){5}[\dA-Fa-f]{1,2}'; # global variables $eol = $/; $rel_version = "0.9"; $using_snifoutfh = 0; # immediately flush output buffer when data is written $| = 1; GetOptions( "help" => \$opt_Help, "nocolor" => \$opt_Nocolor, "nodecode" => \$opt_Nodecode, "run" => \$opt_Run, "drun" => \$opt_Drun ); #begin "main" { my $fh_to_read = (); &reset_ansi(); if ($opt_Help) { print "\n"; print "Options available for $0 v$rel_version:\n"; print "\n"; print " --help\tshow this information\n"; print " --nocolor\tdo not colorize output\n"; print " --nodecode\tdo not de-hexify tcpdump -x output\n"; print " --run\trun \"$sniffer\" with options \"$sniffer_options\" &\n"; print " \t\tsnag stdout (doesn't dump packet payload)\n"; print " --drun\trun \"$sniffer_dump\" with options \"$sniffer_options_dump\" &\n"; print " \t\tsnag stdout (dumps packet payload)\n"; print "\n"; print " For additional information, run perldoc on $0\n"; print "\n"; exit 1; } if ($opt_Run) { if ($sniffer eq "Not configured" || $sniffer_options eq "Not configured") { print "\nEdit $0 and configure \$sniffer and \$sniffer_options\n\n"; exit 1; } else { open(SNIFOUTFH, "$sniffer $sniffer_options|") || die "Can't start \"$sniffer $sniffer_options\". error: $?"; $using_snifoutfh = 1; print "$0 v$rel_version processing SNIFOUTFH.\n"; } } elsif ($opt_Drun) { if ($sniffer_dump eq "Not configured" || $sniffer_options_dump eq "Not configured") { print "\nEdit $0 and configure \$sniffer_dump and \$sniffer_options_dump\n\n"; exit 1; } else { open(SNIFOUTFH, "$sniffer_dump $sniffer_options_dump|") || die "Can't start \"$sniffer_dump $sniffer_options_dump\". error: $?"; $using_snifoutfh = 1; print "$0 v$rel_version processing SNIFOUTFH.\n"; } } else { print "$0 v$rel_version processing stdin.\n"; } &colorize(\@default_color_set); ## begin main loop if ($opt_Run || $opt_Drun) { while () { &match_line($_); } } else { while() { &match_line($_); } } ## end main loop if ($opt_Run || $opt_Drun) { close(SNIFOUTFH); } } #end "main" sub match_line () { my $line_matched = 0; my $line = (); $line = &multi_chomp($_[0]); if (!$line_matched && !$opt_Nodecode && $line =~ /^$hex_x_re/) { &old_hex($line); $line_matched = 1; } if (!$line_matched && $line =~ /^$hex_X_re/) { &new_hex($line); $line_matched = 1; } if (!$line_matched && $line =~ /^$hex_smb_re/) { &smb_hex($line); $line_matched = 1; } # tcpdump info lines if (!$line_matched && $line =~ /^arp (who-has|reply)/) { &arp_info_line($line); $line_matched = 1; } if ( !$line_matched && ( ($line =~ /^$t_timestamp_re/) || ($line =~ /^$t_epoch_timestamp_re/) ) ) { &time_info_line($line); $line_matched = 1; } if ( !$line_matched && ( ($line =~ /^$num_ip_addr_re\.($num_port_re|$alphnum_port_re) > /) || ($line =~ /^$fqdn_re\.($num_port_re|$alphnum_port_re) > /) || ($line =~ /^$hostname_re\.($num_port_re|$alphnum_port_re) > /) ) ) { if(&addr_port_info_line($line) == 1) { $line_matched = 1; } } if ( !$line_matched && ( ($line =~ /^$num_ip_addr_re > /) || ($line =~ /^$fqdn_re > /) || ($line =~ /^$hostname_re > /) ) ) { &addr_info_line($line); $line_matched = 1; } if (!$line_matched && $line =~ /^$mac_addr_re/) { &mac_info_line($line); $line_matched = 1; } # snort lines if ( !$line_matched && ( ($line =~/^$s_timestamp_re/) ) ) { &s_time_info_line($line); $line_matched = 1; } if ( !$line_matched && ( ($line =~/^$s_hex_re/) ) ) { &s_hex_line($line); $line_matched = 1; } if ( !$line_matched && ( ($line =~/^$num_ip_addr_re(:$num_port_re)? -> $num_ip_addr_re(:$num_port_re)?/) ) ) { &s_ipaddr_line($line); $line_matched = 1; } if ( !$line_matched && ( ($line =~/^(ICMP|TCP|UDP)/) ) ) { my @tmp_line_array = split(/\ /, $line); &s_process_rest_of_line(\@tmp_line_array); $line_matched = 1; } # what if dos, do we need \r\n ? if (! $line_matched) { print ("$line$eol"); } $line_matched = 0; } # snort functions sub s_time_info_line() { my $wrk_line = $_[0]; my @wrk_line_array = (); my $date = (); my $time = (); @wrk_line_array = split("\ ", $wrk_line); ($date, $time) = split(/-/, shift(@wrk_line_array)); &colorize(\@time_color_set); print "$date"; &colorize(\@default_color_set); print "-"; &colorize(\@time_color_set); print "$time"; &colorize(\@default_color_set); &s_process_rest_of_line(\@wrk_line_array); } sub s_ipaddr_line() { my $wrk_line = $_[0]; my @wrk_line_array = (); my $addr = (); my $port = (); @wrk_line_array = split("\ ", $wrk_line); $addr = shift(@wrk_line_array); if (index($addr, ":") >= 0) { ($addr, $port) = split (/:/, $addr); &colorize(\@src_ip_color_set); print "$addr"; &colorize(\@default_color_set); print ":"; &colorize(\@src_port_color_set); print "$port"; &colorize(\@default_color_set); } else { &colorize(\@src_ip_color_set); print "$addr"; &colorize(\@default_color_set); } &s_process_rest_of_line(\@wrk_line_array); } sub s_hex_line() { my $wrk_line = $_[0]; my $beg_hex_chunk = (); my $end_hex_chunk = (); my @lhs_hex_array = (); my @rhs_hex_array = (); my $l_ele = (); my $r_ele = (); my $index = 0; my $padding = 0; if ($wrk_line =~ /(([A-Fa-f\d]{2} ){1,16})(\s+)(.{1,16})/) { $beg_hex_chunk = $1; $padding = $3; $end_hex_chunk = $4; } @lhs_hex_array = split(/\ /, $beg_hex_chunk); @rhs_hex_array = split(/ */, $end_hex_chunk); foreach $l_ele (@lhs_hex_array) { if ($l_ele ge "20" && $l_ele le "7E") { &colorize(\@hex_p_color_set); print "$l_ele"; &colorize(\@default_color_set); if ($index <= $#lhs_hex_array) { print " "; } } else { &colorize(\@hex_np_color_set); print "$l_ele"; $rhs_hex_array[$index] = "\0"; if ($index <= $#lhs_hex_array) { print " "; } } $index++; } print $padding; foreach $r_ele (@rhs_hex_array) { if ($r_ele ge " " && $r_ele le "~") { &colorize(\@hex_p_color_set); print "$r_ele"; &colorize(\@default_color_set); } else { &colorize(\@hex_np_color_set); print "."; } } print "\n"; } sub s_process_rest_of_line() { my $wrk_line_array_ref = $_[0]; my $index = 0; my $curr_victim = (); for($index = 0; $index <= $#$wrk_line_array_ref; $index++) { my $did_print = 0; my $look_forward = 0; my $look_backward = 0; my $continue = 0; $curr_victim = $$wrk_line_array_ref[$index]; $look_backward = 1 if ($index > 0); $look_forward = 1 if ($index < $#$wrk_line_array_ref); if ($continue == 0 && $look_backward) { $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq "->"); $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq "who-has" && $$wrk_line_array_ref[$index + 1] eq "tell"); $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq "tell" && $$wrk_line_array_ref[$index - 3] eq "who-has"); $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq "reply" && $$wrk_line_array_ref[$index + 1] eq "is-at"); } if ($continue == 0 && $look_forward) { $continue = 1 if ($$wrk_line_array_ref[$index + 1] eq "->"); } if ($did_print == 0) { if ( $continue && ($curr_victim =~ /^$num_ip_addr_re(:$num_port_re)?/)) { print " "; my $addr = (); my $port = (); if (index($curr_victim, ":") >= 0) { ($addr, $port) = split(/:/, $curr_victim); } else { $addr = $curr_victim; } if ( $$wrk_line_array_ref[$index-1] eq "->" || $$wrk_line_array_ref[$index-1] eq "who-has" ) { &colorize(\@dst_ip_color_set); } else { &colorize(\@src_ip_color_set); } print "$addr"; &colorize(\@default_color_set); if (defined($port)) { if ( $$wrk_line_array_ref[$index-1] eq "->" || $$wrk_line_array_ref[$index-1] eq "who-has" ) { print ":"; &colorize(\@dst_port_color_set); print "$port"; } else { print ":"; &colorize(\@src_port_color_set); print "$port"; } } &colorize(\@default_color_set); $did_print = 1; $continue = 0; } } if ($did_print == 0) { if ($curr_victim =~ /$mac_addr_re/) { print " "; &colorize(\@mac_addr_color_set); print "$curr_victim"; &colorize(\@default_color_set); $did_print = 1; } } if ($did_print == 0) { if ( ($curr_victim eq "ARP") || ($curr_victim eq "ICMP") || ($curr_victim eq "TCP" && ($$wrk_line_array_ref[$index + 1] ne "Options")) || ($curr_victim eq "UDP") ) { if ( ($$wrk_line_array_ref[0] ne "ICMP") && ($$wrk_line_array_ref[0] ne "TCP") && ($$wrk_line_array_ref[0] ne "UDP") ) { print " "; } &colorize(\@keyword_color_set); print "$curr_victim"; &colorize(\@default_color_set); $did_print = 1; } } if ($did_print == 0) { if ($curr_victim =~ /$mac_addr_re/) { print " "; &colorize(\@mac_addr_color_set); print "$curr_victim"; &colorize(\@default_color_set); $did_print = 1; } } if (!$did_print) { print " $curr_victim"; } else { $did_print = 0; } } print "\n"; } # tcpdump functions sub new_hex () { my $wrk_line = $_[0]; my $preamble = (); my $lhs_hex_chunk = (); my $rhs_hex_chunk = (); my @lhs_hex_array = (); my @rhs_hex_array = (); my $padding = (); my $index = (); my $wl_re = (); my $l_ele = (); my $r_ele = (); # really should be 2 or 4 not 2,4 $wl_re = '^(0x[A-Fa-f\d]{4}\s{1,3})((([A-Fa-f\d]{2,4}\s){1,7})?([A-Fa-f\d]{2,4}))(\s{1,45})(.{1,16})'; if ($wrk_line =~ /$wl_re/) { $preamble = $1; $lhs_hex_chunk = $2; $rhs_hex_chunk = $7; } $lhs_hex_chunk =~ s/([a-f\d])([a-f\d])([a-f\d])([a-f\d]) ?/$1$2 $3$4 /g; @lhs_hex_array = split(/\ /, $lhs_hex_chunk); @rhs_hex_array = split(/ */, $rhs_hex_chunk); $padding = length($wrk_line) - ((($#lhs_hex_array + 1) * 2) + ((($#lhs_hex_array + 1) / 2) - 1) + ($#rhs_hex_array + 1)); print "$preamble"; $index = 0; foreach $l_ele (@lhs_hex_array) { if ( uc($l_ele) ge "20" && uc($l_ele) le "7E") { &colorize(\@hex_p_color_set); print "$l_ele"; &colorize(\@default_color_set); } else { &colorize(\@hex_np_color_set); print "$l_ele"; $rhs_hex_array[$index] = "\0"; } if ($index < $#lhs_hex_array && (($index + 1) % 2 == 0)) { print " "; } $index++; } print " " x $padding; foreach $r_ele (@rhs_hex_array) { if ( $r_ele ge " " && $r_ele le "~") { &colorize(\@hex_p_color_set); print "$r_ele"; &colorize(\@default_color_set); } else { &colorize(\@hex_np_color_set); print "."; } } &colorize(\@default_color_set); print "\n"; } sub old_hex () { my $wrk_line = $_[0]; # these really should be globals set by cmd line args my $sub_dot = 1; chomp($wrk_line); print("\t\t\t "); my @hex_blob = split("\ ", $wrk_line); my $space = 1; foreach my $ele (@hex_blob) { my @data_bytes = unpack ("C2",pack("H4", $ele)); foreach my $byte (@data_bytes) { if ($sub_dot) { if (($byte > 31) && ($byte < 127)){ &colorize(\@hex_p_color_set); print chr($byte); &colorize(\@default_color_set); } else { # note that '.' is == to 2e in hex, so if you # see a '.' with a 2e below it really is '.' &colorize(\@hex_np_color_set); print "."; &colorize(\@default_color_set); } } else { print chr($byte); } print " "; if ($space == 2) { $space = 0; print " "; } $space++; } } print "\n$wrk_line\n"; } sub smb_hex () { my $wrk_line = $_[0]; my $preamble = (); my $lhs_hex_chunk = (); my $rhs_hex_chunk = (); my @lhs_hex_array = (); my @rhs_hex_array = (); my $padding = (); my $index = (); my $wl_re = (); my $l_ele = (); my $r_ele = (); $wl_re = '^(\[[\dA-Fa-f]+\]\s)((([A-Fa-f\d]{2}\s{1,2}){1,15})?([A-Fa-f\d]{2}))(\s{1,48})(.{1,8}(\s.{1,8})?)'; if ($wrk_line =~ /$wl_re/) { $preamble = $1; $lhs_hex_chunk = $2; $rhs_hex_chunk = $7; $padding = $6; } $lhs_hex_chunk =~ s/ / /; @lhs_hex_array = split(/\ /, $lhs_hex_chunk); @rhs_hex_array = split(/ */, $rhs_hex_chunk); print "$preamble"; $index = 0; foreach $l_ele (@lhs_hex_array) { if ( uc($l_ele) ge "20" && uc($l_ele) le "7E") { &colorize(\@hex_p_color_set); print "$l_ele"; &colorize(\@default_color_set); } else { &colorize(\@hex_np_color_set); print "$l_ele"; $rhs_hex_array[$index] = "\0"; } if ($index < $#lhs_hex_array) { print " "; if (($index + 1) % 8 == 0) { print " "; } } $index++; } print $padding; $index = 0; foreach $r_ele (@rhs_hex_array) { if ( $r_ele ge " " && $r_ele le "~") { &colorize(\@hex_p_color_set); print "$r_ele"; &colorize(\@default_color_set); } else { &colorize(\@hex_np_color_set); print "."; } print " " if ($index == 7); $index++; } &colorize(\@default_color_set); print "\n"; } sub time_info_line() { my $wrk_line = $_[0]; my @wrk_line_array = (); my $time = (); @wrk_line_array = split("\ ", $wrk_line); $time = shift(@wrk_line_array); &colorize(\@time_color_set); print "$time"; &colorize(\@default_color_set); &process_rest_of_line(\@wrk_line_array); } sub addr_info_line() { my $wrk_line = $_[0]; my @wrk_line_array = (); my $addr = (); my $colon_found = (); @wrk_line_array = split("\ ", $wrk_line); $addr = shift(@wrk_line_array); &colorize(\@src_ip_color_set); print "$addr"; &colorize(\@default_color_set); &process_rest_of_line(\@wrk_line_array); } sub addr_port_info_line() { my $wrk_line = $_[0]; my @wrk_line_array = (); my $addr_port = (); my $addr = (); my $port = (); my $colon_found = (); @wrk_line_array = split("\ ", $wrk_line); $addr_port = shift(@wrk_line_array); ($addr, $port) = &proc_addr_port(\$addr_port); if (!defined($addr) && !defined($port)) { return (0); } &colorize(\@src_ip_color_set); print "$addr"; &colorize(\@default_color_set); print "."; &colorize(\@src_port_color_set); print "$port"; &colorize(\@default_color_set); &process_rest_of_line(\@wrk_line_array); return(1); } sub arp_info_line() { my $wrk_line = $_[0]; my @wrk_line_array = (); my $first_arp_ele = (); @wrk_line_array = split("\ ", $wrk_line); $first_arp_ele = shift(@wrk_line_array); print "$first_arp_ele"; &process_rest_of_line(\@wrk_line_array); } sub mac_info_line() { my $wrk_line = $_[0]; my @wrk_line_array = (); my $mac_addr = (); @wrk_line_array = split("\ ", $wrk_line); $mac_addr = shift(@wrk_line_array); &colorize(\@mac_addr_color_set); print "$mac_addr"; &colorize(\@default_color_set); &process_rest_of_line(\@wrk_line_array); } sub proc_addr_port() { my $addr_port_ref = $_[0]; my @addr_port_rev = (); my $lport = (); my $laddr = (); @addr_port_rev = split(/\./, reverse($$addr_port_ref)); $lport = reverse(shift (@addr_port_rev)); $laddr = reverse(join('.', @addr_port_rev)); if ($lport =~ /[A-Za-z_-]+/) { if ( ! defined(getservbyname("$lport", "tcp")) && ! defined(getservbyname("$lport", "udp")) ) { $lport = (); $laddr = (); } } return ($laddr, $lport); } sub process_rest_of_line() { my $wrk_line_array_ref = $_[0]; my $index = 0; my $curr_victim = (); for($index = 0; $index <= $#$wrk_line_array_ref; $index++) { my $did_print = 0; my $look_forward = 0; my $look_backward = 0; my $continue = 0; $curr_victim = $$wrk_line_array_ref[$index]; # addrs w/ ports $look_backward = 1 if ($index > 0); $look_forward = 1 if ($index < $#$wrk_line_array_ref); if ($continue == 0 && $look_backward) { $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq ">"); $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq "who-has" && $$wrk_line_array_ref[$index + 1] eq "tell"); $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq "tell" && $$wrk_line_array_ref[$index - 3] eq "who-has"); $continue = 1 if ($$wrk_line_array_ref[$index - 1] eq "reply" && $$wrk_line_array_ref[$index + 1] eq "is-at"); } if ($continue == 0 && $look_forward) { $continue = 1 if ($$wrk_line_array_ref[$index + 1] eq ">"); } if ($did_print == 0) { if ( $continue && ( ($curr_victim =~ /$num_ip_addr_re\.($num_port_re|$alphnum_port_re):?$/) || ($curr_victim =~ /$fqdn_re\.($num_port_re|$alphnum_port_re):?$/) || ($curr_victim =~ /$hostname_re\.($num_port_re|$alphnum_port_re):?$/) ) ) { my $colon_found = (); my $addr = (); my $port = (); ($curr_victim, $colon_found) = &was_there_colon($curr_victim); ($addr, $port) = &proc_addr_port(\$curr_victim); if (defined($addr) && defined($port)) { if ($$wrk_line_array_ref[$index-1] eq ">") { &colorize(\@dst_ip_color_set); print " $addr"; &colorize(\@default_color_set); print "."; &colorize(\@dst_port_color_set); print "$port"; } else { &colorize(\@src_ip_color_set); print " $addr"; &colorize(\@default_color_set); print "."; &colorize(\@src_port_color_set); print "$port"; } &colorize(\@default_color_set); if ($colon_found) { print ":"; $colon_found = 0; } $did_print = 1; $continue = 0; } } } # addrs w/o ports if ($did_print == 0) { if ( $continue && ( ($curr_victim =~ /^$num_ip_addr_re:?$/) || ($curr_victim =~ /^$fqdn_re:?$/) || ($curr_victim =~ /$hostname_re:?$/) ) ) { my $colon_found = (); ($curr_victim, $colon_found) = &was_there_colon($curr_victim); if ( $$wrk_line_array_ref[$index-1] eq ">" || $$wrk_line_array_ref[$index-1] eq "who-has" ) { &colorize(\@dst_ip_color_set); } else { &colorize(\@src_ip_color_set); } print " $curr_victim"; &colorize(\@default_color_set); if ($colon_found) { print ":"; $colon_found = 0; } $did_print = 1; $continue = 0; } } # mac addrs if ($did_print == 0) { if ($curr_victim =~ /$mac_addr_re/) { print " "; &colorize(\@mac_addr_color_set); print "$curr_victim"; &colorize(\@default_color_set); $did_print = 1; } } if (! $did_print) { print " $curr_victim"; } else { $did_print = 0; } } print "\n"; } sub was_there_colon() { my $dotted_tuple = $_[0]; if ($dotted_tuple =~ /.*:$/) { chop($dotted_tuple); return ($dotted_tuple, 1); } else { return ($dotted_tuple, 0); } } # support functions sub sig_exit_cleanup_handler() { $SIG{INT} = \&sig_exit_cleanup_handler; $SIG{QUIT} = \&sig_exit_cleanup_handler; &reset_ansi(); if ($using_snifoutfh) { close(SNIFOUTFH); } exit; } sub sig_stop_cleanup_handler() { $SIG{STOP} = \&sig_stop_cleanup_handler; &reset_ansi; } sub multi_chomp () { my $temp_line = $_[0]; $temp_line =~ s/$eol$//; return $temp_line; } sub colorize() { my $color_set_ref = $_[0]; my $setInt = $$color_set_ref[0]; my $setFg = $$color_set_ref[1]; my $setBg = $$color_set_ref[2]; if (! $opt_Nocolor) { printf ("%s%d;%d;%dm", $escape, $intensity{$setInt}, $foreground{$setFg}, $background{$setBg}); } } sub reset_ansi() { print $escape . $reset; } __END__ =head1 NAME snifob - sniffer output beautifier =head1 SYNOPSIS snifob [OPTION] =head1 DESCRIPTION snifob colorizes snort and tcpdump output to make the output easier to read. It will also de-hexify tcpdump -x output. --help show help output --nocolor do not colorize output --nodecode do not de-hexify tcpdump -x output --run run "$sniffer" with options "$sniffer_options" and markup stdout (doesn't dump packet payload) --drun run "$sniffer_dump" with options "$sniffer_options_dump" and markup stdout (dumps packet payload) The user can change the execution of snifob by setting the following variables inside the section marked: ## begin user configurable $sniffer - sets the sniffer that the --run option uses $sniffer_options - sets the options for the sniffer used by --run # the following should include an option or options to dump # the packet payload $sniffer_dump - sets the sniffer that the --drun option uses $sniffer_options _dump - sets the options for the sniffer used by --drun @default_color_set - the default color set that is used when snifob isn't highlighting output There are other color sets available for configuration in this section as well. the syntax for a color set is: @default_color_set = (, , ); the supported intensities are: bright dark the supported background and foreground colors are: black red green yellow blue magenta cyan white To use snort with snifob, you need to patch snort with one of the following diffs and compile. If the setlinebuf(3) function isn't supported on your system you can apply the second diff included below. These diffs were made against snort 1.6.3. *** snort.c.dist Wed Dec 27 02:11:21 2000 --- snort.c Mon Dec 25 06:40:11 2000 *************** *** 405,410 **** --- 405,411 ---- "\n \"unsock\" enables UNIX socket logging (experimental)."); puts(" -a Display ARP packets"); puts(" -b Log packets in tcpdump format (much faster!)"); + puts(" -B Make stdout buffered"); puts(" -c Use Rules File "); puts(" -C Print out payloads with character data only (no hex)"); puts(" -d Dump the Application Layer"); *************** *** 479,485 **** pv.promisc_flag = 1; /* loop through each command line var and process it */ ! while ((ch = getopt(argc, argv, "Og:u:t:CqS:pNA:F:DM:br:xeh:l:dc:n:P:i:vV?aso6")) != -1) { #ifdef DEBUG printf("Processing cmd line switch: %c\n", ch); --- 480,486 ---- pv.promisc_flag = 1; /* loop through each command line var and process it */ ! while ((ch = getopt(argc, argv, "OBg:u:t:CqS:pNA:F:DM:br:xeh:l:dc:n:P:i:vV?aso6")) != -1) { #ifdef DEBUG printf("Processing cmd line switch: %c\n", ch); *************** *** 515,520 **** --- 516,525 ---- case 'C': pv.char_data_flag = 1; break; + + case 'B': + setlinebuf(stdout); + break; case 'D': /* daemon mode */ #ifdef DEBUG *** snort.c.dist Wed Dec 27 02:11:21 2000 --- snort.c Wed Dec 27 02:19:30 2000 *************** *** 405,410 **** --- 405,411 ---- "\n \"unsock\" enables UNIX socket logging (experimental)."); puts(" -a Display ARP packets"); puts(" -b Log packets in tcpdump format (much faster!)"); + puts(" -B Make stdout buffered"); puts(" -c Use Rules File "); puts(" -C Print out payloads with character data only (no hex)"); puts(" -d Dump the Application Layer"); *************** *** 479,485 **** pv.promisc_flag = 1; /* loop through each command line var and process it */ ! while ((ch = getopt(argc, argv, "Og:u:t:CqS:pNA:F:DM:br:xeh:l:dc:n:P:i:vV?aso6")) != -1) { #ifdef DEBUG printf("Processing cmd line switch: %c\n", ch); --- 480,486 ---- pv.promisc_flag = 1; /* loop through each command line var and process it */ ! while ((ch = getopt(argc, argv, "OBg:u:t:CqS:pNA:F:DM:br:xeh:l:dc:n:P:i:vV?aso6")) != -1) { #ifdef DEBUG printf("Processing cmd line switch: %c\n", ch); *************** *** 515,520 **** --- 516,525 ---- case 'C': pv.char_data_flag = 1; break; + + case 'B': + setvbuf(stdout, NULL, _IOLBF, 0); + break; case 'D': /* daemon mode */ #ifdef DEBUG =head1 AUTHOR snifob was written by Holt Sorenson =head1 BUGS I don't know of any today; email me with problems so that I can fix them... =head1 SEE ALSO snort(8), tcpdump(1), perl(1p) http://www.snort.org http://www.tcpdump.org A word about Snort -- I don't mean to imply that Snort is just a sniffer, per say. It has the ability to display information about packets near real time from the command line. However, Snort is a [free] "lightweight network intrusion detection system, capable of performing real-time traffic analysis and packet logging on IP networks. It can perform protocol analysis, content searching/matching and can be used to detect a variety of attacks and probes, such as buffer overflows, stealth port scans, CGI attacks, SMB probes, OS fingerprinting attempts, and much more." If you're interested in using Snort, go to the URL above, it comes with many recommendations. If you're developing in perl, I highly recommend using the Devel-ptkdb module authored by Andrew E. Page You can acquire it at: http://www.cpan.org/modules/by-category/03_Development_Support/Devel/ =head1 ACKNOWLEDGEMENTS gnash for the idea, amholder for the query "why are you using tcpdump? snort has better payload display.", dR. drewenstein for harrassing me about the multiple possibilities of tcpdump output that I wasn't accounting for, and especially to family for putting up with the hands that are seemingly welded to computers. =head1 COPYRIGHT Copyright 2000, Holt Sorenson , All Rights Reserved. This program is licensed under the provisions of the Artistic license as enumerated at: http://www.nosneros.net/hso/programs/licenses/artistic-license.html There are a couple additional quid pro quos: -By downloading or otherwise acquiring snifob you agree to the terms of the license and these quid pro quos. -Any legal or arbitration issues are settled in the current physical locale of the author. -The author retains the right to change the license snifob is made available under. If the author does change the license, the change will apply to that version, and versions later released under the same license. The author commits to keeping the license liberal and available to use for netizens. This is not a requirement, but if snifob is helpful and you use it often, I would like to here from you. If you use it outside of your personal life, I'd like to know where you use it. I ask this out of curiousity, not to track usage for compensation, or some other strange reason. The most current version of snifob can be found at: http://www.nosneros.net/hso/programs/snifob/