#!/usr/bin/perl
print "Content-type: text/html \n\n";

#################################################################
# Yu.Semenov ITEP	October 2009-19				#
# <access_log> development					#
# 1. Programm looks for reqests with "////" and makes		#
#    a IP-distribution for these events				#
#    (file <atk_ip.txt>).					#
#	 File format: IP-address number				#
# 2. Program builds a time evolution of <access_log>-file	#
#    These data are put into the file <delta.txt>		#
# for the last day with the end of interval at current moment	#
#	 File format: 						#
#    seconds_number_(10_secs_interval) delta_len		#
# 3. Program calculate a record length distributin and put	#
#    it into the file <rec_leng.txt>.				#
#	 File format: rec_length number				#
# 4. Program register events with more than 2 requests in	#
#    a one second and build a distribution of such requests	#
#	 on IP-addresses (file <atk_dens.txt>)			#
#	 File format: IP-address number				#
# 5  Total length_of_records & number_of_records for the	#
#    last day	(file <rec_num.txt>)				#
# The selected data for attack cases is written into		#
# DataBase <saturn.access_log> format:				#
# <ip> <date_time> <ID> <full_record> 				#
# $att_type=1 for "////"; $att_type=2 for >3 recs in sec;	#
# $att_type=3 for very long records				#
# $att_type=4 for illegal method of HTTP			#
# $att_type=6 for requests longer than 250 symbols		#
#################################################################

use IO::File;
use Socket;
use Time::Local;
use DBI;
use GD;
use graf_dec;   # Sher library
use libr1;	# primitives library 2020
#use Chart::Gnuplot;
use strict;

my @mon=("Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec");
my @incl=(".gif",".GIF",".jpg",".ico",".css",".png","robots.txt",".crowl.","yandsearch","spider6","robot06.rambler","robot02.rambler","spider18.yandex","spider55.yandex",".googlebot.com","crawl.baidu.com","dotnetdotcom.org","search.msn.com",".cuil.com","crawl.yahoo.net","bredband.telia.com",".us.archive.org",".naver.jp","av16570.comex.ru",".domolink.tula.net",".setooz.com","gigablast.com","78.41.98.38","78.41.98.166","94.103.89.246","robot07.rambler.ru","robot9.rambler.ru","spider27.picsearch","spider30.picsearch","spider23.picsearch","turbospider.yandex","robot7.rambler.ru","spider09.yandex");
my @forbid=("cgiwrap",'"PUT','"TRACE','"DELETE','"OPTIONS','"PROPFIND');
my $l_len=1;			# init line index
my $name="";
my $marker=-1;
my $duration=0;
my $ipa_count=0;		# number of records in file <atk_ip.txt>
my $s_cur=0;
my $browser="";
my $day_night=86400;		# seconds
my $star_TIME=0;
my %rec=();			# Hash-array of records
my $delt=0;
my $step=50;			# bin width
my $sum_len=0;			# sum length of all records
my @records=("","","","","","","","","","","");	#records array
my $tot_len=0;			# length from the file beginning
my $tot_rec_count=0;		# record counter in a file
my $local_rec_count=0;		# record counter in a second
my %ipa=();			# IP-hash-array
my %ipb=();			# IP-hash array for .cgi

my %ipd=();			# IP-hash for dense records
my %len=();			# hash for record-lengths
my %long_req=();		# hash for long_req.txt
my %ips=();			# hash array of ips{name}
#my %d=();			# hash-array of timescale
my $where=-1;
my $where1=-1;
my ($line,$con,$length,$p1,$p2,$year,$month,$day,$Tst,$path1,$path2,$att_type,$t_bin_num);
my ($sigm,$D,$s_length,$len_avr,$tot_num,$pi,$K,$j,$datetime,$res,$DT0,$stop_time,$pppp);
my ($p_cgi,$p_ill,$lin);
my ($hours,$minutes,$seconds,$TIME,$date,$date_time,$pr,$p_r,$img,$start_time,$cur_time);
my ($p_dens,$ip_num,$p,$p_del,$T0,$ip,$p_rec,$ip_adr,$p_len,$p_delta,$pin1,$ptd,$pdel,$counts,$p1_del);
my ($i,$nm,$s,$m,$pin,$key,$delta,$k,$ico,$jpg,$p_reqv,$fl,$M,$len,$num,$pp,$end_time,$cnt);
my (@ar,@L,@LL,@LLL,@Mi,@Lm,@R,@lengths,@recds,@MM,@MMM,@NNN,@t_bins,@tm,@ill);
@Mi=("","","","");
$R[0]="";
my $t_mark=0;
my $meth="";
my $fls=0;						# Flag "/////"
for($i=0;$i<1441;$i++)	{$t_bins[$i]=0;
			 $tm[$i]=0;}			# day-distribution initiating

