#!/usr/bin/perl # A Misuse and Anomaly NIDS for TCP traffic # # Coded by James Fell # james@kaleton.com #################################################################### # Variable declarations ############################################# # IMPORTANT - User must set these values appropriately my $internal = "0.0.0.0"; #IP address of box being protected my $interface = "eth0"; #Network interface to capture packets from my $mailer = "/usr/sbin/sendmail -t"; #Path to sendmail my $tcpdump = "/tcpdump-3.6.2/tcpdump"; #Path to TcpDump my $admin="you\@your-domain.com"; #Email address of sysadmin my $lambda=0.5; #Decay constant for anomaly detection ############################################# my $i; # Temp variable used for for loops etc my $curr_line; # Used to store each line of data from the sniffer my @curr_packet; # Array to store entire packet read from sniffer and split by spaces my @curr_sig; # Array to store each sig as it is read from file my @temp; # Temporary array with various uses my $num_sigs; # Stores number of attack signatures found in database my $e=2.71828; # Value of constant e for use by anomaly detection engine # Arrays to store sniffer output in my @source_ip; # Source IP address of packet my @destination_ip; # Destination IP address my @time; # Timestamp my @tcp_source_port; # Source port my @tcp_dest_port; # Destination port my @tcp_syn; # SYN flag my @tcp_ack; # ACK flag my @tcp_rst; # RST flag my @tcp_fin; # FIN flag my @tcp_urg; # URG flag my @tcp_psh; # PSH flag my @tcp_data; # Data portion # Arrays to store attack sigs in my @sig_source_ip; # Source IP address of attack packet my @sig_source_port; # Source port my @sig_dest_ip; # Destination IP address my @sig_dest_port; # Destination port my @sig_msg; # Short natural language description of attack my @sig_flags; # TCP flags (SARFUP) my @sig_data; # String contained in the data # Counters for statistical model (reset every 100 packets) my @count_in_tcp_source_port; # Incoming packet source ports my @count_in_tcp_dest_port; # Destination ports my $count_in_syn=0; # SYN flag my $count_in_ack=0; # ACK flag my $count_in_rst=0; # RST flag my $count_in_fin=0; # FIN flag my $count_in_psh=0; # PSH flag my $count_in_urg=0; # URG flag my @count_out_tcp_source_port; # Outgoing packet source ports my @count_out_tcp_dest_port; # Destination ports my $count_out_syn=0; # SYN flag my $count_out_ack=0; # ACK flag my $count_out_rst=0; # RST flag my $count_out_fin=0; # FIN flag my $count_out_psh=0; # PSH flag my $count_out_urg=0; # URG flag # Statistical model # Incoming traffic my @average_in_tcp_source_port; # Average for each source port my @sd_in_tcp_source_port; # Standard deviation for each source port my @average_in_tcp_dest_port; # Average for each destination port my @sd_in_tcp_dest_port; # Standard deviation for each destination port my $average_in_syn; # Average for incoming SYN packets my $sd_in_syn; # Standard deviation for incoming SYN packets my $average_in_ack; # Average for incoming ACK packets my $sd_in_ack; # Standard deviation for incoming ACK packets my $average_in_fin; # Average for incoming FIN packets my $sd_in_fin; # Standard deviation for incoming FIN packets my $average_in_rst; # Average for incoming RST packets my $sd_in_rst; # Standard deviation for incoming RST packets my $average_in_urg; # Average for incoming URG packets my $sd_in_urg; # Standard deviation for incoming URG packets my $average_in_psh; # Average for incoming PSH packets my $sd_in_psh; # Standard deviation for incoming PSH packets # Outgoing traffic my @average_out_tcp_source_port;# Average for each source port my @sd_tcp_out_source_port; # Standard deviation for each source port my @average_in_tcp_dest_port; # Average for each destination port my @sd_in_tcp_dest_port; # Standard deviation for each destination port my $average_out_syn; # Average for SYN packets my $sd_out_syn; # Standard deviation for SYN packets my $average_out_ack; # Average for ACK packets my $sd_out_ack; # Standard deviation for ACK packets my $average_out_fin; # Average for FIN packets my $sd_out_fin; # Standard deviation for FIN packets my $average_out_rst; # Average for RST packets my $sd_out_rst; # Standard deviation for RST packets my $average_out_urg; # Average for URG packets my $sd_out_urg; # Standard deviation for URG packets my $average_out_psh; # Average for PSH packets my $sd_out_psh; # Standard deviation for PSH packets ########################################################################### #Email the sysadmin when malicious behaviour is detected sub email { # Start sendmail open (MAIL,"|$mailer"); # Write the email header print MAIL "To: $admin\n"; print MAIL "From: ids\@kaleton.com\n"; print MAIL "Subject: Alert From NIDS\n"; # If called by misuse detection engine if ($_[0]==0) { print MAIL "From Misuse Detection Engine\n\n"; print MAIL "Attacker's IP: $_[1]\n"; print MAIL "Type of attack: $_[2]\n"; # Else if called by anomaly detection engine } else { print MAIL "From Anomaly Detection Engine\n\n"; print MAIL $_[1]; } close (MAIL); } # Function to perform misuse detection on a single packet sub misuse { # Current position in 100 packet array is passed in as argument my $packet_num = $_[0]; #for each signature in the database for ($sig=0;$sig<$num_sigs-1;$sig++) { #if the source ip in the sig matches the source ip in the packet if ((($sig_source_ip[$sig] eq "EXTERNAL") && ($source_ip[$packet_num] ne $internal)) || (($sig_source_ip[$sig] eq "INTERNAL") && ($source_ip[$packet_num] eq $internal))) { #if the dest ip in the sig matches the dest ip in the packet if ((($sig_dest_ip[$sig] eq "EXTERNAL") && ($destination_ip[$packet_num] ne $internal)) || (($sig_dest_ip[$sig] eq "INTERNAL") && ($destination_ip[$packet_num] eq $internal))) { #if sig source port is "any" or matches packet source port if (($sig_source_port[$sig]==$tcp_source_port[$packet_num]) || ($sig_source_port[$sig] eq "any")) { #if sig dest port is "any" or matches packet dest port if (($sig_dest_port[$sig]==$tcp_dest_port[$packet_num]) || ($sig_dest_port[$sig] eq "any")) { #if flag is not set in sig or flag is set in both the sig and the packet if ((($tcp_syn[$packet_num]==1)&&($sig_flags[$sig]=~/S/)) || !($sig_flags[$sig]=~/S/) || ($sig_flags[$sig] eq "NULL")) { if ((($tcp_ack[$packet_num]==1)&&($sig_flags[$sig]=~/A/)) || !($sig_flags[$sig]=~/A/) || ($sig_flags[$sig] eq "NULL")) { if ((($tcp_rst[$packet_num]==1)&&($sig_flags[$sig]=~/R/)) || !($sig_flags[$sig]=~/R/) || ($sig_flags[$sig] eq "NULL")) { if ((($tcp_fin[$packet_num]==1)&&($sig_flags[$sig]=~/F/)) || !($sig_flags[$sig]=~/F/) || ($sig_flags[$sig] eq "NULL")) { if ((($tcp_urg[$packet_num]==1)&&($sig_flags[$sig]=~/U/)) || !($sig_flags[$sig]=~/U/) || ($sig_flags[$sig] eq "NULL")) { if ((($tcp_psh[$packet_num]==1)&&($sig_flags[$sig]=~/P/)) || !($sig_flags[$sig]=~/P/) || ($sig_flags[$sig] eq "NULL")) { #if data in sig is contained in packet data if (($tcp_data[$packet_num] =~ /$sig_data[$sig]/) || ($sig_data[$sig] eq "NULL")) { # If the packet was incoming if ($sig_source_ip[$sig] eq "EXTERNAL") { # Send an email alert email(0,$source_ip[$packet_num],$sig_msg[$sig]); # Else if the packet was outgoing } else { # Send an email alert email(0,$destination_ip[$packet_num],$sig_msg[$sig]); } } } } } } } } } } } } } } # Function to perform anomaly detection on a set of 100 packets sub anomaly { # Current position in the packet array is passed in as argument my $packet_num=$_[0]; # Update all the counters # If the packet is outgoing if ($source_ip[$packet_num] eq $internal) { $count_out_tcp_source_port[$tcp_source_port[$packet_num]]++; $count_out_tcp_dest_port[$tcp_dest_port[$packet_num]]++; if ($tcp_syn[$packet_num]==1) {$count_out_syn++;} if ($tcp_ack[$packet_num]==1) {$count_out_ack++;} if ($tcp_fin[$packet_num]==1) {$count_out_fin++;} if ($tcp_urg[$packet_num]==1) {$count_out_urg++;} if ($tcp_psh[$packet_num]==1) {$count_out_psh++;} if ($tcp_rst[$packet_num]==1) {$count_out_rst++;} # Else if the packet is incoming } else { $count_in_tcp_source_port[$tcp_source_port[$packet_num]]++; $count_in_tcp_dest_port[$tcp_dest_port[$packet_num]]++; if ($tcp_syn[$packet_num]==1) {$count_in_syn++;} if ($tcp_ack[$packet_num]==1) {$count_in_ack++;} if ($tcp_fin[$packet_num]==1) {$count_in_fin++;} if ($tcp_urg[$packet_num]==1) {$count_in_urg++;} if ($tcp_psh[$packet_num]==1) {$count_in_psh++;} if ($tcp_rst[$packet_num]==1) {$count_in_rst++;} } #If we're at the end of the packet buffer, check for anomaly and update model if ($packet_num==99) { # Initialies discovered anomalies to empty string $anomalies=""; # Calculate how many seconds have elapsed for the last 100 packets # Split timestamp on last and first packets into hour minute second @time_last=split(/:/, $time[99]); @time_first=split(/:/, $time[0]); # Convert timestamp for last and first packets into number of seconds since midnight $time_last_secs=($time_last[0]*3600)+($time_last[1]*60)+($time_last[2]); $time_first_secs=($time_first[0]*3600)+($time_first[1]*60)+($time_first[2]); # Calculate number of seconds elapsed from first packet to last packet if ($time_last_secs>$time_first_secs) { $time_elapsed=$time_last_secs-$time_first_secs; } else { $time_elapsed=(24*60*60)+($time_last_secs-$time_first_secs); } # Calculate distribution of external IP addresses for last 100 packets $ext_counter=0; $ext_already_seen=0; # For all 100 packets for ($counter=0;$counter<100;$counter++) { # If packet was outgoing if ($source_ip[$counter] eq $internal) { for ($i=0; $i<$ext_counter;$i++) { if ($externals[$i] eq $destination_ip[$counter]) { $ext_count[$i]++; $ext_already_seen=1; } } if ($ext_already_seen==0) { $externals[$ext_counter]=$destination_ip[$counter]; $ext_count[$ext_counter]=1; $ext_counter++; } $ext_already_seen=0; # Else if packet was incoming } else { for ($i=0;$i<$ext_counter;$i++) { if ($externals[$i] eq $source_ip[$counter]) { $ext_count[$i]++; $ext_already_seen=1; } } if ($ext_already_seen==0) { $externals[$ext_counter]=$source_ip[$counter]; $ext_count[$ext_counter]=1; $ext_counter++; } $ext_already_seen=0 } } # If this is the first time we called anomaly() if ($first_time==1) { # Set original averages and standard deviations for ($i=0;$i<65000;$i++) { $average_in_tcp_source_port[$i]=$count_in_tcp_source_port[$i]; $average_in_tcp_dest_port[$i]=$count_in_tcp_dest_port[$i]; $average_out_tcp_source_port[$i]=$count_out_tcp_source_port[$i]; $average_out_tcp_dest_port[$i]=$count_out_tcp_dest_port[$i]; } $average_in_syn=$count_in_syn; $average_in_ack=$count_in_ack; $average_in_fin=$count_in_fin; $average_in_rst=$count_in_rst; $average_in_psh=$count_in_psh; $average_in_urg=$count_in_urg; $average_out_syn=$count_out_syn; $average_out_ack=$count_out_ack; $average_out_fin=$count_out_fin; $average_out_rst=$count_out_rst; $average_out_psh=$count_out_psh; $average_out_urg=$count_out_urg; $average_time=$time_elapsed; # Set all standard deviations to zero for ($i=0;$i<65000;$i++) { $sd_in_tcp_source_port[$i]=0; $sd_in_tcp_dest_port[$i]=0; $sd_out_tcp_source_port[$i]=0; $sd_out_tcp_dest_port[$i]=0; } $sd_in_urg=0; $sd_in_syn=0; $sd_in_ack=0; $sd_in_psh=0; $sd_in_rst=0; $sd_in_fin=0; $sd_out_urg=0; $sd_out_syn=0; $sd_out_ack=0; $sd_out_psh=0; $sd_out_rst=0; $sd_out_fin=0; $sd_time=0; #Reset counters for ($i=0;$i<65000;$i++) { $count_in_tcp_source_port[$i]=0; $count_in_tcp_dest_port[$i]=0; $count_out_tcp_source_port[$i]=0; $count_out_tcp_dest_port[$i]=0; } $count_in_syn=0; $count_in_ack=0; $count_in_fin=0; $count_in_urg=0; $count_in_psh=0; $count_in_rst=0; $count_out_syn=0; $count_out_ack=0; $count_out_fin=0; $count_out_urg=0; $count_out_psh=0; $count_out_rst=0; $first_time=0; $second_time=1; # Else if this is the second time we called anomaly() } elsif ($second_time==1) { for ($i=0;$i<65000;$i++) { $average_in_tcp_source_port[$i] = ((($average_in_tcp_source_port[$i]*($e**-$lambda)) + $count_in_tcp_source_port[$i]) / (($e**-$lambda)+1) ); $sd_in_tcp_source_port[$i] = ($average_in_tcp_source_port[$i]-$count_in_tcp_source_port[$i]); if ($sd_in_tcp_source_port[$i]<0) { $sd_in_tcp_source_port[$i]=-$sd_in_tcp_source_port[$i]; } $count_in_tcp_source_port[$i]=0; $average_in_tcp_dest_port[$i] = ((($average_in_tcp_dest_port[$i]*($e**-$lambda)) + $count_in_tcp_dest_port[$i]) / (($e**-$lambda)+1) ); $sd_in_tcp_dest_port[$i] = ($average_in_tcp_dest_port[$i]-$count_in_tcp_dest_port[$i]); if ($sd_in_tcp_dest_port[$i]<0) { $sd_in_tcp_dest_port[$i]=-$sd_in_tcp_dest_port[$i]; } $count_in_tcp_dest_port[$i]=0; $average_out_tcp_source_port[$i] = ((($average_out_tcp_source_port[$i]*($e**-$lambda)) + $count_out_tcp_source_port[$i]) / (($e**-$lambda)+1) ); $sd_out_tcp_source_port[$i] = ($average_out_tcp_source_port[$i]-$count_out_tcp_source_port[$i]); if ($sd_out_tcp_source_port[$i]<0) { $sd_out_tcp_source_port[$i]=-$sd_out_tcp_source_port[$i]; } $count_out_tcp_source_port[$i]=0; $average_out_tcp_dest_port[$i] = ((($average_out_tcp_dest_port[$i]*($e**-$lambda)) + $count_out_tcp_dest_port[$i]) / (($e**-$lambda)+1) ); $sd_out_tcp_dest_port[$i] = ($average_out_tcp_dest_port[$i]-$count_out_tcp_dest_port[$i]); if ($sd_out_tcp_dest_port[$i]<0) { $sd_out_tcp_dest_port[$i]=-$sd_out_tcp_dest_port[$i]; } $count_out_tcp_dest_port[$i]=0; } $average_in_syn=( (($average_in_syn*($e**-$lambda)) +$count_in_syn) / (1+($e**-$lambda)) ); $sd_in_syn=($average_in_syn-$count_in_syn); if ($sd_in_syn<0) { $sd_in_syn=-$sd_in_syn; } $count_in_syn=0; $average_out_syn=( (($average_out_syn*($e**-$lambda)) +$count_out_syn) / (1+($e**-$lambda)) ); $sd_out_syn=($average_out_syn-$count_out_syn); if ($sd_out_syn<0) { $sd_out_syn=-$sd_out_syn; } $count_out_syn=0; $average_in_ack=( (($average_in_ack*($e**-$lambda)) +$count_in_ack) / (1+($e**-$lambda)) ); $sd_in_ack=($average_in_ack-$count_in_ack); if ($sd_in_ack<0) { $sd_in_ack=-$sd_in_ack; } $count_in_ack=0; $average_out_ack=( (($average_out_ack*($e**-$lambda)) +$count_out_ack) / (1+($e**-$lambda)) ); $sd_out_ack=($average_out_ack-$count_out_ack); if ($sd_out_ack<0) { $sd_out_ack=-$sd_out_ack; } $count_out_ack=0; $average_in_fin=( (($average_in_fin*($e**-$lambda)) +$count_in_fin) / (1+($e**-$lambda)) ); $sd_in_syn=($average_in_fin-$count_in_fin); if ($sd_in_fin<0) { $sd_in_fin=-$sd_in_fin; } $count_in_fin=0; $average_out_fin=( (($average_out_fin*($e**-$lambda)) +$count_out_fin) / (1+($e**-$lambda)) ); $sd_out_syn=($average_out_fin-$count_out_fin); if ($sd_out_fin<0) { $sd_out_fin=-$sd_out_fin; } $count_out_fin=0; $average_in_urg=( (($average_in_urg*($e**-$lambda)) +$count_in_urg) / (1+($e**-$lambda)) ); $sd_in_urg=($average_in_urg-$count_in_urg); if ($sd_in_urg<0) { $sd_in_urg=-$sd_in_urg; } $count_in_urg=0; $average_out_urg=( (($average_out_urg*($e**-$lambda)) +$count_out_urg) / (1+($e**-$lambda)) ); $sd_out_urg=($average_out_urg-$count_out_urg); if ($sd_out_urg<0) { $sd_out_urg=-$sd_out_urg; } $count_out_urg=0; $average_in_psh=( (($average_in_psh*($e**-$lambda)) +$count_in_psh) / (1+($e**-$lambda)) ); $sd_in_psh=($average_in_psh-$count_in_psh); if ($sd_in_psh<0) { $sd_in_psh=-$sd_in_psh; } $count_in_psh=0; $average_out_psh=( (($average_out_psh*($e**-$lambda)) +$count_out_psh) / (1+($e**-$lambda)) ); $sd_out_psh=($average_out_psh-$count_out_psh); if ($sd_out_psh<0) { $sd_out_psh=-$sd_out_psh; } $count_out_psh=0; $average_in_rst=( (($average_in_rst*($e**-$lambda)) +$count_in_rst) / (1+($e**-$lambda)) ); $sd_in_rst=($average_in_rst-$count_in_rst); if ($sd_in_rst<0) { $sd_in_rst=-$sd_in_rst; } $count_in_rst=0; $average_out_rst=( (($average_out_rst*($e**-$lambda)) +$count_out_rst) / (1+($e**-$lambda)) ); $sd_out_rst=($average_out_rst-$count_out_rst); if ($sd_out_rst<0) { $sd_out_rst=-$sd_out_rst; } $count_out_rst=0; $average_time=( (($average_time*($e**-$lambda)) + $time_elapsed) / (1+($e**-$lambda)) ); $sd_time=$average_time-$time_elapsed; if ($sd_time<0) { $sd_time= -$sd_time; } $second_time=0; # Else this is the third or later time we called anomaly() } else { # Check for anomalies in last 100 packets for ($i=0;$i<65000;$i++) { if (($count_in_tcp_source_port[$i] > ($average_in_tcp_source_port[$i] + (2*$sd_in_tcp_source_port[$i]))) || ($count_in_tcp_source_port[$i] < ($average_in_tcp_source_port[$i] - (2*$sd_in_tcp_source_port[$i])))) { # Anomaly $anomalies=$anomalies."For Incoming Packets From Source Port $i, Average is $average_in_tcp_source_port[$i], Standard Deviation is $sd_in_tcp_source_port[$i], and Counted is $count_in_tcp_source_port[$i]\n\n"; } if (($count_in_tcp_dest_port[$i] > ($average_in_tcp_dest_port[$i] + (2*$sd_in_tcp_dest_port[$i]))) || ($count_in_tcp_dest_port[$i] < ($average_in_tcp_dest_port[$i] - (2*$sd_in_tcp_dest_port[$i])))) { # Anomaly $anomalies=$anomalies."For Incoming Packets To Destination Port $i, Average is $average_in_tcp_dest_port[$i], Standard Deviation is $sd_in_tcp_dest_port[$i], and Counted is $count_in_tcp_dest_port[$i]\n\n"; } if (($count_out_tcp_source_port[$i] > ($average_out_tcp_source_port[$i] + (2*$sd_out_tcp_source_port[$i]))) || ($count_out_tcp_source_port[$i] < ($average_out_tcp_source_port[$i] - (2*$sd_out_tcp_source_port[$i])))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets From Source Port $i, Average is $average_out_tcp_source_port[$i], Standard Deviation is $sd_out_tcp_source_port[$i], and Counted is $count_out_tcp_source_port[$i]\n\n"; } if (($count_out_tcp_dest_port[$i] > ($average_out_tcp_dest_port[$i] + (2*$sd_out_tcp_dest_port[$i]))) || ($count_out_tcp_dest_port[$i] < ($average_out_tcp_dest_port[$i] - (2*$sd_out_tcp_dest_port[$i])))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets To Destination Port $i, Average is $average_out_tcp_dest_port[$i], Standard Deviation is $sd_out_tcp_dest_port[$i], and Counted is $count_out_tcp_dest_port[$i]\n\n"; } } if (($count_in_syn > ($average_in_syn + (2*$sd_in_syn))) || ($count_in_syn < ($average_in_syn - (2*$sd_in_syn)))) { # Anomaly $anomalies=$anomalies."For Incoming Packets With SYN Flag Set, Average is $average_in_syn, Standard Deviation is $sd_in_syn, and Counted is $count_in_syn\n\n"; } if (($count_out_syn > ($average_out_syn + (2*$sd_out_syn))) || ($count_out_syn < ($average_out_syn - (2*$sd_out_syn)))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets With SYN Flag Set, Average is $average_out_syn, Standard Deviation is $sd_out_syn, and Counted is $count_out_syn\n\n"; } if (($count_in_ack > ($average_in_ack + (2*$sd_in_ack))) || ($count_in_ack < ($average_in_ack - (2*$sd_in_ack)))) { # Anomaly $anomalies=$anomalies."For Incoming Packets With ACK Flag Set, Average is $average_in_ack, Standard Deviation is $sd_in_ack, and Counted is $count_in_ack\n\n"; } if (($count_out_ack > ($average_out_ack + (2*$sd_out_ack))) || ($count_out_ack < ($average_out_ack - (2*$sd_out_ack)))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets With ACK Flag Set, Average is $average_out_ack, Standard Deviation is $sd_out_ack, and Counted is $count_out_ack\n\n"; } if (($count_in_rst > ($average_in_rst + (2*$sd_in_rst))) || ($count_in_rst < ($average_in_rst - (2*$sd_in_rst)))) { # Anomaly $anomalies=$anomalies."For Incoming Packets With RST Flag Set, Average is $average_in_rst, Standard Deviation is $sd_in_rst, and Counted is $count_in_rst\n\n"; } if (($count_out_rst > ($average_out_rst + (2*$sd_out_rst))) || ($count_out_rst < ($average_out_rst - (2*$sd_out_rst)))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets With RST Flag Set, Average is $average_out_rst, Standard Deviation is $sd_out_rst, and Counted is $count_out_rst\n\n"; } if (($count_in_psh > ($average_in_psh + (2*$sd_in_psh))) || ($count_in_psh < ($average_in_psh - (2*$sd_in_psh)))) { # Anomaly $anomalies=$anomalies."For Incoming Packets With PSH Flag Set, Average is $average_in_psh, Standard Deviation is $sd_in_psh, and Counted is $count_in_psh\n\n"; } if (($count_out_psh > ($average_out_psh + (2*$sd_out_psh))) || ($count_out_psh < ($average_out_psh - (2*$sd_out_psh)))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets With PSH Flag Set, Average is $average_out_psh, Standard Deviation is $sd_out_psh, and Counted is $count_out_psh\n\n"; } if (($count_in_urg > ($average_in_urg + (2*$sd_in_urg))) || ($count_in_urg < ($average_in_urg - (2*$sd_in_urg)))) { # Anomaly $anomalies=$anomalies."For Incoming Packets With URG Flag Set, Average is $average_in_urg, Standard Deviation is $sd_in_urg, and Counted is $count_in_urg\n\n"; } if (($count_out_urg > ($average_out_urg + (2*$sd_out_urg))) || ($count_out_urg < ($average_out_urg - (2*$sd_out_urg)))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets With URG Flag Set, Average is $average_out_urg, Standard Deviation is $sd_out_urg, and Counted is $count_out_urg\n\n"; } if (($count_in_fin > ($average_in_fin + (2*$sd_in_fin))) || ($count_in_fin < ($average_in_fin - (2*$sd_in_fin)))) { # Anomaly $anomalies=$anomalies."For Incoming Packets With FIN Flag Set, Average is $average_in_fin, Standard Deviation is $sd_in_fin, and Counted is $count_in_fin\n\n"; } if (($count_out_fin > ($average_out_fin + (2*$sd_out_fin))) || ($count_out_fin < ($average_out_fin - (2*$sd_out_fin)))) { # Anomaly $anomalies=$anomalies."For Outgoing Packets With FIN Flag Set, Average is $average_out_fin, Standard Deviation is $sd_out_fin, and Counted is $count_out_fin\n\n"; } if (($time_elapsed > ($average_time + (2*$sd_time))) || ($time_elapsed < ($average_time - (2*$sd_time)))) { $anomalies=$anomalies."For time taken per 100 packets, Average is $average_time seconds, Standard Deviation is $sd_time seconds, and last 100 took $time_elapsed seconds.\n\n"; } if ($anomalies ne "") { $anomalies=$anomalies."For the 100 packets this email refers to, the following external IP addresses were communicating with the server:\n"; for ($i=0;$i<$ext_counter;$i++) { $anomalies=$anomalies."$externals[$i] with $ext_count[$i] packets\n"; } email (1,$anomalies); } # Update model for ($i=0;$i<65000;$i++) { $average_in_tcp_source_port[$i] = ((($average_in_tcp_source_port[$i]*($e**-$lambda)) + $count_in_tcp_source_port[$i]) / (1+($e**-$lambda)) ); $sd_in_temp=$average_in_tcp_source_port[$i] - $count_in_tcp_source_port[$i]; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_tcp_source_port[$i] = ((($sd_in_tcp_source_port[$i]*($e**-$lambda)) + $sd_in_temp) / (1+($e**-$lambda)) ); $count_in_tcp_source_port[$i]=0; $average_in_tcp_dest_port[$i] = ((($average_in_tcp_dest_port[$i]*($e**-$lambda)) + $count_in_tcp_dest_port[$i]) / (1+($e**-$lambda)) ); $sd_in_temp=$average_in_tcp_dest_port[$i] - $count_in_tcp_dest_port[$i]; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_tcp_dest_port[$i] = ((($sd_in_tcp_dest_port[$i]*($e**-$lambda)) + $sd_in_temp) / (1+($e**-$lambda)) ); $count_in_tcp_dest_port[$i]=0; $average_out_tcp_source_port[$i] = ((($average_out_tcp_source_port[$i]*($e**-$lambda)) + $count_out_tcp_source_port[$i]) / (1+($e**-$lambda)) ); $sd_out_temp=$average_out_tcp_source_port[$i] - $count_out_tcp_source_port[$i]; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_tcp_source_port[$i] = ((($sd_out_tcp_source_port[$i]*($e**-$lambda)) + $sd_out_temp) / (1+($e**-$lambda)) ); $count_out_tcp_source_port[$i]=0; $average_out_tcp_dest_port[$i] = ((($average_out_tcp_dest_port[$i]*($e**-$lambda)) + $count_out_tcp_dest_port[$i]) / (1+($e**-$lambda)) ); $sd_out_temp=$average_out_tcp_dest_port[$i] - $count_out_tcp_dest_port[$i]; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_tcp_dest_port[$i] = ((($sd_out_tcp_dest_port[$i]*($e**-$lambda)) + $sd_out_temp) / (1+($e**-$lambda)) ); $count_out_tcp_dest_port[$i]=0; } $average_in_syn=( (($average_in_syn*($e**-$lambda)) +$count_in_syn) / (1+($e**-$lambda)) ); $sd_in_temp=$average_in_syn - $count_in_syn; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_syn = ((($sd_in_syn*($e**-$lambda)) + $sd_in_temp) / (1+($e**-$lambda))); $count_in_syn=0; $average_out_syn=( (($average_out_syn*($e**-$lambda)) +$count_out_syn) / (1+($e**-$lambda)) ); $sd_out_temp=$average_out_syn - $count_out_syn; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_syn = ((($sd_out_syn*($e**-$lambda)) + $sd_out_temp) / (1+($e**-$lambda))); $count_out_syn=0; $average_in_ack = ((($average_in_ack*($e**-$lambda)) + $count_in_ack) / (1+($e**-$lambda))); $sd_temp=$average_in_ack - $count_in_ack; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_ack = ((($sd_in_ack*($e**-$lambda)) + $sd_in_temp) / (1+($e**-$lambda))); $count_in_ack=0; $average_out_ack = ((($average_out_ack*($e**-$lambda)) + $count_out_ack) / (1+($e**-$lambda))); $sd_out_temp=$average_out_ack - $count_out_ack; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_ack = ((($sd_out_ack*($e**-$lambda)) + $sd_out_temp) / (1+($e**-$lambda))); $count_out_ack=0; $average_in_rst = ((($average_in_rst*($e**-$lambda)) + $count_in_rst) / (1+($e**-$lambda))); $sd_in_temp=$average_in_rst - $count_in_rst; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_rst = ((($sd_in_rst*($e**-$lambda)) + $sd_in_temp) / (1+($e**-$lambda))); $count_in_rst=0; $average_out_rst = ((($average_out_rst*($e**-$lambda)) + $count_out_rst) / (1+($e**-$lambda))); $sd_out_temp=$average_out_rst - $count_out_rst; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_rst = ((($sd_out_rst*($e**-$lambda)) + $sd_out_temp) / (1+($e**-$lambda))); $count_out_rst=0; $average_in_fin = ((($average_in_fin*($e**-$lambda)) + $count_in_fin) / (1+($e**-$lambda))); $sd_in_temp=$average_in_fin - $count_in_fin; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_fin = ((($sd_in_fin*($e**-$lambda)) + $sd_in_temp) / (1+($e**-$lambda))); $count_in_fin=0; $average_out_fin = ((($average_out_fin*($e**-$lambda)) + $count_out_fin) / (1+($e**-$lambda))); $sd_temp=$average_out_fin - $count_out_fin; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_fin = ((($sd_out_fin*($e**-$lambda)) + $sd_out_temp) / (1+($e**-$lambda))); $count_out_fin=0; $average_in_urg = ((($average_in_urg*($e**-$lambda)) + $count_in_urg) / (1+($e**-$lambda))); $sd_in_temp=$average_in_urg - $count_in_urg; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_urg = ((($sd_in_urg*($e^-$lambda)) + $sd_in_temp) / (1+($e**-$lambda))); $count_in_urg=0; $average_out_urg = ((($average_out_urg*($e**-$lambda)) + $count_out_urg) / (1+($e**-$lambda))); $sd_out_temp=$average_out_urg - $count_out_urg; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_urg = ((($sd_out_urg*($e^-$lambda)) + $sd_out_temp) / (1+($e**-$lambda))); $count_out_urg=0; $average_in_psh = ((($average_in_psh*($e**-$lambda)) + $count_in_psh) / (1+($e**-$lambda))); $sd_in_temp=$average_in_psh - $count_in_psh; if ($sd_in_temp<0) { $sd_in_temp=0-$sd_in_temp; } $sd_in_psh = ((($sd_in_psh*($e**-$lambda)) + $sd_in_temp) / (1+($e**-$lambda))); $count_in_psh=0; $average_out_psh = ((($average_out_psh*($e**-$lambda)) + $count_out_psh) / (1+($e**-$lambda))); $sd_out_temp=$average_out_psh - $count_out_psh; if ($sd_out_temp<0) { $sd_out_temp=0-$sd_out_temp; } $sd_out_psh = ((($sd_out_psh*($e**-$lambda)) + $sd_out_temp) / (1+($e**-$lambda))); $count_out_psh=0; $average_time= ((($average_time*($e**-$lambda)) + $time_elapsed) / (1+($e**-$lambda))); $sd_temp=$average_time - $time_elapsed; if ($sd_temp<0) { $sd_temp=0-$sd_temp; } $sd_time= ((($sd_time*($e**-$lambda)) + $sd_temp) / (1+($e**-$lambda))); #Save model to file open (MODEL, ">/ids/model"); print MODEL "$average_in_syn\n"; print MODEL "$sd_in_syn\n"; print MODEL "$average_in_ack\n"; print MODEL "$sd_in_ack\n"; print MODEL "$average_in_fin\n"; print MODEL "$sd_in_fin\n"; print MODEL "$average_in_rst\n"; print MODEL "$sd_in_rst\n"; print MODEL "$average_in_urg\n"; print MODEL "$sd_in_urg\n"; print MODEL "$average_in_psh\n"; print MODEL "$sd_in_psh\n"; print MODEL "$average_out_syn\n"; print MODEL "$sd_out_syn\n"; print MODEL "$average_out_ack\n"; print MODEL "$sd_out_ack\n"; print MODEL "$average_out_fin\n"; print MODEL "$sd_out_fin\n"; print MODEL "$average_out_rst\n"; print MODEL "$sd_out_rst\n"; print MODEL "$average_out_urg\n"; print MODEL "$sd_out_urg\n"; print MODEL "$average_out_psh\n"; print MODEL "$sd_out_psh\n"; print MODEL "$average_time\n"; print MODEL "$sd_time\n"; for ($i=0;$i<65000;$i++) { print MODEL "$average_in_tcp_source_port[$i]\n"; print MODEL "$average_out_tcp_source_port[$i]\n"; } for ($i=0;$i<65000;$i++) { print MODEL "$sd_in_tcp_source_port[$i]\n"; print MODEL "$sd_out_tcp_source_port[$i]\n"; } for ($i=0;$i<65000;$i++) { print MODEL "$average_in_tcp_dest_port[$i]\n"; print MODEL "$average_out_tcp_dest_port[$i]\n"; } for ($i=0;$i<65000;$i++) { print MODEL "$sd_in_tcp_dest_port[$i]\n"; print MODEL "$sd_out_tcp_dest_port[$i]\n"; } close(MODEL); } } } # Read in the attack signatures open (SIGS,") { @curr_sig=split(/\s/, $_); $sig_source_ip[$i]=$curr_sig[0]; $sig_source_ip[$i] =~ s/ //g; $sig_source_ip[$i] =~ s/\n//g; $sig_source_port[$i]=$curr_sig[1]; $sig_source_port[$i] =~ s/ //g; $sig_source_port[$i] =~ s/\n//g; $sig_dest_ip[$i]=$curr_sig[2]; $sig_dest_ip[$i] =~ s/ //g; $sig_dest_ip[$i] =~ s/\n//g; $sig_dest_port[$i]=$curr_sig[3]; $sig_dest_port[$i] =~ s/ //g; $sig_dest_port[$i] =~ s/\n//g; $sig_msg[$i]=$curr_sig[4]; $sig_msg[$i] =~ s/ //g; $sig_msg[$i] =~ s/\n//g; $sig_flags[$i]=$curr_sig[5]; $sig_flags[$i] =~ s/ //g; $sig_flags[$i] =~ s/\n//g; $sig_data[$i]=$curr_sig[6]; $sig_data[$i] =~ s/ //g; $sig_data[$i] =~ s/\n//g; $i++; } close (SIGS); $num_sigs=$i; # If the model file does not already exist if (!(-e "/ids/model")) { $first_time=1; $second_time=0; # Else the model file does already exist } else { #Read in the model $first_time=0; $second_time=0; open (MODEL, "/ids/model"); $average_in_syn=; $sd_in_syn=; $average_in_ack=; $sd_in_ack=; $average_in_fin=; $sd_in_fin=; $average_in_rst=; $sd_in_rst=; $average_in_urg=; $sd_in_urg=; $average_in_psh=; $sd_in_psh=; $average_out_syn=; $sd_out_syn=; $average_out_ack=; $sd_out_ack=; $average_out_fin=; $sd_out_fin=; $average_out_rst=; $sd_out_rst=; $average_out_urg=; $sd_out_urg=; $average_out_psh=; $sd_out_psh=; $average_time=; $sd_time=; for ($i=0;$i<65000;$i++) { $average_in_tcp_source_port[$i]=; $average_out_tcp_source_port[$i]=; } for ($i=0;$i<65000;$i++) { $sd_in_tcp_source_port[$i]=; $sd_out_tcp_source_port[$i]=; } for ($i=0;$i<65000;$i++) { $average_in_tcp_dest_port[$i]=; $average_out_tcp_dest_port[$i]=; } for ($i=0;$i<65000;$i++) { $sd_in_tcp_dest_port[$i]=; $sd_out_tcp_dest_port[$i]=; } close(MODEL); } # Initialise all the port counters to zero for ($i=0;$i<65000;$i++) { $count_in_tcp_source_port[$i]=0; $count_in_tcp_dest_port[$i]=0; $count_out_tcp_source_port[$i]=0; $count_out_tcp_dest_port[$i]=0; } # Start tcpdump and redirect its output to STDIN open(STDIN,"$tcpdump -xnlp -i$interface tcp |"); # Read and process the sniffer output print "NIDS Started. Now logging and checking packets. Press Ctrl-C to quit.\n"; $i=0; $read_extra_line=0; while () { if ($read_extra_line==0) { until (defined($curr_line=)) { } } # Read the packet header into our data structure @curr_packet=split(/\s/, $curr_line); $time[$i]=$curr_packet[0]; @temp=split(/\./, $curr_packet[1]); @temp2 = ($temp[0],$temp[1],$temp[2],$temp[3]); $source_ip[$i]=join(".", @temp2); $tcp_source_port[$i]=$temp[4]; @temp=split(/\./, $curr_packet[3]); @temp2 = ($temp[0],$temp[1],$temp[2],$temp[3]); $destination_ip[$i]=join(".", @temp2); $tcp_dest_port[$i]=$temp[4]; $tcp_dest_port[$i]=~ s/://g; if ($curr_packet[4]=~/S/) { $tcp_syn[$i]=1; } else { $tcp_syn[$i]=0; } if ($curr_line=~/ack/) { $tcp_ack[$i]=1; } else { $tcp_ack[$i]=0; } if ($curr_packet[4]=~/R/) { $tcp_rst[$i]=1; } else { $tcp_rst[$i]=0; } if ($curr_packet[4]=~/F/) { $tcp_fin[$i]=1; } else { $tcp_fin[$i]=0; } if ($curr_packet[4]=~/U/) { $tcp_urg[$i]=1; } else { $tcp_urg[$i]=0; } if ($curr_packet[4]=~/P/) { $tcp_psh[$i]=1; } else { $tcp_psh[$i]=0; } # Read in the data part of the packet $curr_data_line=; $curr_data_line =~ s/ //g; $curr_data_line =~ s/\t//g; $curr_data_line =~ s/\n//g; $tcp_data[$i]=$curr_data_line; while (length($curr_data_line)==32) { $curr_data_line=; $curr_data_line =~ s/\t//g; $curr_data_line =~ s/\n//g; if (length($curr_data_line)<=40) { $read_extra_line=0; $curr_data_line =~ s/ //g; $tcp_data[$i]=$tcp_data[$i].$curr_data_line; } else { $read_extra_line=1; $curr_line=$curr_data_line; } } # Perform misuse detection misuse($i); # Perform anomaly detection anomaly($i); # Increment packet counter $i++; # Reset packet counter to zero once we have 100 packets if ($i>=100) { $i=0; } }