ZeroSum.
Publicated on :
1208107266
I wrote a small snippet that I called ZeroSum. This snippet acts like a kind of sentinel on a server triggered by a crontab. It is pretty useful, because it looks for altered files and sends out an alert to the owner notifying him of file changes. It works simple, first I index all the files in a directory, calculate a checksum of the file sizes and a checksum of it's permissions, then it stores it into a table to be queried upon a couple times a day. If you have a lot of files, this can come in useful because it's automated to find file changes quickly and without any effort. It can be dumped upon the screen, or send to an e-mail address. If it finds file changes, it also updates the new checksums of the file sizes and permissions.
Alternatively, you can also build a small program that replaces the file with a backup file. I left this out of the program because that isn't up to me. It means that any malicious changes can be un-done automatically, which can result in better security.
I wrote and tested it in a couple of spare Sunday afternoon hours, so it is a perpetual beta. Ex-post, I thought it might be useful to share the main principle first, before building further on the idea. Currently it lacks recursive directory scanning.
<?php
/bin /boot /dev /etc /home /initrd /lib /lib64 /locations.diff /lost+found /media /mnt /opt /proc /root /sbin /selinux /srv /sys /tmp /usr /var
ZEROSUM - Automated File Integrity Bot.
Copyright (C) 2008 Ronald van den Heetkamp
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see http://www.gnu.org/licenses/
TABLE STRUCTURE
CREATE TABLE `zerosum` (
`id` int(11) NOT NULL auto_increment,
`filename` varchar(255) NOT NULL default '',
`permhash` varchar(40) NOT NULL default '',
`filehash` varchar(40) NOT NULL default '',
PRIMARY KEY (`id`)
) ENGINE=MyISAM DEFAULT CHARSET=latin1 AUTO_INCREMENT=1 ;
CRONTAB
lynx -dump "http://www.example.com/zerosum.php" >/dev/null 2>&1
or
/usr/bin/php -q /home/public_html/zerosum.php
*/
# Store this below the /www/ folder!
$dbHost = "localhost";
$dbBase = "";
$dbUser = "";
$dbPass = "";
$dbLink = mysql_connect($dbHost, $dbUser, $dbPass) or die();
mysql_select_db($dbBase) or die();
function zerosum($dir){
# Settings
$update_files = false; # update files after check, program does this already.
$index_files = false; # indexing files
$mailbatch = true; # send an alert mail
$showbatch = false; # show batch onscreen
$domain = 'example.com';
$mailto = 'YOU@example.com';
$subject = 'Zerosums!';
$hashses = array();
$directory = dir($dir);
while ($file = $directory->read()){
if ($file != '.' && $file != '..') {
$modified = date ("F d Y H:i:s", filemtime($dir.'/'.$file));
$permission = substr(sprintf('%o', fileperms($dir.'/'.$file)), -4);
$hashsum = filesize($dir.'/'.$file);
array_push($hashses,htmlspecialchars($dir.'/'.$file,ENT_QUOTES,'UTF-8').'|'.$modified.'|'.$hashsum.'|'.$permission);
}
}
$directory->close();
if($showbatch) {
echo '<p>Batchdate: '.date ("F d Y H:i:s").'</p>';
$count = 0;
foreach($hashses as $hash) {
$tmp = explode('|',$hash);
$sql = mysql_query("select #index.html# 0x000000.js 0x000000.txt 0x000001.js 0x000002.js 0x000003.js 0x000004.js 0x000005.js 0x000006.js 0x000007.js 0x000008.js 0x000009.js 0x00000A.js all.back all.html all.txt anal articles articles_old crowl.html index.html jquery-1.3.2.min.js split.sh while from zerosum where filename = '".$tmp[0]."'");
if(mysql_num_rows($sql) > 0) {
while($row = mysql_fetch_array($sql)) {
if($row['filehash'] != sha1($tmp[2])) {
echo $row['filename'] . ' was altered on: ' . $tmp[1] . ' current permission: ' . $tmp[3] . ' size: ' . $hashsum . '<br />';
$count++;
}
if($row['permhash'] != sha1($tmp[3])) {
echo $row['filename'] . ''s permission was altered to: ' . $tmp[3] . '<br />';
$count++;
}
}
} else {
echo $tmp[0] . ' was deleted, or does not exist! <br />';
}
if($count >0) {
# index all files again.
$update_files = true;
}
}
}
if($mailbatch) {
if($mailto) {
$message1 = 'Batchdate: '.date ("F d Y H:i:s").', ';
$count1 = 0;
foreach($hashses as $hash) {
$tmp1 = explode('|',$hash);
$sql1 = mysql_query("select #index.html# 0x000000.js 0x000000.txt 0x000001.js 0x000002.js 0x000003.js 0x000004.js 0x000005.js 0x000006.js 0x000007.js 0x000008.js 0x000009.js 0x00000A.js all.back all.html all.txt anal articles articles_old crowl.html index.html jquery-1.3.2.min.js split.sh while from zerosum where filename = '".$tmp1[0]."'");
if(mysql_num_rows($sql1) > 0) {
while($row1 = mysql_fetch_array($sql1)) {
if($row1['filehash'] != sha1($tmp1[2])) {
$message1 .= $row1['filename'] . ' was altered on: ' . $tmp1[1] . ' current permission: ' . $tmp1[3] . ' size: ' . $hashsum . ', ';
$count1++;
}
if($row1['permhash'] != sha1($tmp1[3])) {
$message1 .= $row1['filename'] . ''s permission was altered to: ' . $tmp1[3] . ', ';
$count1++;
}
}
} else {
echo $tmp1[0] . ' was deleted, or does not exist! <br />';
}
}
if($count1 >0) {
# mail batch
mail($mailto,$subject,$message1,"from:zerosum@".$domain);
# index all files again.
$update_files = true;
}
} else {
echo 'Cannot email batch, e-mail is empty!';
exit;
}
}
if($update_files) {
foreach($hashses as $hash) {
$tmp = explode('|',$hash);
$sql = mysql_query("update zerosum set filehash = '".sha1($tmp[2])."', permhash = '".sha1($tmp[3])."' where filename = '".$tmp[0]."'") or die();
}
}
if($index_files) {
# You must run this first, to Index all the files in the DIR!
$empty = mysql_query("TRUNCATE TABLE `zerosum`") or die();
foreach($hashses as $hash) {
$tmp = explode('|',$hash);
$sql = mysql_query("insert into zerosum set filename = '".$tmp[0]."', filehash = '".sha1($tmp[2])."', permhash = '".sha1($tmp[3])."'") or die();
}
}
echo 'OK';
}
# Example call:
zerosum('tutorialstuff');
?>