$pin="/home/httpd/htdocs/saturn/attacks/ids/access_log.filt1";	# for debugging purposes

# Opening file <access_log.filt1>
sysopen(AFIL, $pin, O_RDWR) or die$!;

#################################################################
# Start of records development
#################################################################

my $N_rc=0;		# record counter
my $n_req=0;		# request counter
my $n_reqt=0;
my $il=0;		# illegal line counter

while (!eof(AFIL)) {	# Cycle for access_log.filt1-file  development	 ########
$line=readline(AFIL);								#

# we need to check presence of "////" (atk_ip.txt) 				#
# and illegal HTTP-method (@ill)						#
# to put such ilnes in correspondent files atk_ip.txt and illegal.txt		#
#										#
$lin=lined($line);	# Format: "$ip $tm $meth $length $fls"	$fls=1, if //// #

# illegal HTTP-methods								#
ill_tex($line,$il,@ill);							#

@MM=split/\s+/,$lin;								#
#print "Lin=",$MM[3],"\n";							#
$N_rc++;					# Next record			#
#########################################################################	#
# The first record is an oldest						#	#
# Date-Time format: [22/Nov/2009:04:09:51 +0300]			#	#
#########################################################################	#
$cur_time=$MM[1];		# from the current record			#

# "////"-strings detection							#
slash($line,%ipa);								#
#print "dat-time=",$date_time, " cur_time=", $cur_time,"\n";			#

$records[$n_req]=$lin;		# put down the record				#
$rec{$records[$n_req]}=$cur_time;	# hash rec				#
$n_req++;									#
$length=$MM[3];									#
$sum_len=$sum_len+$length;	# Total record length (?)			#
$n_reqt++;									#
			}	# end of basic WHILE			#########
#print "last line=",$records[$n_req-1],"\n";
$start_time=$cur_time-$day_night;

#print "start-time=",$start_time," cur_time=",$cur_time, "\n";
close(AFIL);			# Close file <access_log.filt1>	#
#print "useful records=",$n_req," Total length=",$sum_len," Total_recs=",$n_reqt,"\n";

#################################################
# The record array reodering according TIME	#
#################################################

$counts=0;
foreach $key (sort {$rec{$a}<=>$rec{$b}} keys %rec)
{
if($rec{$key}>$start_time)	{				#########
$records[$counts]="$key";	# Writing into file <record-array>	#
# print "rec=",$records[$counts],"\n";					#
    $counts++;								#
				}				#########
}
#print "counts=",$counts," rec0=",$records[0],"\n","rec_last=",$records[$counts-1],"\n";

# OPEN all OUTPUT files					#########
# template for the file <date_time.txt>				#
$p_rec="/home/httpd/htdocs/saturn/attacks/ids1/";		#

# form the pass for the file <delta.txt>			#
$p_del=$p_rec."delta.txt";	# /home/httpd/htdocs/saturn/attacks/ids1/delta.txt
$p1_del="/home/httpd/htdocs/saturn/attacks/ids1/delta1.txt";
# Opening the time_log-file	<delta1.txt>			#
sysopen(AFT, $p_del, O_RDWR|O_TRUNC|O_CREAT) or die$!;		# delta.txt

