Here is the script
It was tested on Cre Loaded 6.15
This script will monitor any server files, it does not need to be Cre Loaded
Here is the readme file
Code:
Sitemonitor_log.php was created to journal all of the modifications I make to Cre Loaded 6.15.
This script automatically writes a log of all deleted files, added files, file time changes, file permissions changes and file size changes. This way if I need to review what files I have changed - then all I need to do is view my log or review my emails.
Once I am done using this script as a journal I then can use it to monitor my site for changes due to a hacker getting into my site. It will also tell me when my site's error log has changed thereby alerting me.
sitemonitor_log.php, v1.0 2006/08/22 by pyramids
Adapted from original $Id: sitemonitor.php,v 1.0 2006/08/02 by Jack_mcs
//////////////////
SETUP INSTRUCTIONS
//////////////////
fill in the settings in sitemonitor_log.php
create folder called site_monitor
password protect the site_monitor folder
place sitemonitor_log.php into the site_monitor folder
run the sitemonitor_log.php script for the first time manually "VERBOSE set to 1" the script will create the REF and LOG files then you are ready to setup cron (change the VERBOSE to 0 to run as a cron script)
cron setup (run in the am hours)
/usr/bin/php -q /home/YOUR_USER_NAME/public_html/site_monitor/sitemonitor_log.php
Note 1:
If you want to start a clean journal just delete the log file and run manually one time
Note 2:
On some servers - if you are having permission problems with site_monitor/sitemonitor_log.txt and site_monitor/sitemonitor_ref.txt, try the enclosed script FixLogPermissions.php which runs in the root.
Both of these newly created files need to have permission to write. Set to 755, if that does not work then set to 777.
Note 3:
There is a php time out of 30 seconds. This script can monitor about 1500 files before it timesout. I suggest that you monitor the root, includes and templates. If you want to monitor the admin then setup a second monitoring script. Just copy, rename and change the settings
Note 4:
This scrpt can be run manually without setting it up as a cron script
Here is the sitemonitor_log.php file
Code:
<?php
/*
sitemonitor_log.php, v1.1 2006/08/22 by pyramids
Adapted from original $Id: sitemonitor.php,v 1.0 2006/08/02 by Jack_mcs
osCommerce, Open Source E-Commerce Solutions
http://www.oscommerce.com
Copyright (c) 2003 osCommerce
Released under the GNU General Public License
Use at your own risk
Modified the original sitemonitor.php to do the following:
1: Keep a detailed log (optional feature)
2: Update the reference file every time there are changes (optional feature)
3: Added a timer
4: Will now check all file changes including deleted files
5: List sub directories to exclude
6: Removed the call to "require('includes/application_top.php')"
7: Updated the mail function
8: Updated message and email reporting
9: Was 2 files - the script and it's functions, now just one file with both since we shortened the script to be more efficient
*/
// SETUP INSTRUCTIONS
// SET THE OPTIONS AND SETTINGS below
// create folder called site_monitor and make the permissions 777
// password protect the site_monitor folder
// place sitemonitor_log.php into the site_monitor folder
// run the sitemonitor_log.php script for the first time manually, the script will create the REF and LOG files
// then you are ready to setup cron (change the VERBOSE to 0 to run as a cron script)
// cron setup
// /usr/bin/php -q /home/YOUR_USER_NAME/public_html/site_monitor/sitemonitor_log.php
//
//Note: if you want to start a clean journal just delete the ref and log files and run the script once manually
//
/************** SET THE OPTIONS AND SETTINGS ****************/
define('VERBOSE', 1); //set to 1 to see the results displayed on the page (for when running manually)
define('ALWAYS_EMAIL', 1); //set to one to send an email even if no differences found - else only send if difference found
$subject = "Site Monitor Results";//edit email subject
$email = "YOUR_EMAIL_ADDRESS";//send email to this address
$email_reply_to = "YOUR_REPLY_TO_EMAIL_ADDRESS";//optional - can be blank - email header info
$email_from = "YOUR_FROM_EMAIL_ADDRESS";//optional - can be blank - email header info
$email_header_text = 'Site Monitor Results';//optional - can be blank - email header info
$start_dir = '/home/YOUR_USER_NAME/public_html'; //replace with your actual path - using the define from configure.php won't work on all setups
//where sitemonitor_log.php is located
$site_monitor_dir = '/home/YOUR_USER_NAME/public_html/site_monitor';
//don't check these directories - change to your liking - must be set prior to first run, if you decide to change them later, you will need to delete the ref file
$excludeList = array("admin","images","site_monitor");
// sub directories one level below the start dir that you want to exclude
$exclude_sub_dir_list = array("Pixame_v1","Helius","E-vector","espanol","german","paypal");
// link to the log file for the email message
$web_address = 'http://www.YOUR_WEB-ADDRESS.com/site_monitor/sitemonitor_log.txt';//name and http location of the log file, you can change the file name if you want
$journal = 1;// 1 means the ref file is overwrittten each time the script finds changes. 0 means the ref file is written only the first time the script is run
$keep_log = 1;//1 for keeping a log, 0 for no log
$timezone = -5; //(GMT -5:00) EST (U.S. & Canada)
$adjtime = 3600;// server time adjustment
$site_log = '/sitemonitor_log.txt';
$site_ref = '/sitemonitor_ref.txt';
/********************* END EDIT OPTIONS ************************/
$sitemonitor_log = $site_monitor_dir . $site_log;
$referenceFile = $site_monitor_dir . $site_ref;
// Start TIMER
// -----------
$stimer = explode( ' ', microtime() );
$stimer = $stimer[1] + $stimer[0];
// -----------
$headers = 'From: ' . $email_reply_to . "\r\n" . 'Reply-To: ' . $email_reply_to . "\r\n" . $email_header_text;
$ttlErrors = 0;
$error = 0;
$errorDELETED = 0;
$errorADDED = 0;
$errorSIZE = 0;
$errorTIME = 0;
$errorPERM = 0;
$msg = '';
// set def for part function
define('NAME', 0);
define('SIZE', 1);
define('TIME', 2);
define('PERM', 3);
$level=1; // level is the first level started at
$last=1; //this is set the same as level
//set arrays
$files = array();
$hold_files = array();// hold a unchanged copy of the files
$refFiles = array();
$hold_refFiles = array();//hold an unchanged copy of the ref files
clearstatcache();//start with a new stat cache
$appendfile = "a";
$writefile = "w";
$today = gmdate("l m/d/Y H:i:s", time() + $adjtime*($timezone+date("I")));
/******************Check Log File *****************/
if ($keep_log == 1){
if (! file_exists($sitemonitor_log)){
$start_log = 'New Log started on ' . $today;
$start_log .= "\n*-------------------------------------*\n";
WriteLog($sitemonitor_log, $start_log, $writefile);
if (file_exists($sitemonitor_log))
{
$msg .= DisplayMessage('Created a New Log File.');
}
else{
$msg .= DisplayMessage('Failed to create a New Log File.');
}
}
else{
$adate = ($adjtime +filemtime($sitemonitor_log));
$date_file_updated = date ("l m/d/Y H:i:s",$adate);
$msg .= DisplayMessage('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
$msg .= DisplayMessage("Log was last updated on " . $date_file_updated);
$msg .= DisplayMessage('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~');
$msg .= DisplayMessage("Sitemonitor was run on " . $today);
}
}
/************** READ IN THE FILES ****************/
CreateReferenceFile($start_dir, $level, $last, $files, $exclude_sub_dir_list);
$hold_files = $files; //hold a fresh copy of server files
/************** SAVE THE FILES OR, IF PRESENT, READ THEM IN ****************/
if (! file_exists($referenceFile))
{
if (empty($files))
$msg .= DisplayMessage('*** Reference file creation FAILED ***');
else
{
WriteFile($referenceFile, $files, $writefile);
$msg .= DisplayMessage(' Made a new Reference file on ' . $today);
}
exit;
}
else
{
$refFiles = GetReferenceFiles($referenceFile); //read in the saved file
$hold_refFiles = $refFiles;// hold a unaltered copy of ref files
$sizeA2 = count($refFiles);
/************** COVERT REF FILES TO NORMAL FILENAME ****************/
for ($i = 0; $i < $sizeA2; ++$i)
{
$refFiles[$i] = rtrim($refFiles[$i]);//remove ending white space
$pos = strpos($refFiles[$i], ",");//read the number of places up to the first comma which is the file name
$refFiles[$i] = substr($refFiles[$i], 0, $pos);//only put the file name in the array
}
}
/************** COVERT NEW FILES TO NORMAL FILENAME ****************/
$size = count($files);
for ($i = 0; $i< $size; ++$i)
{
$files[$i] = str_replace("./", "", $files[$i]);
$pos = strpos($files[$i], ",");
$files[$i] = substr($files[$i], 0, $pos);
}
/************** SEE IF THERE ARE ANY NEW FILES ****************/
$diff_added = array_diff($files, $refFiles);
if (count($diff_added) > 0)
{
foreach($diff_added as $key => $value) //can't use for loop due to keys staying constant - key 0 may not be present
{
$msg .= DisplayMessage('NEW FILE: ' . GetFileName($value));
$errorADDED++;
$ttlErrors++;
}
}
/************** SEE IF THERE ARE ANY DELETED FILES ****************/
$diff_deleted = array_diff($refFiles, $files);
if (count($diff_deleted) > 0)
{
foreach($diff_deleted as $key => $value) //can't use for loop due to keys staying constant - key 0 may not be present
{
$msg .= DisplayMessage('DELETED FILES: ' . GetFileName($value));
$errorDELETED++;
$ttlErrors++;
}
}
/************** SEE IF THE FILES HAVE CHANGED SIZE, TIME, OR PERMISSIONS ****************/
$refFiles = $hold_refFiles; //reload for all checks below
$count_files = 0;
for ($i = 0; $i < $size; ++$i)// CHECK FILES
{
if ($diff_added){if (in_array($files[$i], $diff_added)){continue;}}// ignor new added files
for ($t = 0; $t < $sizeA2; ++$t)
{
if ($diff_deleted){if (in_array($refFiles[$t], $diff_deleted)){continue;}}//ignor deleted files
if ($files[$i] === GetPart(NAME, $refFiles[$t]))
{
$count_files++;
$newSize = GetSize($files[$i]);
$oldSize = GetPart(SIZE, $refFiles[$t]);
if ($newSize != $oldSize)
{
$msg .= DisplayMessage('SIZE CHANGED: ' . GetFileName($files[$i]) . ' Now: '. $newSize . ' Was: ' . $oldSize);
$errorSIZE++;
$ttlErrors++;
}
$r = stat($files[$i]);
if ($r[9] != GetPart(TIME, $refFiles[$t]))
{
$hold_time = ($adjtime + GetPart(TIME, $refFiles[$t]));
$old_file_time = strftime ("%A, %d %b %Y %T", $hold_time);
$hold_new_time = ($adjtime + $r[9]);
$new_time = strftime ("%A, %d %b %Y %T", $hold_new_time);
$msg .= DisplayMessage('TIME CHANGED: '. GetFileName($files[$i]). ' Was: ' . $old_file_time . ' Last Changed on ' . $new_time);
$errorTIME++;
$ttlErrors++;
}
$pCurrent = substr(sprintf('%o', @fileperms($files[$i])), -3);
$pLast = GetPart(PERM, $refFiles[$t]);
if ($pCurrent != $pLast)
{
$msg .= DisplayMessage('PERMISSIONS CHANGED: '. GetFileName($files[$i]). ' Currently: "' . $pCurrent . '" was: "' . $pLast .'"');
$errorPERM++;
$ttlErrors++;
}
}
}
// }
}
$msg .= DisplayMessage('Total Number of files now being checked on the server: ' . ($count_files + $errorADDED) . ' files');
//end routine for FILES HAVE CHANGED SIZE, TIME, OR PERMISSIONS
// if we have no errors in certain areas then print a message
if ($errorDELETED == 0){
$msg .= DisplayMessage('NO DELETED FILES ...');
}
if ($errorADDED == 0){
$msg .= DisplayMessage('NO NEW FILES ...');
}
if ($errorSIZE == 0){
$msg .= DisplayMessage("NO SIZE MISMATCH ...");
}
if ($errorTIME == 0){
$msg .= DisplayMessage("NO TIME MISMATCH ...");
}
if ($errorPERM == 0){
$msg .= DisplayMessage("NO PERMISSIONS MISMATCH ...");
}
// end print messages
// End TIMER
// ---------
$etimer = explode( ' ', microtime() );
$etimer = $etimer[1] + $etimer[0];
$ourRunTime = $etimer-$stimer;
$msg .= DisplayMessage("Script timer: " . $ourRunTime . " seconds.");
// ---------
/*************** Write updated REF file and updated LOG file ******************************************/
$adate = ($adjtime +filemtime($referenceFile));
$date_file_updated = date ("l m/d/Y H:i:s",$adate);
if ($ttlErrors){
//if setup as a journal then write a new ref file
if ($journal == 1){
WriteFile($referenceFile, $hold_files, $writefile);//write a new base reference file if the old one changed
$msg .= DisplayMessage('The Reference file was last updated on ' . $date_file_updated);
}
if ($keep_log == 1){
//found errors so write a log entry
WriteLog($sitemonitor_log, $msg, $appendfile);//write log file
}
}
else{// if there aren't any changes then write to the log - no changes
$msgLOG = "\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSitemonitor was run on " . $today . "\nChecked " . $count_files . " files.\nNo changes were found.\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n";
WriteLog($sitemonitor_log, $msgLOG, $appendfile);//write log file
$msg .= DisplayMessage('The Reference file was last updated on ' . $date_file_updated);
}
/************** Mail Results *****************************************/
if ($ttlErrors || ALWAYS_EMAIL)
{
$msg .= DisplayMessage($web_address_log);
mail($email, $subject, $msg, $headers);// send email of details
if (VERBOSE)
echo 'Email sent to ' . $email;
}
/****************** FUNCTIONS **********************/
function CreateReferenceFile($dir,$level,$last,&$files,$exclude_sub_dir)
{
$dp=opendir($dir);
while (false!=($file=readdir($dp)) && $level == $last)
{
if ($file!="." && $file!="..")
{
if (ExcludeDirectory($dir))
continue;;
if (is_dir($dir."/".$file))
{
/* Skip these sub directories */
$holddir = 0;
for($i = 0; $i < count($exclude_sub_dir); $i++)
{
if ($file == $exclude_sub_dir[$i]){$holddir = 1;}
}
if ($holddir ==1){continue;}
/* End Skip these sub directories */
CreateReferenceFile($dir."/".$file,$level+1,$last+1,$files,$exclude_sub_dir); // uses recursion
}
else
{
if (strpos($file, $site_ref) == FALSE) //don't include the reference file
{
$locn = "$dir/$file";
$r = stat($locn);
$str = sprintf("%s,%d,%d,%d", $locn, $r[7], $r[9],substr(sprintf('%o', @fileperms($locn)), -3));
$files[] = $str; // reads the file into an array
}
}
}
}
closedir($dp);
}
function DisplayMessage($msg)
{
$str = $msg;
if (VERBOSE) echo $str . '<br>';
return ($str . "\n");
}
function ExcludeDirectory($dir)
{
global $excludeList;
$path = GetFileName($dir);
$parts = explode("/", $path);
return (in_array($parts[0], $excludeList));
}
function GetFileName($full_path)
{
global $start_dir;
return substr($full_path, strlen($start_dir) + 1);
}
function GetSize($path)
{
if(!is_dir($path))return filesize($path);
$dir = opendir($path);
while($file = readdir($dir))
{
if(is_file($path."/".$file))$size+=filesize($path."/".$file);
if(is_dir($path."/".$file) && $file!="." && $file !="..")$size +=get_size($path."/".$file);
}
closedir($dir);
return $size;
}
function GetPart($part, $path)
{
$parts = explode(",", $path);
return trim($parts[$part]);
}
function GetReferenceFiles($referenceFile)
{
$refFiles = "";
if (!( $refFiles = file($referenceFile)))
{
echo 'Failed to read Reference File';
exit;
}
return $refFiles;
}
function WriteFile($filename, $files, $write_mode)
{
$fpOut = fopen($filename, "$write_mode");
if (!fpOut)
{
echo 'Failed to open file '.$filename;
exit;
}
for ($idx = 0; $idx < count($files); ++$idx)
{
$str = $files[$idx]."\n";
$str = str_replace('./','',$str);
if (fwrite($fpOut, $str) == FALSE)
{
echo "Cannot write to file ($filename)";
exit;
}
}
fclose($fpOut);
}
function WriteLog($filename, $files, $write_mode)
{
$fpOut = fopen($filename, "$write_mode");
if (!fpOut)
{
echo 'Failed to open file '. $filename;
exit;
}
if (fwrite($fpOut, $files) == FALSE)
{
echo "Cannot write to file ($filename)";
exit;
}
fclose($fpOut);
}
clearstatcache();// empty the stat cache
?>
Here is the FixLogPermissions.php file
Code:
<?php
// run this script from the root using a http browser
chmod('site_monitor/sitemonitor_log.txt', 0777);
if (substr(sprintf('%o', fileperms('site_monitor/sitemonitor_log.txt')), -3) == 777){
echo 'Changed the permission on site_monitor/sitemonitor_log.txt to 777<br>';}
chmod('site_monitor/sitemonitor_ref.txt', 0777);
if (substr(sprintf('%o', fileperms('site_monitor/sitemonitor_ref.txt')), -3) == 777){
echo 'Changed the permission on site_monitor/sitemonitor_ref.txt to 777';}
?>
Added two changes 10-03