Files
IPB/upload/sources/classes/class_virus_checker.php
T
2025-12-19 00:21:15 -08:00

469 lines
15 KiB
PHP

<?php
/*
+--------------------------------------------------------------------------
| Invision Power Board 2.1.7
| =============================================
| by Matthew Mecham
| (c) 2001 - 2005 Invision Power Services, Inc.
| http://www.invisionpower.com
| =============================================
| Web: http://www.invisionboard.com
| http://www.ibresource.ru/products/invisionpowerboard/
| Time: Tuesday 18th of July 2006 05:56:00 PM
| Release: 52f408a29988b02f45b5e6f4ba5af0ae
| Licence Info: http://www.invisionboard.com/?license
| http://www.ibresource.ru/license
+---------------------------------------------------------------------------
| INVISION POWER BOARD IS NOT FREE / OPEN SOURCE!
+---------------------------------------------------------------------------
| INVISION POWER BOARD ÍÅ ßÂËßÅÒÑß ÁÅÑÏËÀÒÍÛÌ ÏÐÎÃÐÀÌÌÍÛÌ ÎÁÅÑÏÅ×ÅÍÈÅÌ!
| Ïðàâà íà ÏÎ ïðèíàäëåæàò Invision Power Services
| Ïðàâà íà ïåðåâîä IBResource (http://www.ibresource.ru)
+---------------------------------------------------------------------------
| > $Date: 2006-06-23 10:44:15 +0100 (Fri, 23 Jun 2006) $
| > $Revision: 338 $
| > $Author: matt $
+---------------------------------------------------------------------------
|
| > Virus Checker CLASS
| > Module written by Brandon Farber / Matt Mecham
| > Date started: Monday 3rd July 2006
|
| > Module Version Number: 1.0.0
| > DBA Checked: Wed 19 May 2004
+--------------------------------------------------------------------------
*/
class class_virus_checker
{
/**
* Global
*/
var $ipsclass;
/**
* Directory separator
*/
var $dir_split = "/";
/**
* Dodgy files
* @var array [ idx ] = ( file_path, file_name );
*/
var $bad_files = array ();
/**
* Checked folders
*/
var $checked_folders = array ();
/**
* Known names
*/
var $known_names = array ();
/*-------------------------------------------------------------------------*/
// CONSTRUCTAA
/*-------------------------------------------------------------------------*/
function class_virus_checker()
{
set_time_limit(0);
if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN')
{
$this->dir_split = "\\";
}
//-----------------------------------------
// Known names
//-----------------------------------------
require (ROOT_PATH.'sources/classes/class_virus_checker/lib_known_names.php');
$this->known_names = $KNOWN_NAMES;
}
/*-------------------------------------------------------------------------*/
// Run the scan
/*-------------------------------------------------------------------------*/
/**
* Runs the scan
* All suspicious files are entered into
* $this->bad_files array
*/
function run_scan()
{
//-----------------------------------------
// INIT
//-----------------------------------------
$expected = array ();
$root_dir = preg_replace("#^(.+?)\/$#", "\\1", ROOT_PATH);
$skin_dirs = array ();
//-----------------------------------------
// Load extra db cache file
//-----------------------------------------
$this->ipsclass->DB->load_cache_file(ROOT_PATH.'sources/sql/'.SQL_DRIVER.'_extra_queries.php', 'sql_extra_queries');
//-----------------------------------------
// Get libs
//-----------------------------------------
require (ROOT_PATH.'sources/classes/class_virus_checker/lib_writeable_dirs.php');
require (ROOT_PATH.'sources/classes/class_virus_checker/lib_lang_files.php');
//-----------------------------------------
// Sort out directory separator
//-----------------------------------------
if ($this->dir_split != '/')
{
$_WRITEABLE_DIRS = $WRITEABLE_DIRS;
$WRITEABLE_DIRS = array ();
foreach ($_WRITEABLE_DIRS as $dir)
{
$WRITEABLE_DIRS[] = str_replace('/', $this->dir_split, $dir);
}
}
//-----------------------------------------
// Get language directories
//-----------------------------------------
if (isset ($this->ipsclass->cache['languages']) AND is_array($this->ipsclass->cache['languages']) && count($this->ipsclass->cache['languages']))
{
foreach ($this->ipsclass->cache['languages'] as $v)
{
$WRITEABLE_DIRS[] = 'cache'.$this->dir_split.'lang_cache'.$this->dir_split.$v['ldir'];
foreach ($LANG_FILES as $filename)
{
$expected[] = 'cache'.$this->dir_split.'lang_cache'.$this->dir_split.$v['ldir'].$this->dir_split.$filename.'.php';
}
}
}
else
{
$this->ipsclass->DB->build_query(array ('select' => 'ldir', 'from' => 'languages'));
$this->ipsclass->DB->exec_query();
while ($v = $this->ipsclass->DB->fetch_row())
{
$WRITEABLE_DIRS[] = 'cache'.$this->dir_split.'lang_cache'.$this->dir_split.$v['ldir'];
foreach ($LANG_FILES as $filename)
{
$expected[] = 'cache'.$this->dir_split.'lang_cache'.$this->dir_split.$v['ldir'].$this->dir_split.$filename.'.php';
}
}
}
//-----------------------------------------
// Get skin directories
//-----------------------------------------
if (is_array($this->ipsclass->cache['skin_id_cache']) && count($this->ipsclass->cache['skin_id_cache']))
{
foreach ($this->ipsclass->cache['skin_id_cache'] as $k => $v)
{
if ($k == 1 && !IN_DEV)
{
continue;
}
$WRITEABLE_DIRS[] = 'cache'.$this->dir_split.'skin_cache'.$this->dir_split.'cacheid_'.$v['set_skin_set_id'];
$skin_dirs[] = $v['set_skin_set_id'];
}
}
else
{
$this->ipsclass->DB->build_query(array ('select' => 'set_skin_set_id', 'from' => 'skin_sets'));
$this->ipsclass->DB->exec_query();
while ($v = $this->ipsclass->DB->fetch_row())
{
$WRITEABLE_DIRS[] = 'cache'.$this->dir_split.'skin_cache'.$this->dir_split.'cacheid_'.$v['set_skin_set_id '];
$skin_dirs[] = $v['set_skin_set_id'];
}
}
//-----------------------------------------
// Get skin files
//-----------------------------------------
$this->ipsclass->DB->cache_add_query('diag_distinct_skins', array (), 'sql_extra_queries');
$this->ipsclass->DB->cache_exec_query();
while ($v = $this->ipsclass->DB->fetch_row())
{
foreach ($skin_dirs as $dir)
{
$expected[] = 'cache'.$this->dir_split.'skin_cache'.$this->dir_split.'cacheid_'.$dir.$this->dir_split.$v['group_name'].'.php';
}
}
//-----------------------------------------
// Alright, do it!
//-----------------------------------------
$WRITEABLE_DIRS = array_unique($WRITEABLE_DIRS);
foreach ($WRITEABLE_DIRS as $dir_to_check)
{
if ($dir_to_check == 'uploads' OR $dir_to_check == 'style_emoticons')
{
# Leave this 'til later
continue;
}
if (file_exists($root_dir.$this->dir_split.$dir_to_check))
{
$this->checked_folders[] = $root_dir.$this->dir_split.$dir_to_check;
$dh = opendir($root_dir.$this->dir_split.$dir_to_check);
while (false !== ($file = readdir($dh)))
{
if (preg_match("#.*\.(php|js|html|htm|cgi|pl|perl|php3|php4|php5|php6)$#i", $file))
{
if (!in_array($dir_to_check.$this->dir_split.$file, $expected) AND $file != "index.html" AND $file != 'lang_javascript.js')
{
$score = intval($this->score_file($root_dir.$this->dir_split.$dir_to_check.$this->dir_split.$file));
$this->bad_files[] = array ('file_path' => $root_dir.$this->dir_split.$dir_to_check.$this->dir_split.$file, 'file_name' => $file, 'score' => $score);
}
}
}
@ closedir($dh);
}
}
//-----------------------------------------
// Check 'blog' dir
//-----------------------------------------
if (file_exists($root_dir.$this->dir_split.'blog'))
{
$this->anti_virus_deep_scan($root_dir.$this->dir_split.'blog', 'all', array ('index.php'));
}
//-----------------------------------------
// Check 'html' dir
//-----------------------------------------
if (file_exists($root_dir.$this->dir_split.'html'))
{
$this->anti_virus_deep_scan($root_dir.$this->dir_split.'html', 'all', array ('index.php'));
}
//-----------------------------------------
// Check 'Skin' dir
//-----------------------------------------
if (file_exists($root_dir.$this->dir_split.'Skin'))
{
$this->anti_virus_deep_scan($root_dir.$this->dir_split.'Skin', 'all');
}
//-----------------------------------------
// Check emoticons
//-----------------------------------------
$this->anti_virus_deep_scan($root_dir.$this->dir_split.'style_emoticons', 'all');
//-----------------------------------------
// Check image directories
//-----------------------------------------
$this->anti_virus_deep_scan($root_dir.$this->dir_split.'style_images', '(php|cgi|pl|perl|php3|php4|php5|php6)');
//-----------------------------------------
// Check upload directories
//-----------------------------------------
$this->anti_virus_deep_scan($root_dir.$this->dir_split.'uploads');
}
/*-------------------------------------------------------------------------*/
// Score a file
/*-------------------------------------------------------------------------*/
/**
* Score a file
*
* Return a score from 0 being harmless to 10 being, well the complete opposite to harmless.
*
* Score information:
* Name 3 chars or less + 2
* '- Name 2 chars or less + 4
* Size over 65k + 3
* '- Size over 100k + 4
* User nobody + 3
* Modified in the 30 days + 1
* In non PHP folder + 3
*
* @param string Full file path and name
* @param array stat info
*
* @return int Score (0 - 10 )
*/
function score_file($file_name, $stat = array ())
{
//-----------------------------------------
// INIT
//-----------------------------------------
$SCORE = 0;
$name = preg_replace("#^(.*)/(.+?)$#is", "\\2", $file_name);
$name_sans_ext = preg_replace("#^(.*)\.(.+?)$#si", "\\1", $name);
//-----------------------------------------
// Check
//-----------------------------------------
if (!$file_name)
{
return -1;
}
if (!is_array($stat) OR !count($stat))
{
$stat = stat($file_name);
}
//-----------------------------------------
// Alright...
//-----------------------------------------
if (in_array($file_name, $this->known_names))
{
$SCORE += 7;
}
//-----------------------------------------
// User nobody?
//-----------------------------------------
if ($stat['uid'] == 99)
{
$SCORE += 3;
}
if (strlen($name_sans_ext) < 3)
{
$SCORE += 4;
}
else
if ($name_sans_ext == 'temp' OR $name_sans_ext == 'test')
{
$SCORE += 2;
}
else
if (strlen($name_sans_ext) < 4)
{
$SCORE += 2;
}
//-----------------------------------------
// Size
//-----------------------------------------
if ($stat['size'] > 100 * 1024)
{
$SCORE += 4;
}
else
if ($stat['size'] > 65 * 1024)
{
$SCORE += 3;
}
//-----------------------------------------
// Last modified...
//-----------------------------------------
if ($stat['mtime'] > time() - 86400 * 30)
{
$SCORE += 1;
}
//-----------------------------------------
// Non PHP folder...
//-----------------------------------------
if (preg_match("#(?:style_images|style_emoticons|uploads|style_avatars|default|1|skin_acp|html|skin)/#i", $file_name))
{
$SCORE += 3;
}
//-----------------------------------------
// Return
//-----------------------------------------
return $SCORE > 10 ? 10 : $SCORE;
}
/*-------------------------------------------------------------------------*/
// Deep scan
/*-------------------------------------------------------------------------*/
/**
* Deep scan
*
* All suspicious files are entered into
* $this->bad_files array
*/
function anti_virus_deep_scan($dir, $look_for = '(php|js|html|htm|cgi|pl|perl|php3|php4|php5|php6)', $ignore_files = array ())
{
//-----------------------------------------
// Short-hand
//-----------------------------------------
if ($look_for == 'all')
{
$look_for = '(php|js|html|htm|cgi|pl|perl|php3|php4|php5|php6)';
}
//-----------------------------------------
// Add into checked folders
//-----------------------------------------
$this->checked_folders[] = $dir.$this->dir_split.$file;
$dh = opendir($dir);
while (false !== ($file = readdir($dh)))
{
if ($file == '.' or $file == '..' or $file == '.svn' or $file == '.DS_store' or $file == 'index.html')
{
continue;
}
if (is_dir($dir.$this->dir_split.$file))
{
$this->anti_virus_deep_scan($dir.$this->dir_split.$file, $look_for);
}
else
{
if (in_array($dir.$this->dir_split.$file, $ignore_files))
{
continue;
}
if (preg_match("#^(.*)?\.".$look_for."$#i", $file))
{
$score = intval($this->score_file($dir.$this->dir_split.$file));
$this->bad_files[] = array ('file_path' => $dir.$this->dir_split.$file, 'file_name' => $file, 'score' => $score);
}
}
}
}
}
?>