# form the pass for the file <rec_leng.txt>
$p_len=$p_rec."rec_leng.txt";
# Opening file <rec_leng.txt>: length-number			#
sysopen(Flen, $p_len, O_RDWR|O_TRUNC|O_CREAT) or die$!;		# rec_leng.txt

# form the pass for the file <atk_ip.txt>
$p_r=$p_rec."atk_ip.txt";		# e:/www/attacks/ids1/atk_ip.txt
# Opening file <atk_ip.txt>					#
sysopen(Fipa, $p_r, O_RDWR|O_TRUNC|O_CREAT) or die$!;		# atk_ip.txt

# the pass for the file <atk_dens.txt>
$p_dens=$p_rec."atk_dens.txt";	# /home/httpd/htdocs/saturn/attacks/ids1/atk_dens.txt
# Opening the <atk_dens.txt>					#
sysopen(Fipd, $p_dens, O_RDWR|O_TRUNC|O_CREAT) or die "Can't start tst1: $!\n";	# atk_dens.txt
# the pass for the file <cgi.txt>				#
$p_cgi=$p_rec."cgi.txt";	
# Opening the <cgi.txt>						#
sysopen(Fcgi, $p_cgi, O_RDWR|O_TRUNC|O_CREAT) or die "Can't start tst2: $!\n";	# cgi.txt

# open file <time_length.txt>					#
$pppp="/home/httpd/htdocs/saturn/attacks/ids1/time_length.txt";
sysopen(Ftml, $pppp, O_RDWR|O_TRUNC|O_CREAT) or die$!;		#

# the pass for the file <illegal.txt>				#
$p_ill=$p_rec."illegal.txt";		# /home/httpd/htdocs/saturn/attacks/ids1/illegal.txt
# Opening the <illegal.txt>					#
sysopen(Fil, $p_ill, O_RDWR|O_TRUNC|O_CREAT) or die$!;		# illegal.txt

# the pass for the file <long_req.txt>				#
my $p_long=$p_rec."long_req.txt";    # /home/httpd/htdocs/saturn/attacks/ids1/long_req.txt
# Opening the <long_req.txt>					#
sysopen(F_long, $p_long, O_RDWR|O_TRUNC|O_CREAT) or die$!;	#
								#
###########################################		#########
# connect to the DB <saturn.access_log>	  #
# Table format:				  #
# date_time, ip, brouser, type, attack#	  #
###########################################

#$con = DBI->connect("DBI:mysql:host=localhost;database=saturn",
#                    "root",
#                    "yurgur241",
#{PrintError => 0, RaiseError => 1})or die "no connect to DB: $DBI::errstr\n";
#print "useful records=",$n_req," Total length=",$sum_len," Total_recs=","\n";

#################################################################
# Start of record array development				#
#################################################################

