$number." .
" | $starttime | " .
"$id_html | | \n";
#
# --- Save Raw Sessions to Disk ---
#
if ($Arg{output_raw}) {
#
# Save ".raw" file, all raw 2-way data time-sorted.
#
$filename = "session_${numtext}.${service_name}.raw";
open (OUT,">$filename") ||
die "ERROR12: creating $filename $!\n";
binmode(OUT); # for backward OSs
print OUT $rawboth;
close OUT;
### Update HTML index table with link
$Index{HTML}[$number] .= "raw ";
#
# Save ".raw1" file, server->client 1-way data assembled.
#
$filename = "session_${numtext}.${service_name}.raw1";
open (OUT,">$filename") ||
die "ERROR13: creating $filename $!\n";
binmode(OUT); # for backward OSs
print OUT &TCP_Follow_RawA($session_id);
close OUT;
### Update HTML index table with link
$Index{HTML}[$number] .= "raw1 ";
#
# Save ".raw2" file, client->server 1-way data assembled.
#
$filename = "session_${numtext}.${service_name}.raw2";
open (OUT,">$filename") ||
die "ERROR14: creating $filename $!\n";
binmode(OUT); # for backward OSs
print OUT &TCP_Follow_RawB($session_id);
close OUT;
### Update HTML index table with link
$Index{HTML}[$number] .= "raw2 ";
}
next unless $Arg{output_apps};
#
# --- Save Session as HTML ---
#
if ($Arg{Save_As_TCP_HTML}{$service} || $Arg{output_allhtml}) {
&Save_Both_HTML("TCP",$session_id,$number,$service_name,
$id_html);
}
#
# --- Save X11 Session as HTML ---
#
if ($Arg{Save_As_X11_HTML}{$service}) {
#
# HTML Postprocessing can go here
#
&Generate_X11_HTML($session_id);
&Process_BothHTML("TCP",$session_id,1);
&Save_Both_HTML("TCP",$session_id,$number,"text$service_name",
$id_html);
}
#
# --- Save Hex Dump as HTML ---
#
if ($Arg{output_hex}) {
&Process_Hex_Finish("TCP",$session_id);
&Save_Hex_HTML("TCP",$session_id,$number,$service_name,
$id_html);
&Save_Hex_Text("TCP",$session_id,$number,$service_name,
$id_text);
}
#
# --- Process Application Data ---
#
if ($service == 20) {
&Save_FTP_File($session_id,$number);
}
if ($service == 22) {
&Save_Session_textSSH_files($session_id,$number,
"SSH",$id_html);
}
if ($Arg{keydata} && $Arg{Save_As_TCP_Playback}{$service}) {
# The following is for special analysis,
&Save_Session_Keydata($session_id,$number,
$service_name,$id_html);
}
if ($service == 25) {
&Save_SMTP_Emails($session_id,$number);
}
if ($service == 80 or $service == 8080 or
$service == 3127 or $service == 1080) {
&Save_HTTP_Files($session_id,$number,$service_name);
&Process_HTTP($session_id,$number);
}
if ($Arg{Save_As_X11_Playback}{$service}) {
&Save_Session_XReplay($session_id,$number,$service_name);
}
if ($Arg{Save_As_VNC_Playback}{$service}) {
&Save_Session_VNCReplay_andHTML($session_id,$number,
$service_name,$id_html);
}
$raw = &TCP_Follow_RawB($session_id);
if ($raw =~ /^\200\0\0p0\211/) {
&Save_NFS_File($session_id,$number);
}
if ($Arg{Save_As_TCP_Playback}{$service}) {
&Save_Session_Replay($session_id,$number,$service_name);
}
}
$Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
$Bench{$BM}{text} = "Process TCP Sessions - end";
}
# Process_UDP_Streams - this subroutine processes %UDP, saving the
# sessions to various "session*" files on disk. It populates %Index
# with information on the files that were created. It also checks
# the application port numbers and triggers further processing -
# eg DNS html output files.
#
sub Process_UDP_Streams {
my ($filename,$id_html,$id_text,$time,$rawboth);
$Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
$Bench{$BM}{text} = "Process UDP Sessions - start";
#
# Loop through all UDP Streams
#
foreach $session_id (keys %{$UDP{id}}) {
$number = $Index{Sort_Lookup}{"UDP:$session_id"};
#
# Determine the service - usually by the lowest numbered port, eg,
# ports 51327 and 53 would give 53 (dns). (big assumption!)
#
$ip_src = $UDP{id}{$session_id}{src};
$ip_dest = $UDP{id}{$session_id}{dest};
$udp_src_port = $UDP{id}{$session_id}{src_port};
$udp_dest_port = $UDP{id}{$session_id}{dest_port};
($service,$client) = &Pick_Service_Port("UDP",$session_id,
$udp_src_port,$udp_dest_port);
### Fetch text name for this port
$service_name = $Services_UDP{$service} || $service || "0";
#
# Don't actually save any files if CLI args say not to
#
if ($Arg{port_reject} && $Arg{Port_Rejected}{$service}) { next; }
if ($Arg{port_accept} && !$Arg{Port_Accepted}{$service}) { next; }
if ($Arg{ip_reject}) {
if ($Arg{IP_Rejected}{$ip_src} || $Arg{IP_Rejected}{$ip_dest}) {
next;
}
}
if ($Arg{ip_accept}) {
unless ($Arg{IP_Accepted}{$ip_src} ||
$Arg{IP_Accepted}{$ip_dest}) {
next;
}
}
#
# --- Fetch RawBoth ---
#
# rawboth will contain the raw data in time order.
$rawboth = "";
foreach $time (sort {$a <=> $b}
(keys (%{$UDP{id}{$session_id}{time}}))) {
$rawboth .= $UDP{id}{$session_id}{time}{$time};
}
$length = length($rawboth);
#
# --- Check for Min and Max Size ---
#
next if $length < $Arg{minbytes};
next if (($Arg{maxbytes} != 0) && ($length > $Arg{maxbytes}));
### Print status line
$numtext = sprintf("%04d",$number);
printf "%6s %-45s %s\n",$numtext,$session_id,$service_name
unless $Arg{quiet};
#
# --- Save Info File to Disk ---
#
if ($Arg{output_info}) {
$filename = "stream_${numtext}.info";
$firsttime = localtime($UDP{id}{$session_id}{StartTime});
$lasttime = localtime($UDP{id}{$session_id}{EndTime});
$duration = ($UDP{id}{$session_id}{EndTime} -
$UDP{id}{$session_id}{StartTime});
$duration = sprintf("%.0f",$duration);
if ($UDP{id}{$session_id}{Partial}) { $partial = "yes"; }
else { $partial = "no"; }
### Build output text
$outtext = "$numtext===$session_id===$service===" .
"$service_name===$length\n\n" .
"Source addr : $ip_src\n" .
"Source port : $udp_src_port\n" .
"Dest addr : $ip_dest\n" .
"Dest port : $udp_dest_port\n" .
"Dest service: $service_name\n" .
"Length bytes: $length\n" .
"First time : $firsttime\n" .
"Last time : $lasttime\n" .
"Duration : $duration seconds\n" .
"Partial : $partial\n";
### Write info file
open (OUT,">$filename") ||
die "ERROR15: creating $filename $!\n";
print OUT $outtext;
close OUT;
}
#
# --- Save Index data in Memory ---
#
### Fetch Times
$starttime = scalar localtime($UDP{id}{$session_id}{StartTime});
$duration = ($UDP{id}{$session_id}{EndTime} -
$UDP{id}{$session_id}{StartTime});
$duration = sprintf("%.0f",$duration);
### Construct HTML table row containing stream data
if ($Arg{prefer_dns}) {
$ip_src = &Get_Name_For_IP($ip_src);
$ip_dest = &Get_Name_For_IP($ip_dest);
}
$id_html = "$ip_src:$udp_src_port <-> $ip_dest:$udp_dest_port";
$Index{HTML}[$number] = " |
$number. | " .
"$starttime | $duration s | " .
"$id_html " .
" | " .
"$service_name | " .
"$length bytes | \n";
### Construct text line containing session data
$id_text = "$ip_src:$udp_src_port <-> $ip_dest:$udp_dest_port";
$Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",$number,
$id_text,"($service_name)",$length);
#
# --- Save Raw Stream to Disk ---
#
if ($Arg{output_raw}) {
#
# Save ".raw" file, all raw 2-way data time-sorted.
#
$filename = "stream_${numtext}.${service_name}.raw";
open (OUT,">$filename") ||
die "ERROR16: creating $filename $!\n";
binmode(OUT); # for backward OSs
print OUT $rawboth;
close OUT;
### Update HTML index table with link
$Index{HTML}[$number] .= "raw ";
#
# Save ".raw1" file, server->client 1-way data time-sorted.
#
$filename = "stream_${numtext}.${service_name}.raw1";
open (OUT,">$filename") ||
die "ERROR17: creating $filename $!\n";
binmode(OUT); # for backward OSs
print OUT $UDP{id}{$session_id}{RawA};
close OUT;
### Update HTML index table with link
$Index{HTML}[$number] .= "raw1 ";
#
# Save ".raw2" file, client->server 1-way data time-sorted.
#
$filename = "stream_${numtext}.${service_name}.raw2";
open (OUT,">$filename") ||
die "ERROR18: creating $filename $!\n";
binmode(OUT); # for backward OSs
print OUT $UDP{id}{$session_id}{RawB};
close OUT;
### Update HTML index table with link
$Index{HTML}[$number] .= "raw2 ";
}
next unless $Arg{output_apps};
#
# --- Save Stream as HTML ---
#
if ($Arg{Save_As_UDP_HTML}{$service} || $Arg{output_allhtml}) {
#
# HTML Postprocessing can go here
#
&Process_BothHTML("UDP",$session_id);
&Save_Both_HTML("UDP",$session_id,$number,$service_name);
}
#
# --- Save Hex Dump as HTML ---
#
if ($Arg{output_hex}) {
&Process_Hex_Finish("UDP",$session_id);
&Save_Hex_HTML("UDP",$session_id,$number,$service_name,
$id_html);
&Save_Hex_Text("UDP",$session_id,$number,$service_name,
$id_text);
}
#
# --- Process Application Data ---
#
if ($Arg{Save_As_UDP_Playback}{$service}) {
&Save_Stream_Replay($session_id,$number,$service_name);
}
if ($service == 53) {
&Save_DNS_File($session_id,$number);
}
}
$Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
$Bench{$BM}{text} = "Process UDP Sessions - end";
}
# Process_ICMP - this subroutine processes %ICMP.
#
sub Process_ICMP {
my ($filename,$id_text,$id_html);
$Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
$Bench{$BM}{text} = "Process ICMP Sessions - start";
#
# Loop through all ICMP Streams
#
foreach $time (keys %{$ICMP{time}}) {
$number = $Index{Sort_Lookup}{"ICMP:$time"};
### Fetch Data
$icmp_type = $ICMP{time}{$time}{type};
$icmp_code = $ICMP{time}{$time}{code};
$icmp_ver = $ICMP{time}{$time}{ver};
$ip_src = $ICMP{time}{$time}{src};
$ip_dest = $ICMP{time}{$time}{dest};
$session_id = "$ip_src,$ip_dest";
### Fetch text name for this port
$type_name = $ICMP_Types{$icmp_type} || $icmp_type || "0";
$service_name = $icmp_type;
#
# Don't actually save any files if CLI args say not to
#
if ($Arg{ip_reject}) {
if ($Arg{IP_Rejected}{$ip_src} || $Arg{IP_Rejected}{$ip_dest}){
next;
}
}
if ($Arg{ip_accept}) {
unless ($Arg{IP_Accepted}{$ip_src} ||
$Arg{IP_Accepted}{$ip_dest}) {
next;
}
}
#
# --- Check for Min and Max Size ---
#
$length = length($ICMP{time}{$time}{data});
next if $length < $Arg{minbytes};
next if (($Arg{maxbytes} != 0) && ($length > $Arg{maxbytes}));
### Print status line
$numtext = sprintf("%04d",$number);
printf "%6s %-45s ICMP %s\n",$numtext,$session_id,$type_name
unless $Arg{quiet};
#
# --- Save Info File to Disk ---
#
if (($Arg{output_info}) && ($length > 0)) {
$filename = "icmp_${numtext}.${service_name}.info";
if ($ICMP{time}{$time}{Partial}) { $partial = "yes"; }
else { $partial = "no"; }
$starttime = scalar localtime($time);
### Build output text
$outtext = "$numtext===$session_id===$icmp_type===" .
"$type_name===$length\n\n" .
"Source addr : $ip_src\n" .
"Dest addr : $ip_dest\n" .
"ICMP version: $icmp_ver\n" .
"ICMP type : $icmp_type\n" .
"ICMP code : $icmp_code\n" .
"ICMP name : $type_name\n" .
"Length bytes: $length\n" .
"Time : $starttime\n" .
"Partial : $partial\n";
### Write info file
open (OUT,">$filename") ||
die "ERROR19: creating $filename $!\n";
print OUT $outtext;
close OUT;
}
#
# --- Save Index data in Memory ---
#
### Fetch Times
$starttime = scalar localtime($time);
### Construct HTML table row containing stream data
$id_html = "$ip_src -> $ip_dest";
$Index{HTML}[$number] = " |
$number. | " .
"$starttime | 0 s | " .
"$id_html" .
" | " .
"$icmp_ver | " .
"$length bytes | $type_name\n";
### Construct text line containing session data
$id_text = "$ip_src -> $ip_dest";
$Index{Text}[$number] .= sprintf("%-4s %-45s %-10s %8s bytes\n",$number,
$id_text, "($icmp_ver $type_name)",$length);
#
# --- Save Raw Stream to Disk ---
#
if (($Arg{output_raw}) && ($length > 0)) {
#
# Save ".raw" file, all raw 2-way data time-sorted.
#
$filename = "icmp_${numtext}.${service_name}.raw";
open (OUT,">$filename") ||
die "ERROR20: creating $filename $!\n";
binmode(OUT); # for backward OSs
print OUT $ICMP{time}{$time}{data};
close OUT;
### Update HTML index table with link
$Index{HTML}[$number] .= "raw ";
}
#
# --- Save Stream as HTML ---
#
if ($Arg{output_allhtml}) {
#
# HTML Postprocessing can go here
#
&Process_BothHTML("ICMP",$time);
&Save_Both_HTML("ICMP",$time,$number,$service_name,$id_html);
}
#
# --- Save Hex Dump as HTML ---
#
if ($Arg{output_hex}) {
&Process_Hex_Finish("ICMP",$time);
&Save_Hex_HTML("ICMP",$time,$number,$service_name,$id_html);
&Save_Hex_Text("ICMP",$time,$number,$service_name,$id_text);
}
}
$Bench{++$BM}{mark} = new Benchmark if $Arg{bench};
$Bench{$BM}{text} = "Process ICMP Sessions - end";
}
# JL: Process_DNS - DNS processing. Look for DNS replies and store
# names for IP addresses into %DNS.
# Also store CNAME aliases so that the "original" name can be retrieved.
#
sub Process_DNS {
my $data = shift;
my $session_id = shift;
my $dns = Net::DNS::Packet->new(\$data);
unless ($dns) {
#print "Failed to create Net::DNS::Packet!\n";
return;
}
$UDP{id}{$session_id}{DNS} = $dns->string;
foreach my $rr ($dns->answer) {
if ($rr->type eq "A") {
$DNS{$rr->address} = $rr->name;
}
if ($rr->type eq "CNAME") {
$DNS{$rr->cname} = $rr->name;
}
}
}
# Process_HTTP - HTTP processing. Looks for GETs and POSTs, and process them
# into %GETPOST. Constructs a HTTP log in %HTTPlog.
# JL: Added host parameter
#
sub Process_HTTP {
my ($junk,$var,$value,$term,$data,$request,$host,$site,$post,$get,$reply);
my ($start,$src,$num,$req,$recv,$type,$status,$time1,$duration,$dest);
my @Terms;
my $index = 0;
my $indexA = 0;
my $indexB = 0;
### Input
my $session_id = shift;
my $number = shift;
my $partnum = 0;
$src = $TCP{id}{$session_id}{src};
$dest = $TCP{id}{$session_id}{dest};
#
# Process
#
### Get packet times (may need to use seqs instead)
@Times = sort{$a <=> $b} (keys(%{$TCP{id}{$session_id}{time}}));
### Step through each packet
for ($i=0; $i <= $#Times; $i++) {
### Fetch data from mem
$time = $Times[$i];
$request = $TCP{id}{$session_id}{time}{$time}{data};
$request =~ s/^\0\0*//;
#
# --- Do HTTPlog Processing ---
#
next unless $request =~ /^(GET|POST)\s/; # speed
### Calc duration
$time1 = $Times[$i+1] || $time;
$duration = $time1 - $time;
# some magic
$reply = "";
foreach $inc (1..16) {
$next = $TCP{id}{$session_id}{time}{$Times[$i+$inc]}{data};
$next =~ s/^\0\0*//;
if ($next =~ /^U*\0*HTTP/) {
$reply = $next;
$time1 = $Times[$i+$inc] || $time;
$duration = $time1 - $time;
last;
} else {
$request .= $next;
}
}
$i++; # speed
$partnum++;
if ($request =~ /^GET \S* HTTP/) {
### JL: Get the host string, referer, and cookies.
($host) = $request =~ /\sHost:\s(\S*)\s/is;
($referer) = $request =~ /\sReferer:\s(\S*)/is;
($cookie) = $request =~ /\sCookie:\s(\S*)/is;
($setcookie) = $reply =~ /\sSet-Cookie:\s(\S*)/is;
### Get the site string
($site) = $request =~ /^GET (\S*)\s/;
if ($site =~ m:^/:) {
# assume this was a http, missing the "http://host"
# JL: Prefer hostname over IP address
if ($Arg{httplog_html}) {
$site = "http://${host}$site";
} else {
$site = "http://${dest}$site";
}
}
### Get the status and mime type from reply
($status) = $reply =~ /HTTP\/\S*\s(\S*)/s;
# JL: Be careful to use case insensitive matching
($type) = $reply =~ /Content-Type:\s(\S*)/is;
($size) = $reply =~ /Content-Length:\s(\S*)/is;
$type = "-" if $type eq "";
$size = 0 if $size eq "";
$result = $Result_Names{$status} || "TCP_HIT";
### Store the log entry
$HTTPlog{time}{$time} =
Print_Log_Line($number,$time,$duration,
$src,$dest,$result,$status,$size,
"GET",$site,"-","NONE","","-",$type);
$HTTPtxtlog{time}{$time} =
Print_TxtLog_Line($number,$time,
$referer,$cookie,$setcookie,
"GET",$site);
$HTTPlog{notempty} = 1;
### JL: External image data.
if ( defined $ExtImage{HTML}[$number]{parts}[$partnum] ) {
$ExtImage{HTML}[$number]{links} .= " ";
}
} elsif ($request =~ /^POST .* HTTP/) {
### Get the site string
($site) = $request =~ /^POST (\S*)\s/;
if ($site =~ m:^/:) {
# assume this was a http, missing the "http://host"
$site = "http://${dest}$site";
}
### JL: Get the host string, referer, and cookies.
($host) = $request =~ /\sHost:\s(\S*)\s/is;
($referer) = $request =~ /\sReferer:\s(\S*)/is;
($cookie) = $request =~ /\sCookie:\s(\S*)/is;
($setcookie) = $reply =~ /\sSet-Cookie:\s(\S*)/is;
### Get the status and mime type
($status) = $reply =~ /HTTP\/\S*\s(\S*)/s;
($type) = $reply =~ /Content-Type:\s(\S*)/is;
($size) = $reply =~ /Content-Length:\s(\S*)/is;
$type = "-" if $type eq "";
$size = length($TCP{id}{$session_id}) if $size eq "";
$result = $Result_Names{$status} || "TCP_HIT";
### Store the log entry
$HTTPlog{time}{$time} =
Print_Log_Line($number,$time,$duration,
$src,$dest,$result,$status,$size,
"POST",$site,"-","NONE","","-",$type);
$HTTPtxtlog{time}{$time} =
Print_TxtLog_Line($number,$time,
$referer,$cookie,$setcookie,
"POST",$site);
$HTTPlog{notempty} = 1;
}
#
# --- Do GETPOST Processing ---
#
# JL: chaosreader 0.94 includes only URIs containing a question
# mark. Why? Go for all instead.
#if ($request =~ /^GET \S*\?\S* HTTP/) {
if ($request =~ /^GET \S* HTTP/) {
### Get the GET string
($site,$get) = $request =~ /^GET (\S*)\?(\S*)\s/;
if ($site eq "") {
($site) = $request =~ /^GET (\S*)\s/;
}
# check it looks like a GET,
# JL: Why only those with parameters?
#if ($get =~ /=/) {
#
# Populate %GETPOST with a table containing the GET data
#
if (! defined $GETPOST{HTML}[$number]{query}) {
$GETPOST{HTML}[$number]{info} .=
"GET | ";
$GETPOST{notempty} = 1;
} else {
$GETPOST{HTML}[$number]{query} .= " \n";
}
#
# Generate table of query key value pairs
#
$GETPOST{HTML}[$number]{query} .= "$site
\n";
@Terms = split(/&/,$get);
foreach $term (@Terms) {
($var,$value) = split(/=/,$term);
$value =~ tr/+/ /;
$value =~ s/%([a-f0-9][a-f0-9])/pack("C",hex($1))/egi;
$value =~ s/</g;
$value =~ s/>/>/g;
$value =~ s/\n/ \n/g;
$GETPOST{HTML}[$number]{query} .=
"$var | " .
"$value | \n";
}
$GETPOST{HTML}[$number]{query} .= " \n";
#}
} elsif ($request =~ /^POST .* HTTP/) {
### Get the POST strings
($junk,$post,$junk1) = split(/\n\n|\r\n\r\n/,$request);
# check it looks like a POST
if ($post =~ /=/) {
#
# Populate %GETPOST with a table containing the POST data
#
if (! defined $GETPOST{HTML}[$number]{query}) {
$GETPOST{HTML}[$number]{info} .=
"POST | ";
$GETPOST{notempty} = 1;
} else {
$GETPOST{HTML}[$number]{query} .= " \n";
}
($site) = $request =~ /^POST (\S*)\s/;
$post =~ s/HTTP .*//s;
#
# Generate table of query key value pairs
#
$GETPOST{HTML}[$number]{query} .= "$site
\n";
@Terms = split(/&/,$post);
foreach $term (@Terms) {
($var,$value) = split(/=/,$term);
$value =~ tr/+/ /;
$value =~
s/%([a-fA-F0-9][a-fA-F0-9])/pack("C", hex($1))/eg;
$value =~ s/</g;
$value =~ s/>/>/g;
$value =~ s/\n/ /g;
$GETPOST{HTML}[$number]{query} .=
"$var | " .
"$value | \n";
}
$GETPOST{HTML}[$number]{query} .= " \n";
}
}
}
}
# Sort_Index - this creates a sort order for the master index.html, based
# on the sort argument (defaults to sort by time).
#
sub Sort_Index {
if ($Arg{sort} eq "size") {
&Sort_Index_By_Size();
} elsif ($Arg{sort} eq "type") {
&Sort_Index_By_Type();
} elsif ($Arg{sort} eq "ip") {
&Sort_Index_By_IP();
} else {
&Sort_Index_By_Time();
}
}
# Sort_Index_By_Time - this calculates an appropriate order for the index
# files based on session start time.
#
sub Sort_Index_By_Time {
my ($session_id,$time,$number);
#
# Determine Session and Stream time order
#
foreach $session_id (keys %{$TCP{id}}) {
$Index{Time_Order}{"TCP:$session_id"} =
$TCP{id}{$session_id}{StartTime};
}
foreach $session_id (keys %{$UDP{id}}) {
$Index{Time_Order}{"UDP:$session_id"} =
$UDP{id}{$session_id}{StartTime};
}
foreach $time (keys %{$ICMP{time}}) {
$Index{Time_Order}{"ICMP:$time"} = $time;
}
$number = 0;
foreach $session (sort {$Index{Time_Order}{$a} <=>
$Index{Time_Order}{$b}} keys %{$Index{Time_Order}}) {
$number++;
$Index{Sort_Lookup}{$session} = $number;
}
}
# Sort_Index_By_Size - this calculates an appropriate order for the index
# files based on session size.
#
sub Sort_Index_By_Size {
my ($session_id,$time,$number);
#
# Determine Session and Stream size order
#
foreach $session_id (keys %{$TCP{id}}) {
$Index{Size_Order}{"TCP:$session_id"} =
$TCP{id}{$session_id}{size};
}
foreach $session_id (keys %{$UDP{id}}) {
$Index{Size_Order}{"UDP:$session_id"} =
$UDP{id}{$session_id}{size};
}
foreach $time (keys %{$ICMP{time}}) {
$Index{Size_Order}{"ICMP:$time"} =
$ICMP{time}{$time}{size};
}
$number = 0;
foreach $session (sort {$Index{Size_Order}{$b} <=>
$Index{Size_Order}{$a}} keys %{$Index{Size_Order}}) {
$number++;
$Index{Sort_Lookup}{$session} = $number;
}
}
# Sort_Index_By_Type - this calculates an appropriate order for the index
# files based on session type, followed by time.
#
sub Sort_Index_By_Type {
my ($service,$tcp_src_port,$tcp_dest_port,$client,$udp_src_port,
$udp_dest_port,$session_id,$time,$number);
#
# Determine Session and Stream time order
#
foreach $session_id (keys %{$TCP{id}}) {
# Determine the service - usually by the lowest numbered port
$tcp_src_port = $TCP{id}{$session_id}{src_port};
$tcp_dest_port = $TCP{id}{$session_id}{dest_port};
($service,$client) = &Pick_Service_Port("TCP",$session_id,
$tcp_src_port,$tcp_dest_port);
$Index{Type_Order}{"TCP:$session_id"}{1} = 1;
$Index{Type_Order}{"TCP:$session_id"}{2} = $service;
$Index{Type_Order}{"TCP:$session_id"}{3} =
$TCP{id}{$session_id}{StartTime};
}
foreach $session_id (keys %{$UDP{id}}) {
# Determine the service - usually by the lowest numbered port
$udp_src_port = $UDP{id}{$session_id}{src_port};
$udp_dest_port = $UDP{id}{$session_id}{dest_port};
($service,$client) = &Pick_Service_Port("UDP",$session_id,
$udp_src_port,$udp_dest_port);
$Index{Type_Order}{"UDP:$session_id"}{1} = 2;
$Index{Type_Order}{"UDP:$session_id"}{2} = $service;
$Index{Type_Order}{"UDP:$session_id"}{3} =
$UDP{id}{$session_id}{StartTime};
}
foreach $time (keys %{$ICMP{time}}) {
$Index{Type_Order}{"ICMP:$time"}{1} = 3;
$Index{Type_Order}{"ICMP:$time"}{2} = 0;
$Index{Type_Order}{"ICMP:$time"}{3} = $time;
}
# now we sort by TCP->UDP->IP then port then time.
$number = 0;
foreach $session (sort {
$Index{Type_Order}{$a}{1} <=> $Index{Type_Order}{$b}{1} ||
$Index{Type_Order}{$a}{2} <=> $Index{Type_Order}{$b}{2} ||
$Index{Type_Order}{$a}{3} <=> $Index{Type_Order}{$b}{3}
} keys %{$Index{Type_Order}}) {
$number++;
$Index{Sort_Lookup}{$session} = $number;
}
}
# Sort_Index_By_IP - this calculates an appropriate order for the index
# files based on client IP, followed by time.
#
sub Sort_Index_By_IP {
my ($service,$ip,$ip_dest,$ip_src,$client,
$session_id,$time,$number,$text,$html,$rest);
my @IP;
#
# Determine Session and Stream time order
#
foreach $session_id (keys %{$TCP{id}}) {
# Determine source IP
# here we use the same subroutine as the index.html
# so that they match up.
($text,$html) = &Generate_TCP_IDs($session_id);
($ip,$rest) = split(/:/,$text,2);
# Split on IPv4 or IPv6
$IP = ();
if ($ip =~ /\./) { @IP = split(/\./,$ip); }
else { $IP[0] = $ip; }
$Index{Type_Order}{"TCP:$session_id"}{1} = $IP[0];
$Index{Type_Order}{"TCP:$session_id"}{2} = $IP[1];
$Index{Type_Order}{"TCP:$session_id"}{3} = $IP[2];
$Index{Type_Order}{"TCP:$session_id"}{4} = $IP[3];
$Index{Type_Order}{"TCP:$session_id"}{5} =
$TCP{id}{$session_id}{StartTime};
}
foreach $session_id (keys %{$UDP{id}}) {
# Determine source IP
$ip = $UDP{id}{$session_id}{src};
# Split on IPv4 or IPv6
$IP = ();
if ($ip =~ /\./) { @IP = split(/\./,$ip); }
else { $IP[0] = $ip; }
$Index{Type_Order}{"UDP:$session_id"}{1} = $IP[0];
$Index{Type_Order}{"UDP:$session_id"}{2} = $IP[1];
$Index{Type_Order}{"UDP:$session_id"}{3} = $IP[2];
$Index{Type_Order}{"UDP:$session_id"}{4} = $IP[3];
$Index{Type_Order}{"UDP:$session_id"}{5} =
$UDP{id}{$session_id}{StartTime};
}
foreach $time (keys %{$ICMP{time}}) {
# Determine source IP
$ip = $ICMP{time}{$time}{src};
# Split on IPv4 or IPv6
$IP = ();
if ($ip =~ /\./) { @IP = split(/\./,$ip); }
else { $IP[0] = $ip; }
$Index{Type_Order}{"ICMP:$time"}{1} = $IP[0];
$Index{Type_Order}{"ICMP:$time"}{2} = $IP[1];
$Index{Type_Order}{"ICMP:$time"}{3} = $IP[2];
$Index{Type_Order}{"ICMP:$time"}{4} = $IP[3];
$Index{Type_Order}{"ICMP:$time"}{5} = $time;
}
# now we sort by IP then time
$number = 0;
foreach $session (sort {
$Index{Type_Order}{$a}{1} <=> $Index{Type_Order}{$b}{1} ||
$Index{Type_Order}{$a}{2} <=> $Index{Type_Order}{$b}{2} ||
$Index{Type_Order}{$a}{3} <=> $Index{Type_Order}{$b}{3} ||
$Index{Type_Order}{$a}{4} <=> $Index{Type_Order}{$b}{4} ||
$Index{Type_Order}{$a}{1} cmp $Index{Type_Order}{$b}{1} ||
$Index{Type_Order}{$a}{5} <=> $Index{Type_Order}{$b}{5}
} keys %{$Index{Type_Order}}) {
$number++;
$Index{Sort_Lookup}{$session} = $number;
}
}
# Print_Welcome - print short program welcome message.
#
sub Print_Welcome {
unless ($Arg{quiet}) {
print "Chaosreader ver 0.95g\n\n";
}
}
# Print_Header1 - print program welcome message.
#
sub Print_Header1 {
unless ($Arg{quiet}) {
print "Reading $TYPE log...\n";
printf "%6s %-45s %s\n","Packet",
"Session (host:port <=> host:port)","Length";
}
}
# Print_Header2 - print header before loading the file
#
sub Print_Header2 {
print "\nCreating files...\n" unless $Arg{quiet};
printf "%6s %-45s %s\n","Num","Session (host:port <=> host:port)",
"Service" unless $Arg{quiet};
}
# Print_Footer1 - print footer at end of program.
#
sub Print_Footer1 {
if ($Arg{output_index}) {
print "\nindex.html created.\n" unless $Arg{quiet};
}
}
# Chdir - change directory with error
#
sub Chdir {
my $dir = shift;
#
# This can be invoked with $Arg{output_dir}, so $dir won't
# always be defined - which is okay.
#
if (defined $dir) {
chdir "$dir" ||
die "ERROR21: Can't cd to $dir: $!\n";
}
}
# Create_Index_Files - Create the HTML and text index files. This reads
# %Index and creates the files on disk.
#
sub Create_Index_Files {
my ($html_index,$html_line,$html_links,$image_empty,$getpost_empty);
$getpost_empty = $image_empty = "";
if ($Arg{output_index}) {
######################
# --- index.html ---
$image_empty = "(Empty) " unless $Image{notempty};
$getpost_empty = "(Empty) " unless $GETPOST{notempty};
$httplog_empty = "(Empty) " unless $HTTPlog{notempty};
#
# Create HTML Index file containing all reports
#
open(FILE,">index.html") || die "ERROR22: creating index: $!\n";
print FILE <
Chaosreader Report, $Arg{infile}
Chaosreader Report
File: $Arg{infile}, Type: $TYPE, Created at: $the_date
Image Report
$image_empty - Click here for a report on captured images.
External Image Report
$image_empty - Click here for a report embedding external images.
GET/POST Report
$getpost_empty - Click here for a report on HTTP GETs and POSTs.
HTTP Proxy Log
$httplog_empty - Click here for a generated proxy style HTTP log.
New HTTP Proxy Log
$httplog_empty - Click here for HTTP log with referers and Cookie indicators.
TCP/UDP/... Sessions
END_HTML
for ($html_index=0; $html_index <= $#{$Index{HTML}}; $html_index++) {
$html_line = $Index{HTML}[$html_index];
next unless defined $html_line;
print FILE "$html_line \n";
}
print FILE <
IP Count
END_HTML
foreach $IP (sort {$Count{IP}{$b} <=> $Count{IP}{$a}}
keys %{$Count{IP}}) {
print FILE "$IP | $Count{IP}{$IP} | \n";
}
print FILE <
TCP Port Count
END_HTML
foreach $port (sort {$Count{TCPport}{$b} <=> $Count{TCPport}{$a}}
keys %{$Count{TCPport}}) {
$port_text = $Services_TCP{$port} || $port || "0";
print FILE "$port_text | $Count{TCPport}{$port}" .
" | \n";
}
print FILE <
UDP Port Count
END_HTML
foreach $port (sort {$Count{UDPport}{$b} <=> $Count{UDPport}{$a}}
keys %{$Count{UDPport}}) {
$port_text = $Services_UDP{$port} || $port || "0";
print FILE "$port_text | $Count{UDPport}{$port}" .
" | \n";
}
print FILE <
IP Protocol Count
END_HTML
foreach $protocol (sort {$Count{IPprotocol}{$b} <=>
$Count{IPprotocol}{$a}} keys %{$Count{IPprotocol}}) {
$protocol_text = $IP_Protocols{$protocol};
print FILE "$protocol_text | " .
"$Count{IPprotocol}{$protocol} | \n";
}
print FILE <
Ethernet Type Count
END_HTML
foreach $type (sort {$Count{EtherType}{$b} <=> $Count{EtherType}{$a}}
keys %{$Count{EtherType}}) {
print FILE "$type | $Count{EtherType}{$type}" .
" | \n";
}
print FILE <
|