#!/usr/bin/perl # # ViperDB v0.6 # # ViperDB was created as a smaller & faster option to Tripwire. # Tripwire while being a great product leaves something to be # desired in the speed department and also, by default tripwire # generates a report everytime it runs and directs that report # to an email address. This hinders most people from running # Tripwire every few minutes to do a system check. ViperDB # however is the answer to this problem. ViperDB does not use # a fancy all-in-one database to keep records instead, I opted # to keep it fast and hence decided to go with a plaintext db # which is stored in each "watched" directory. By using this # there is no real one attack point for a attacker to focus his # attention on. This coupled with the running of ViperDB every # 5 minutes (via cron root job) decreases that likelyhood that # an attacker will be able to modify your "watched" filesystem # .while ViperDB is monitoring your system # # NOTES: # # # PLANNED UPGRADES: # - Adding of a "protect" function which would "react" to changes # made to the filesystem and do whatever it could to maintain # the stored filesystem (ie change permissions, owners, and # groups back to what they were stored as when -init was run) # - Adding of a more complex "reporting" system which would # create email to a specified address and would report changes, # additions, and deletions # - Adding of a more complex "system status" function which when # a change is detected, would grab info that might be helpful # in determining what caused the change (ie. processes running, # users logged in, last few lines from logfiles, etc) # # THANKS TO: # whitetrash, wrlwnd, punkis, & rooster # # VERSION HISTORY # 0.1 - 0.5 - Wrote CreateDB.pl which generates the DBs # - Wrote CheckDB.pl which used diff to find changes # - Re-Coded to use a "distributed database" instead of # one centralized DB. # - Re-Coded to use a config file (ViperDB.ini) # - Changed to use Assoc. Arrays to speed up processing # - Added capability to detect additions & deletions of # files to "watched" directories # 0.6 - Merged CreateDB.pl & CheckDB.pl into one # - Cleaned out debugging code and commented more # These are the only things you should need to set $configfile='/usr/local/etc/viperdb.ini'; $logfile='/var/log/ViperDB.log'; ### ### You shouldn't have to touch anything below here ### $startrun=`date`; chomp $startrun; # Detect what command line switches were passed and act accordingly if (@ARGV[0] eq '-init'){ print "Init Detected. Creating Databases...\n"; &InitDB; } elsif (@ARGV[0] eq '-check'){ # print "Check Detected: Now Checking File Sanity...\n"; &SysCheck; } else { print "\n\nViperDB v0.6\n"; print "ERROR: Unrecoignized option or none given.\n"; print "usage: ViperDB -init -check\n"; print " -init Initializes the ViperDB Databases\n"; print " -check Runs a system file sanity check\n"; } sub InitDB { $runtype='init'; &CreateDB; } sub SysCheck { $runtype='check'; &CreateDB; &Compare; &Cleanup; } sub CreateDB { open (CONFIG, "< $configfile"); STARTCONFIG: $configline=; chomp $configline; while ( defined($configline) ) { if ( $configline =~ /:/) { goto STARTCONFIG; } else { $wd=$configline; #Set some Var's based on wether we are initing or checking if ($runtype eq 'init') { $ViperDB=$wd . '.ViperDB'; $tmpfile='/tmp/.ViperDB'; } else { $ViperDB=$wd . '.ViperDB.tmp'; $tmpfile='/tmp/.ViperDB.tmp'; } # Get a dump of all the current files in the dir and system("ls -laAS $wd|tr -s ' '|grep -v total|grep -v ViperDB>>$tmpfile"); open (SUPPAHSEKRETDB, "> $ViperDB"); open (BINLIST, "< $tmpfile"); $line=; chomp $line; while ( defined($line) ) { ($perms,$junk,$uid,$gid,$size,$month,$day,$yearortime,$bname) = split/ /,$line; # I couldn't figure out a way to just do 3 chops and then reverse the string stored in the variables so... # I am doing it this way... SHADDDUP... itz not lame.. itz.. just ... just so kewl you don't know it... $aa = (chop $perms); $ab = (chop $perms); $ac = (chop $perms); $ba = (chop $perms); $bb = (chop $perms); $bc = (chop $perms); $ca = (chop $perms); $cb = (chop $perms); $cc = (chop $perms); $aperms = $ac . $ab . $aa; $gperms = $bc . $bb . $ba; $operms = $cc . $cb . $ca; $filetype = (chop $perms); # Misc Debuggin Shit # print "Binary Name: $bname\n"; # print " File Type: $filetype\n"; # print " File Size: $size\n"; # print " File Owner: $uid\n"; # print " File Group: $gid\n"; # print "Owner Perms: $operms\n"; # print "Group Perms: $gperms\n"; # print "Other Perms: $aperms\n"; print SUPPAHSEKRETDB "$wd$bname,$size,$filetype,$uid,$operms,$gid,$gperms,$aperms,$month,$day,$yearortime\n"; $line=; chomp $line; } # While close (BINLIST); # rm the tmpfile system("rm -rf $tmpfile"); close(SUPPAHSEKRETDB); # Change the permissions to only allow root to read... system("chmod 400 $ViperDB"); $configline=; chomp $configline; } # else...if } close (CONFIG); } sub Compare { open (DIRLIST, "< $configfile"); open (LOG, ">> $logfile"); print LOG "\n\n START RUN: $startrun\n"; READDIRLIST: $dirlistline=; chomp $dirlistline; while ( defined($dirlistline) ) { if ( $dirlistline =~ /:/) { goto READDIRLIST; } else { $mypath=$dirlistline; } $RealDB=$mypath . '.ViperDB'; $ChkDB=$mypath . '.ViperDB.tmp'; # Init some Assoc. Arrays %valid = (); %check = (); # Read the RealDB into an Assoc. Array open(A, $RealDB); while () { ($bname,$junk) = split /,/,$_; chomp $bname; if ( defined($bname) ) { if ( defined($valid{$bname}) ) { # print "ERROR:RealDB: Duplicate entry found for $bname.\n"; } else { $valid{$bname} = $_; } # if ... else } # if } # while close (A); # Read the CheckDB into an Assoc. Array open(B, $ChkDB); while () { ($bname,$junk) = split /,/,$_; chomp $bname; if ( defined($bname) ) { if ( defined($check{$bname}) ) { # print "ERROR:CheckDB: Duplicate entry found for $bname.\n"; } else { $check{$bname} = $_; } # if ... else } # if } # while close (B); foreach $bname ( sort keys %valid ) { $fileinfoa=$valid{$bname}; $fileinfob=$check{$bname}; if($fileinfoa ne $fileinfob) { ($binnamea,$sizea,$filetypea,$uida,$opermsa,$gida,$gpermsa,$apermsa,$montha,$daya,$yearortimea) = split/,/,$fileinfoa; ($binnameb,$sizeb,$filetypeb,$uidb,$opermsb,$gidb,$gpermsb,$apermsb,$monthb,$dayb,$yearortimeb) = split/,/,$fileinfob; chomp $yearortimea; chomp $yearortimeb; if( ! defined($binnameb) ){ print LOG " FILE DELETED: $binnamea\n"; } else { print LOG "CHANGES TO FILE: $bname\n"; if($sizeb ne $sizea) { print LOG " SIZE: was $sizea now $sizeb\n"; } if($filetypeb ne $filetypea) { print LOG " TYPE: was $filetypea now $filetypeb\n"; } if($uidb ne $uida) { print LOG " OWNER: was $uida now $uidb\n"; } if($opermsb ne $opermsa) { print LOG " OWNER PERMS: was $opermsa now $opermsb\n"; } if($gidb ne $gida) { print LOG " GROUP: was $gida now $gidb\n"; } if($gpermsb ne $gpermsa) { print LOG " GROUP PERMS: was $gpermsa now $gpermsb\n"; } if($apermsb ne $apermsa) { print LOG " ALL PERMS: was $apermsa now $apermsb\n"; } if($monthb ne $montha || $dayb ne $daya || $yearortimeb ne $yearortimea) { print LOG " TIMESTAMP: was $montha $daya $yearortimea now $monthb $dayb $yearortimeb\n"; } } # if ... else } # if } # foreach foreach $bname ( sort keys %check ) { $fileinfoa=$valid{$bname}; $fileinfob=$check{$bname}; ($binnamea,$junk) = split/,/,$fileinfoa; ($binnameb,$junk) = split/,/,$fileinfob; if (! defined($binnamea) ) { print LOG " NEW FILE: $binnameb\n"; } } # foreach $dirlistline=; chomp $dirlistline; } # While close (LOG); } sub Cleanup { open (CONF, "< $configfile"); STARTCONF: $confline=; chomp $confline; while ( defined($confline) ) { if ( $confline =~ /:/) { goto STARTCONF; } else { $rmdir=$confline; } $tmpDB=$rmdir . '.ViperDB.tmp'; system("rm -rf $tmpDB"); $confline=; chomp $confline; } # While close (CONF); } #no stickbitz or SUIDs