for($K=0;$K<$counts;$K++)	{			# Records CYCLE #####
$line=$records[$K];					# of a new format   #
#print "K=",$K," line=",$line," R=",$records[$K],"\n";			    #
if($K==0)	{print "R_0=",$line,"\n";}				    #
if($K==$counts-1){print "R_fin=",$line,"\n";}				    #
@L=split/\s+/,$line;		# Split request line $L[0]=$ip		    #
$cur_time=$L[1];
$ip=$L[0];
#print "IP=",$ip," cur-time=",$L[1],"\n";				    #
# date-time for MYSQL							    #
#########################################################		    #
# Absolute time calculation				#		    #
#########################################################		    #
$TIME=$cur_time;							    #
# The start record development						    #
#########################################################################   #
if($K==0)	{		# The last record analysis first	#   #
$T0=$TIME;			# The last record time			#   #
$s_cur=$T0;			# start time seconds			#   #
$Tst=$T0;			# Start time constant			#   #
$star_TIME=$TIME;		# start time for array			#   #
#print "star_Time=",$star_TIME," cur-time=",$cur_time,"\n";		#   #
		}		# end of start time development		#   #
#########################################################################   #
$length=$L[3];
#print "LEN=",$length,"\n";
print Ftml $TIME," ",$length,"\n";	# file time_length.txt		    #
#################################
# %len-hash creating & updating	#
#################################################################	    #
# rec_len($length,%len);						    #
rec_len;
#################################################################	    #
# Record analysis						#	    #
#################################################################	    #
#$where=index($line,"////");	# look for path traversal		    #
$where1=-1;
$fl=0;
$meth=$L[2];
#print "meth=",$meth,"\n";						    #
if($fl==1)	{$where1=1};		# if GET ...cgi			    #
$where=$L[4];
$ip=$L[0];
$ip_num=ip_to_num($ip);			# IP-number for DB		    #
if($where!=-1)	{			#########			    #
$att_type=1;					#			    #
		}	# Fix attack type   #####			    #
if($where1!=-1)	{							    #
$att_type=4;	}							    #
# LONG REQUST attack (BUFFER OVERFLOW)					    #
#print "Le=",$length,"\n";						    #
if($length>250)	{			# Too long record development ###   #
$att_type=6;								#   #
#################################					#   #
# Long request attack		#					#   #
#################################					#   #
if(exists($long_req{$ip}))		{	# hash init		#   #
$long_req{$ip}=$long_req{$ip}+1;					#   #
					}				#   #
		else{$long_req{$ip}=1;}					#   #
		}						#########   #
if($ip eq "144.206.148.31"){$ip="1.1.1.1";}	# if request from my comp   #
if($where!=-1)	{						########### #
if(exists($ipa{$ip}))	{		# IP-hash updating	######### # #
$ipa{$ip}=$ipa{$ip}+1;							# # #
									# # #
#print "ipa=",$ip," n=",$ipa{$ip}," type=",$att_type,"\n";		# # #
#$res = $con->prepare("INSERT INTO access_log VALUES('$datetime','$ip_num','$att_type',1,'$browser')") or die "no prepare sql-command: $DBI::errstr\n";
#$res->execute();							# # #
			}					######### # #
else{$ipa{$ip}=1;						  ######### #
#$res = $con->prepare("INSERT INTO access_log VALUES('$datetime','$ip_num','$att_type',1,'$browser')") or die "no prepare sql-command: $DBI::errstr\n";
#$res->execute();							#   #
    }							# hash init #####   #
		}		# end for WHERE!=-1		#############

if($where1!=-1)	{						#########	#
if(exists($ipb{$ip}))	{	# IP-hash updating #########		#	#
    $ipb{$ip}=$ipb{$ip}+1;				   #		#	#
#print "ipb=",$ip," n=",$ipb{$ip}," type=",$att_type,"\n"; #		#	#
#$res = $con->prepare("INSERT INTO access_log VALUES('$datetime','$ip_num','$att_type',1,'$browser')") or die "no prepare sql-command: $DBI::errstr\n";
#$res->execute();					   #		#	#
			}			   #########		#	#
else{$ipb{$ip}=1;								#
#$res = $con->prepare("INSERT INTO access_log VALUES('$datetime','$ip_num','$att_type',1,'$browser')") or die "no prepare sql-command: $DBI::errstr\n";
#$res->execute();							#	#
    }		# hash init		#####				#	#
		}			# end for WHERE1!=-1	#########	#
#				}	# end of if for ///		######### !!!!!!!!
#############################################################

if($TIME>($Tst+$day_night))	{$K=$n_req;  ####
				}	     #### set end of cycle

#########################################################
# Building the file increments distribution 		#
#########################################################

$t_bin_num=int(($TIME-$star_TIME)/60);			#
# number of 60-second intervals				#
#print " del_T=",($TIME-$star_TIME)," idx=",$t_bin_num," leng=",$length," time=",$TIME,"\n";
if(($t_bin_num<1440) && ($t_bin_num>=0))		#
{$t_bins[$t_bin_num]=$t_bins[$t_bin_num]+ $length;}	#
#########################################################
my $count=0;
$delta=$TIME-$s_cur;			# Is this record in the same second?
if($delta==0)	{			# if inside a second	#####
	$recds[$count]=$line;					    #
#print "count=",$count,"\n";					    #
#print "RR=",$recds[$count],"\n";				    #
	$count++;			# records in sec	    #
		}						#####
else	{				# it is not in the same second		#############
	$m=$count-1;			# record counter				    #
	$count=0;									    #
	$s_cur=$TIME;			# renew current second				    #
#print "m=",$m," REC=",$recds[0],"\n";							    #
#############################################################				    #
if($m>3)	{			# if > 3 records in sec			#########   #
for($j=0;$j<$m;$j++)	{						#########	#
#print "j=",$j," rec=",$recds[$j],"\n";						#	#   #
@R=split/\s+/,$recds[$j];							#	#
print "Recs=",$recds[0],"\n";
@Mi=split/\./,$R[0];			# Is name of IP-form?			#	#   #
if($#Mi==3)	{		#########################################	#	#
if($Mi[0]!~/\D/)	{		######### if number	#########	#	#   #
	if($Mi[0]>0 && $Mi[0]<255)	{	#####################	#	#	#
	if($Mi[1]!~/\D/)			{	# if number	#	#	#   #
	if($Mi[1]>0 && $Mi[1]<255)	{				#	#	#
		if($Mi[2]>0 && $Mi[2]<255)	{	########### #	#	#	#   #
			if($Mi[3]>0 && $Mi[3]<255)	{    #### # #	#	#	#
				$ips{$R[0]}=$R[0];		# # #	#	#	#   #
							}    #### # #	#	#
						}	########### #	#	#	#   #
					}		#	#	#	#
							}		#	#	#   #
					}	#################	#	#
			}		#################################	#	#   #
		}					#########	#	#
if(exists($ips{$R[0]}))	{$ip=$ips{$R[0]};}	# fix IP			#	#   #
else{								#########	#
$ip_adr= gethostbyname($R[0]);						#	#	#   #
if (defined $ip_adr) 	{		# If there is IP    #####	#	#
	$ip = inet_ntoa($ip_adr);	# IP-adr within cluster	#	#	#	#   #
#print "IP=",$ip," name=",$R[0],"\n";					#	#
	$ips{$R[0]}=$ip;			# if it is not in hash	#	#	#   #
	$ip_num=ip_to_num($ip);		# IP-number for DB			#	#   #
# High request density
if(exists($ipd{$ip}))	{		##### IP-hash updating	#	#	# !!!	#   #
	$ipd{$ip}=$ipd{$ip}+1;		# for $ipd			#	#	#   #
#print "ipd=",$ip," n=",$ipd{$ip},"\n";	#	#	#	#	#	#	#   #
			}		##### 		#	#	#	#	#
else{$ipd{$ip}=1;}			# hash init	#	#	#	#	#
			}				    #####	#	#	#   #
	}				# end of ELSE $m	    #####	#	#
			}	########## end of FOR $m ########################	#   #
for($i=0; $i<$m; $i++)	{	#####			#	#			#   #
	$recds[$i]="";		# clear record array	#	#			#   #
	$count=1;	}	#####			#	#			#
	$recds[0]=$line;					#			#   #
$att_type=2;			# too many requests in a second	#			#
if(!defined $ip_num) {$ip_num=0;}				#			#   #
#print "DT=",$datetime," IP=",$ip_num," BRWS=",$browser," m=",$m,"\n";			#   #
#$res = $con->prepare("INSERT INTO access_log VALUES('$datetime','$ip_num','$att_type','1','$browser')") or die "no prepare sql-command: $DBI::errstr\n";
#$res->execute();								#	#   #
			}	# end of IF $m>2				#########   #
	}			# end of ELSE not in a second			#############
#############################################################
#	    }						# date terms number control
$tm[$t_bin_num]=$star_TIME+$t_bin_num*60+30;
}							# end of basic FOR cycle

#########################################
#	<delta.txt> and <delta1.txt>	#
#########################################

sysopen(AFT1, $p1_del, O_RDWR|O_TRUNC|O_CREAT) or die$!;
for($i=0;$i<1440;$i++)	{		# minute intervals	#########
if($tm[$i]==0) {$tm[$i]=$star_TIME+($i)*60+30;}				#
if($t_bins[$i] eq "")	{$t_bins[$i]=0;}				#
print AFT1 $tm[$i]," ",$t_bins[$i],"\n";				#
print AFT $i," ",$t_bins[$i],"\n"; # growth rate evolution <delta.txt>	#
			}					#########
close(AFT);				# close file <delta.txt>

############################################################################################
# Writing into files <long_req.txt> <atk_ip.txt> <cgi.txt> <atk_dens.txt> <rec_leng.txt>   #
############################################################################################

# Write to <long_rec.txt>

foreach $key (reverse sort {$long_req{$a}<=>$long_req{$b}} keys %long_req)
{print F_long "$key $long_req{$key}\n";		# Write into long_req.txt
}

# Write to <atk_ip.txt>

$ipa_count=0;
foreach $key (reverse sort {$ipa{$a}<=>$ipa{$b}} keys %ipa)
{print Fipa "$key $ipa{$key}\n";	# Writing into file <atk_ip.txt>
$ipa_count++;
#	print " ipa= $key $ipa{$key}\n";
}
if($ipa_count==0)	{print Fipa "- 0\n";}
#print "IPA-count=",$ipa_count,"\n";

# Write to <cgi.txt>

foreach $key (reverse sort {$ipb{$a} <=> $ipb{$b}} keys %ipb)
{print Fcgi "$key $ipb{$key}\n";	# Writing into file <cgi.txt>
}

# Write to <atk_dens.txt>

foreach $key (reverse sort {$ipd{$a} <=> $ipd{$b}} keys %ipd)
{print Fipd "$key $ipd{$key}\n";	# Writing into file <atk_dens.txt>
}

# Write to <rec_leng.txt>

foreach $key (reverse sort {$len{$a} <=> $len{$b}} keys %len)
{print Flen "$key $len{$key}\n";	# Writing to file <rec_leng.txt>
$sum_len=$sum_len+($key*$len{$key});
}
close(Flen);
close(Fipa);
close(Fipd);
close(F_long);

my $p="/home/httpd/htdocs/saturn/attacks/ids1/rec_leng.txt";	# Input
my $pp="/home/httpd/htdocs/saturn/attacks/ids1/lengths.txt";

avr_rms($p,$pp);

for($i=0;$i<30;$i++)	{ 	# filling in file <illegal.txt> #########
if((defined $ill[$i])&& ($ill[$i] ne "")){print	Fil $ill[$i];}		#
			}					#########

#################################################################
# 	Making up a picture from the file <lengths.txt> 	#
#################################################################
$path1='/home/httpd/htdocs/saturn/attacks/ids1/rec_len.png';
$img = &vert_diagr(15,600,400,15,'/home/httpd/htdocs/saturn/attacks/ids1/lengths.txt',$path1,1,7,3,$img,25);
sysopen(PICTURE, $path1, O_RDWR|O_CREAT) or die("Cannot open file for writing");
binmode PICTURE;
print PICTURE $img->png;
close PICTURE;

$path2='/home/httpd/htdocs/saturn/attacks/ids1/long_req.png';
$img = &vert_diagr(15,600,400,15,'/home/httpd/htdocs/saturn/attacks/ids1/long_req.txt',$path2,1,7,3,$img,25);
sysopen(PICTURE,$path2, O_RDWR|O_CREAT) or die("Cannot open file for writing");
binmode PICTURE;
print PICTURE $img->png;
close PICTURE;
use Chart::Gnuplot;
# Plot the data set on the chart
#print "GNUPLOT\n";
my $chart = Chart::Gnuplot->new(
output => "/home/semenov/delta1.ps"
);

my $dataSet=Chart::Gnuplot::DataSet->new(
datafile => "/home/httpd/htdocs/saturn/attacks/ids1/delta.txt",
style => "boxes"
);
$chart->plot2d($dataSet);
do "/home/crontab_files/error.pl";		# start of error.pl (restored at 26-12-2019)
exit;
# END { }
