Файловый менеджер - Редактировать - /var/www/html/administrator/components/com_rsfirewall/models/check.php
Ðазад
<?php /* * @package RSFirewall! * @copyright (c) 2009 - 2024 RSJoomla! * @link https://www.rsjoomla.com/joomla-extensions/joomla-security.html * @license GNU General Public License https://www.gnu.org/licenses/gpl-3.0.en.html */ \defined('_JEXEC') or die; use Joomla\CMS\MVC\Model\BaseDatabaseModel; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Http\HttpFactory; use Joomla\Filesystem\File; use Joomla\CMS\Uri\Uri; use Joomla\CMS\Version; use Joomla\Registry\Registry; use Joomla\CMS\Date\Date; class RsfirewallModelCheck extends BaseDatabaseModel { const HASHES_DIR = '/components/com_rsfirewall/assets/hashes/'; const SIGS_DIR = '/components/com_rsfirewall/assets/sigs/'; const DICTIONARY = '/components/com_rsfirewall/assets/dictionary/passwords.txt'; const CHUNK_SIZE = 2048; protected $count = 0; protected $folders = array(); protected $files = array(); protected $limit = 0; protected $ignored = array(); protected $log = false; public function __construct($config = array()) { parent::__construct($config); // Enable logging if ($this->getConfig()->get('log_system_check') && is_writable(Factory::getApplication()->get('log_path'))) { $this->log = true; } } protected function addLogEntry($data, $error=false) { if (!$this->log) { return false; } static $path; if (!$path) { $path = Factory::getApplication()->get('log_path').'/rsfirewall.log'; } $prepend = gmdate('Y-m-d H:i:s '); if ($error) { $prepend .= '** ERROR ** '; } return file_put_contents($path, $prepend.$data."\n", FILE_APPEND); } public function getConfig() { return RSFirewallConfig::getInstance(); } protected function connect($url, $caching = true) { $cache = Factory::getCache('com_rsfirewall'); $cache->setCaching($caching); try { $response = $cache->get(array('RsfirewallModelCheck', 'connectCache'), array($url)); } catch (Exception $e) { $this->setError($e->getMessage()); return false; } return $response; } public static function connectCache($url) { $response = HttpFactory::getHttp()->get($url, array(), 30); return (object) array( 'code' => $response->code, 'body' => $response->body, 'headers' => $response->headers, ); } public function getCurrentJoomlaVersion() { return (new Version())->getShortVersion(); } protected function _loadPasswords() { static $passwords; if (is_null($passwords)) { $passwords = array(); if ($contents = file_get_contents(JPATH_ADMINISTRATOR.self::DICTIONARY)) { $passwords = $this->explode($contents); } } return $passwords; } protected function explode($string) { $string = str_replace(array("\r\n", "\r"), "\n", $string); return explode("\n", $string); } protected function checkWeakPassword($original) { $passwords = $this->_loadPasswords(); foreach ($passwords as $password) { if ($original == $password) return $password; } return false; } protected function isWindows() { static $result = null; if (!is_bool($result)) { $result = substr(PHP_OS, 0, 3) == 'WIN'; } return $result; } public function getIsWindows() { return $this->isWindows(); } public function checkJoomlaVersion() { $this->addLogEntry('System check started.'); $code = $this->getConfig()->get('code'); $current = $this->getCurrentJoomlaVersion(); $url = 'http://www.rsjoomla.com/index.php?option=com_rsfirewall_kb&task=version&version=joomla¤t='.urlencode($current).'&code='.urlencode($code); // could not connect if (!($response = $this->connect($url))) { return false; } // error response code if ($response->code != 200) { if (isset($response->headers) && is_array($response->headers) && isset($response->headers['Reason'])) { $this->setError(strip_tags($response->headers['Reason'])); return false; } $this->setError(Text::sprintf('COM_RSFIREWALL_HTTP_ERROR_RESPONSE_CODE', $response->code)); return false; } $latest = $response->body; return array($current, $latest, version_compare($current, $latest, '>=')); } public function checkRSFirewallVersion() { $code = $this->getConfig()->get('code'); $current = $this->getCurrentJoomlaVersion(); $version = new RSFirewallVersion(); $url = 'http://www.rsjoomla.com/index.php?option=com_rsfirewall_kb&task=version&version=firewall¤t='.urlencode($current).'&firewall='.urlencode((string) $version).'&code='.urlencode($code); // could not connect if (!($response = $this->connect($url))) { return false; } // error response code if ($response->code != 200) { if (isset($response->headers) && is_array($response->headers) && isset($response->headers['Reason'])) { $this->setError(strip_tags($response->headers['Reason'])); return false; } $this->setError(Text::sprintf('COM_RSFIREWALL_HTTP_ERROR_RESPONSE_CODE', $response->code)); return false; } $current = (string) $version; $latest = $response->body; return array($current, $latest, version_compare($current, $latest, '>=')); } public function checkSQLPassword() { return $this->checkWeakPassword(Factory::getApplication()->get('password')); } public function hasAdminUser() { $db = $this->getDbo(); $query = $db->getQuery(true); $query->select($db->qn('id')) ->from($db->qn('#__users')) ->where($db->qn('username').'='.$db->q('admin')) ->where($db->qn('block').'='.$db->q('0')); $db->setQuery($query); return $db->loadResult(); } public function hasFTPPassword() { return Factory::getApplication()->get('ftp_pass') != ''; } public function isSEFEnabled() { return Factory::getApplication()->get('sef') > 0; } public function buildConfiguration($overwrite = array()) { $oldConfig = new Registry(new JConfig()); if ($overwrite) { foreach ($overwrite as $key => $value) { $oldConfig->set($key, $value); } } return $oldConfig->toString('PHP', array('class' => 'JConfig', 'closingtag' => false)); } protected function getArrayString($a) { $s = 'array('; $i = 0; foreach ($a as $k => $v) { $s .= ($i) ? ', ' : ''; $s .= '"' . $k . '" => '; if (is_array($v) || is_object($v)) { $s .= $this->getArrayString((array) $v); } else { $s .= '"' . addslashes($v) . '"'; } $i++; } $s .= ')'; return $s; } public function getDisableFunctions() { return array( 'system', 'shell_exec', 'passthru', 'exec', 'popen', 'proc_open' ); } public function isConfigurationModified() { $reflector = new ReflectionClass('JConfig'); $config = $reflector->getFileName(); $contents = file_get_contents($config); $configuration = $this->buildConfiguration(); if ($contents != $configuration) { $contents = explode("\n", $contents); $configuration = explode("\n", $configuration); $diff = array_diff($contents, $configuration); return $diff; } else { return false; } } public function getPHPini() { $contents = array( 'expose_php=Off', 'allow_url_include=Off', 'disable_functions=' . implode(', ', $this->getDisableFunctions()) ); return implode("\r\n", $contents); } protected function getAdminUsers() { require_once JPATH_ADMINISTRATOR.'/components/com_rsfirewall/helpers/users.php'; return RSFirewallUsersHelper::getAdminUsers(); } public function getSessionLifetime() { return Factory::getApplication()->get('lifetime'); } public function getTemporaryFolder() { return Factory::getApplication()->get('tmp_path'); } public function getLogFolder() { return Factory::getApplication()->get('log_path'); } public function getServerSoftware() { if (preg_match('#IIS/([\d.]*)#', $_SERVER['SERVER_SOFTWARE'])) { return 'iis'; } return 'apache'; } public function getFiles($folder, $recurse=false, $sort=true, $fullpath=true, $ignore=array()) { if (!is_dir($folder)) { $this->addLogEntry("[getFiles] $folder is not a valid folder!", true); $this->setError("$folder is not a valid folder!"); return false; } $arr = array(); try { $handle = @opendir($folder); while (($file = readdir($handle)) !== false) { if ($file != '.' && $file != '..' && !in_array($file, $ignore)) { $dir = $folder . DIRECTORY_SEPARATOR . $file; if (is_file($dir)) { if ($fullpath) { $arr[] = $dir; } else { $arr[] = $file; } } elseif (is_dir($dir) && $recurse) { $arr = array_merge($arr, $this->getFiles($dir, $recurse, $sort, $fullpath, $ignore)); } } } closedir($handle); } catch (Exception $e) { $this->setError($e->getMessage()); return false; } if ($sort) { asort($arr); } return $arr; } public function getFolders($folder, $recurse=false, $sort=true, $fullpath=true) { if (!is_dir($folder)) { $this->addLogEntry("[getFolders] $folder is not a valid folder!", true); $this->setError(Text::sprintf('COM_RSFIREWALL_FOLDER_IS_NOT_A_VALID_FOLDER', $folder)); return false; } $arr = array(); try { $handle = @opendir($folder); if ($handle) { while (($file = readdir($handle)) !== false) { if ($file != '.' && $file != '..') { $dir = $folder . DIRECTORY_SEPARATOR . $file; if (is_dir($dir)) { if ($fullpath) { $arr[] = $dir; } else { $arr[] = $file; } if ($recurse) { $arr = array_merge($arr, $this->getFolders($dir, $recurse, $sort, $fullpath)); } } } } closedir($handle); } else { $this->setError(Text::sprintf('COM_RSFIREWALL_FOLDER_CANNOT_BE_OPENED', $folder)); return false; } } catch (Exception $e) { $this->setError($e->getMessage()); return false; } if ($sort) { asort($arr); } return $arr; } protected function getParent($path) { $parts = explode(DIRECTORY_SEPARATOR, $path); array_pop($parts); return implode(DIRECTORY_SEPARATOR, $parts); } protected function getAdjacentFolder($folder) { // one level up $parent = $this->getParent($folder); $folders = $this->getFolders($parent, false, false, true); if ($this->ignored['folders']) { // remove ignored folders $folders = array_diff($folders, $this->ignored['folders']); // renumber indexes $folders = array_merge(array(), $folders); } if ($folders !== false) { if (($pos = array_search($folder, $folders)) !== false) { if (isset($folders[$pos+1])) { return $folders[$pos+1]; } else { if ($parent == JPATH_SITE || $parent == '/') { // this means that there are no more folders left in the Joomla! installation // so we're done here return false; } // up again return $this->getAdjacentFolder($parent); } } } else { return false; } } protected function getAdjacentFolderFiles($folder) { if ($folder == JPATH_SITE) { return false; } // one level up $parent = $this->getParent($folder); $folders = $this->getFolders($parent, false, false, true); if ($this->ignored['folders']) { // remove ignored folders $folders = array_diff($folders, $this->ignored['folders']); // renumber indexes $folders = array_merge(array(), $folders); } if ($folders !== false) { if (($pos = array_search($folder, $folders)) !== false) { if (isset($folders[$pos+1])) { return $folders[$pos+1]; } else { if (!$this->addFiles($parent, false)) { return false; } if ($parent == JPATH_SITE || $parent == '/') { // this means that there are no more folders left in the Joomla! installation // so we're done here return false; } // up again return $this->getAdjacentFolderFiles($parent); } } } else { return false; } } public function getFoldersLimit($folder) { if (!is_dir($folder)) { $this->setError(Text::sprintf('COM_RSFIREWALL_FOLDER_IS_NOT_A_VALID_FOLDER', $folder)); return false; } try { $handle = @opendir($folder); if ($handle) { if (!is_link($folder)) { while (($file = readdir($handle)) !== false) { // check the limit if (count($this->folders) >= $this->limit) { $this->addLogEntry("[getFoldersLimit] Limit '{$this->limit}' reached!"); return true; } $dir = $folder . DIRECTORY_SEPARATOR . $file; if ($file != '.' && $file != '..' && is_dir($dir)) { // is it ignored? if so, continue if (in_array($dir, $this->ignored['folders'])) { $this->addLogEntry("[getFoldersLimit] Skipping '$dir' because it's ignored."); continue; } $this->addLogEntry("[getFoldersLimit] Adding '$dir' to array."); $this->folders[] = $dir; $this->getFoldersLimit($dir); return true; } } } closedir($handle); } else { $this->addLogEntry("[getFoldersLimit] Error opening $folder!"); } // try to find the next folder if (($dir = $this->getAdjacentFolder($folder)) !== false) { $this->addLogEntry("[getFoldersLimit] Adding adjacent '$dir' to array."); $this->folders[] = $dir; $this->getFoldersLimit($dir); } } catch (Exception $e) { $this->setError($e->getMessage()); return false; } } public function getFilesLimit($startfile) { if (is_file($startfile)) { $folder = dirname($startfile); $scan_subdirs = false; } else { $folder = $startfile; $scan_subdirs = true; } $this->addLogEntry("[getFilesLimit] Reading from '$startfile'"); try { $handle = @opendir($folder); if ($handle) { if (!is_link($folder)) { if ($scan_subdirs) { while (($file = readdir($handle)) !== false) { $path = $folder . DIRECTORY_SEPARATOR . $file; if ($file != '.' && $file != '..' && is_dir($path)) { // is it ignored? if so, continue if (in_array($path, $this->ignored['folders'])) { continue; } $this->getFilesLimit($path); return true; } } } } closedir($handle); if (!$this->addFiles($folder, is_file($startfile) ? $startfile : false)) { return true; } } else { $this->addLogEntry("[getFilesLimit] Error opening $folder!"); } // done here, try to find the next folder to parse if (($dir = $this->getAdjacentFolderFiles($folder)) !== false) { $this->getFilesLimit($dir); } } catch (Exception $e) { $this->setError($e->getMessage()); return false; } } protected function addFiles($folder, $skip_until=false) { $handle = @opendir($folder); if ($handle) { $passed = false; // no more subdirectories here, search for files while (($file = readdir($handle)) !== false) { $path = $folder . DIRECTORY_SEPARATOR . $file; if ($file != '.' && $file != '..' && is_file($path)) { // is it ignored? if so, continue if (in_array($path, $this->ignored['files'])) { $this->addLogEntry("[addFiles] Skipping '$path' because it's ignored."); continue; } if ($skip_until !== false) { if (!$passed && $path == $skip_until) { $passed = true; continue; } if (!$passed) { continue; } } if (count($this->files) >= $this->limit) { $this->addLogEntry("[addFiles] Limit '{$this->limit}' reached!"); return false; } $this->addLogEntry("[addFiles] Adding '$path' to array."); $this->files[] = $path; } } closedir($handle); return true; } } public function getAccessFile() { static $software; if (!$software) { $software = $this->getServerSoftware(); } switch ($software) { case 'apache': return '.htaccess'; break; case 'iis': return 'web.config'; break; } } public function getDefaultAccessFile() { static $software; if (!$software) { $software = $this->getServerSoftware(); } switch ($software) { case 'apache': return 'htaccess.txt'; break; case 'iis': return 'web.config.txt'; break; } } public function hasHtaccess() { $file = $this->getAccessFile(); if (file_exists(JPATH_SITE.'/'.$file)) { return true; } return false; } public function checkPHPVersion() { // According to https://www.php.net/supported-versions.php $phpSupportData = array( '5.4' => '2015-09-03', '5.5' => '2016-07-21', '5.6' => '2018-12-31', '7.0' => '2019-01-10', '7.1' => '2019-12-01', '7.2' => '2020-11-30', '7.3' => '2021-12-06', '7.4' => '2022-11-28', '8.0' => '2023-11-26', '8.1' => '2023-11-25', '8.2' => '2024-12-31', '8.3' => '2025-12-31', '8.4' => '2026-12-31', ); $supportStatus = array('status' => true, 'message' => Text::sprintf('COM_RSFIREWALL_PHP_YOU_ARE_RUNNING', PHP_VERSION)); // Check the PHP version's support status using the minor version $activePhpVersion = PHP_MAJOR_VERSION . '.' . PHP_MINOR_VERSION; if (isset($phpSupportData[$activePhpVersion])) { // First check if the version has reached end of support $today = new Date(); $phpEndOfSupport = new Date($phpSupportData[$activePhpVersion]); if ($today > $phpEndOfSupport) { $supportStatus = array('status' => false, 'message' => Text::sprintf('COM_RSFIREWALL_PHP_YOU_ARE_RUNNING_WRONG', PHP_VERSION, $phpEndOfSupport->format('Y-m-d'))); } } return $supportStatus; } public function checkGoogleSafeBrowsing(){ require_once JPATH_ADMINISTRATOR.'/components/com_rsfirewall/helpers/google-safe-browsing.php'; $check = RSFirewallGoogleSafeBrowsing::getInstance(); return $check->check(); } public function checkGoogleWebRisk(){ require_once JPATH_ADMINISTRATOR.'/components/com_rsfirewall/helpers/google-web-risk.php'; $check = RSFirewallGoogleWebRisk::getInstance(); return $check->check(); } public function getINI($name) { return ini_get($name); } public function compareINI($name, $against='1') { return $this->getINI($name) == $against; } protected function getHash($version) { $path = JPATH_ADMINISTRATOR.self::HASHES_DIR.$version.'.csv'; if (!file_exists($path)) { // Attempt to download the new hashes // Make sure we have a valid code before continuing $code = $this->getConfig()->get('code'); if (!$code || strlen($code) != 20) { throw new Exception(Text::_('COM_RSFIREWALL_CODE_FOR_HASHES')); } $url = 'http://www.rsjoomla.com/index.php?'.http_build_query(array( 'option' => 'com_rsfirewall_kb', 'task' => 'gethash', 'site' => Uri::root(), 'code' => $code, 'version' => $version )); // Connect to grab hashes (no caching) if (!($response = $this->connect($url, false))) { return false; } // Error code? if ($response->code != 200) { if (isset($response->headers) && is_array($response->headers) && isset($response->headers['Reason'])) { $reason = is_array($response->headers['Reason']) ? implode('', $response->headers['Reason']) : $response->headers['Reason']; throw new Exception(strip_tags($reason)); } throw new Exception(Text::sprintf('COM_RSFIREWALL_HTTP_ERROR_RESPONSE_CODE', $response->code)); } if (!File::write($path, $response->body)) { throw new Exception(Text::sprintf('COM_RSFIREWALL_COULD_NOT_WRITE_HASH_FILE', $path)); } // Let's find out if we need to add the hashes to the database $db = Factory::getDbo(); $query = $db->getQuery(true); $query->select('*') ->from($db->qn('#__rsfirewall_hashes')) ->where($db->qn('file').'='.$db->q('index.php')) ->where($db->qn('type').'='.$db->q($version)); if (!$db->setQuery($query)->loadObject()) { $files = array( 'plugins/user/joomla/joomla.php', 'plugins/authentication/joomla/joomla.php', 'index.php', 'administrator/index.php' ); $count = 0; if ($handle = @fopen($path, 'r')) { while (($data = fgetcsv($handle, self::CHUNK_SIZE, ',')) !== false && $count < 4) { list($file_path, $file_hash) = $data; if (in_array($file_path, $files)) { $query->clear() ->insert($db->qn('#__rsfirewall_hashes')) ->set($db->qn('file').'='.$db->q($file_path)) ->set($db->qn('hash').'='.$db->q($file_hash)) ->set($db->qn('type').'='.$db->q($version)); $db->setQuery($query)->execute(); $count++; } } fclose($handle); } else { throw new Exception(Text::sprintf('COM_RSFIREWALL_COULD_NOT_READ_HASH_FILE', $path)); } } } return $path; } protected function getMemoryLimitInBytes() { $memory_limit = $this->getINI('memory_limit'); switch (substr($memory_limit, -1)) { case 'K': $memory_limit = (int) $memory_limit * 1024; break; case 'M': $memory_limit = (int) $memory_limit * 1024 * 1024; break; case 'G': $memory_limit = (int) $memory_limit * 1024 * 1024 * 1024; break; } return $memory_limit; } protected function getIgnoredHashedFiles() { $db = $this->getDbo(); $query = $db->getQuery(true); $query->select($db->qn('file')) ->select($db->qn('hash')) ->select($db->qn('flag')) ->select($db->qn('type')) ->from($db->qn('#__rsfirewall_hashes')) ->where('('. $db->qn('type') . '=' . $db->q('ignore') . ' OR ' . $db->qn('type') . ' = ' . $db->q($this->getCurrentJoomlaVersion()) . ')'); $db->setQuery($query); $results = $db->loadObjectList('file'); $ignored = array( 'administrator/language/en-GB/en-GB.com_associations.ini', 'administrator/language/en-GB/en-GB.com_associations.sys.ini', 'administrator/language/en-GB/en-GB.com_banners.ini', 'administrator/language/en-GB/en-GB.com_banners.sys.ini', 'administrator/language/en-GB/en-GB.com_contact.ini', 'administrator/language/en-GB/en-GB.com_contact.sys.ini', 'administrator/language/en-GB/en-GB.com_contenthistory.ini', 'administrator/language/en-GB/en-GB.com_contenthistory.sys.ini', 'administrator/language/en-GB/en-GB.com_fields.ini', 'administrator/language/en-GB/en-GB.com_fields.sys.ini', 'administrator/language/en-GB/en-GB.com_finder.ini', 'administrator/language/en-GB/en-GB.com_finder.sys.ini', 'administrator/language/en-GB/en-GB.com_newsfeeds.ini', 'administrator/language/en-GB/en-GB.com_newsfeeds.sys.ini', 'administrator/language/en-GB/en-GB.com_search.ini', 'administrator/language/en-GB/en-GB.com_search.sys.ini', 'administrator/language/en-GB/en-GB.mod_feed.ini', 'administrator/language/en-GB/en-GB.mod_feed.sys.ini', 'administrator/language/en-GB/en-GB.mod_latest.ini', 'administrator/language/en-GB/en-GB.mod_latest.sys.ini', 'administrator/language/en-GB/en-GB.mod_logged.ini', 'administrator/language/en-GB/en-GB.mod_logged.sys.ini', 'administrator/language/en-GB/en-GB.mod_multilangstatus.ini', 'administrator/language/en-GB/en-GB.mod_multilangstatus.sys.ini', 'administrator/language/en-GB/en-GB.mod_popular.ini', 'administrator/language/en-GB/en-GB.mod_popular.sys.ini', 'administrator/language/en-GB/en-GB.mod_sampledata.ini', 'administrator/language/en-GB/en-GB.mod_sampledata.sys.ini', 'administrator/language/en-GB/en-GB.mod_version.ini', 'administrator/language/en-GB/en-GB.mod_version.sys.ini', 'administrator/language/en-GB/en-GB.plg_authentication_cookie.ini', 'administrator/language/en-GB/en-GB.plg_authentication_cookie.sys.ini', 'administrator/language/en-GB/en-GB.plg_authentication_gmail.ini', 'administrator/language/en-GB/en-GB.plg_authentication_gmail.sys.ini', 'administrator/language/en-GB/en-GB.plg_authentication_ldap.ini', 'administrator/language/en-GB/en-GB.plg_authentication_ldap.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_contact.ini', 'administrator/language/en-GB/en-GB.plg_content_contact.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_emailcloak.ini', 'administrator/language/en-GB/en-GB.plg_content_emailcloak.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_finder.ini', 'administrator/language/en-GB/en-GB.plg_content_finder.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_joomla.ini', 'administrator/language/en-GB/en-GB.plg_content_joomla.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_loadmodule.ini', 'administrator/language/en-GB/en-GB.plg_content_loadmodule.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_pagebreak.ini', 'administrator/language/en-GB/en-GB.plg_content_pagebreak.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_pagenavigation.ini', 'administrator/language/en-GB/en-GB.plg_content_pagenavigation.sys.ini', 'administrator/language/en-GB/en-GB.plg_content_vote.ini', 'administrator/language/en-GB/en-GB.plg_content_vote.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_article.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_article.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_contact.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_contact.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_fields.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_fields.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_image.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_image.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_menu.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_menu.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_module.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_module.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_pagebreak.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_pagebreak.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_readmore.ini', 'administrator/language/en-GB/en-GB.plg_editors-xtd_readmore.sys.ini', 'administrator/language/en-GB/en-GB.plg_editors_tinymce.ini', 'administrator/language/en-GB/en-GB.plg_editors_tinymce.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_calendar.ini', 'administrator/language/en-GB/en-GB.plg_fields_calendar.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_checkboxes.ini', 'administrator/language/en-GB/en-GB.plg_fields_checkboxes.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_color.ini', 'administrator/language/en-GB/en-GB.plg_fields_color.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_editor.ini', 'administrator/language/en-GB/en-GB.plg_fields_editor.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_imagelist.ini', 'administrator/language/en-GB/en-GB.plg_fields_imagelist.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_integer.ini', 'administrator/language/en-GB/en-GB.plg_fields_integer.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_list.ini', 'administrator/language/en-GB/en-GB.plg_fields_list.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_media.ini', 'administrator/language/en-GB/en-GB.plg_fields_media.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_radio.ini', 'administrator/language/en-GB/en-GB.plg_fields_radio.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_sql.ini', 'administrator/language/en-GB/en-GB.plg_fields_sql.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_text.ini', 'administrator/language/en-GB/en-GB.plg_fields_text.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_textarea.ini', 'administrator/language/en-GB/en-GB.plg_fields_textarea.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_url.ini', 'administrator/language/en-GB/en-GB.plg_fields_url.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_user.ini', 'administrator/language/en-GB/en-GB.plg_fields_user.sys.ini', 'administrator/language/en-GB/en-GB.plg_fields_usergrouplist.ini', 'administrator/language/en-GB/en-GB.plg_fields_usergrouplist.sys.ini', 'administrator/language/en-GB/en-GB.plg_finder_categories.ini', 'administrator/language/en-GB/en-GB.plg_finder_categories.sys.ini', 'administrator/language/en-GB/en-GB.plg_finder_contacts.ini', 'administrator/language/en-GB/en-GB.plg_finder_contacts.sys.ini', 'administrator/language/en-GB/en-GB.plg_finder_content.ini', 'administrator/language/en-GB/en-GB.plg_finder_content.sys.ini', 'administrator/language/en-GB/en-GB.plg_finder_newsfeeds.ini', 'administrator/language/en-GB/en-GB.plg_finder_newsfeeds.sys.ini', 'administrator/language/en-GB/en-GB.plg_finder_tags.ini', 'administrator/language/en-GB/en-GB.plg_finder_tags.sys.ini', 'administrator/language/en-GB/en-GB.plg_sampledata_blog.ini', 'administrator/language/en-GB/en-GB.plg_sampledata_blog.sys.ini', 'administrator/language/en-GB/en-GB.plg_search_categories.ini', 'administrator/language/en-GB/en-GB.plg_search_categories.sys.ini', 'administrator/language/en-GB/en-GB.plg_search_contacts.ini', 'administrator/language/en-GB/en-GB.plg_search_contacts.sys.ini', 'administrator/language/en-GB/en-GB.plg_search_content.ini', 'administrator/language/en-GB/en-GB.plg_search_content.sys.ini', 'administrator/language/en-GB/en-GB.plg_search_newsfeeds.ini', 'administrator/language/en-GB/en-GB.plg_search_newsfeeds.sys.ini', 'administrator/language/en-GB/en-GB.plg_search_tags.ini', 'administrator/language/en-GB/en-GB.plg_search_tags.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_debug.ini', 'administrator/language/en-GB/en-GB.plg_system_debug.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_fields.ini', 'administrator/language/en-GB/en-GB.plg_system_fields.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_highlight.ini', 'administrator/language/en-GB/en-GB.plg_system_highlight.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_languagecode.ini', 'administrator/language/en-GB/en-GB.plg_system_languagecode.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_p3p.ini', 'administrator/language/en-GB/en-GB.plg_system_p3p.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_sef.ini', 'administrator/language/en-GB/en-GB.plg_system_sef.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_stats.ini', 'administrator/language/en-GB/en-GB.plg_system_stats.sys.ini', 'administrator/language/en-GB/en-GB.plg_system_updatenotification.ini', 'administrator/language/en-GB/en-GB.plg_system_updatenotification.sys.ini', 'administrator/language/en-GB/en-GB.plg_twofactorauth_totp.ini', 'administrator/language/en-GB/en-GB.plg_twofactorauth_totp.sys.ini', 'administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.ini', 'administrator/language/en-GB/en-GB.plg_twofactorauth_yubikey.sys.ini', 'administrator/language/en-GB/en-GB.plg_user_contactcreator.ini', 'administrator/language/en-GB/en-GB.plg_user_contactcreator.sys.ini', 'administrator/language/en-GB/en-GB.plg_user_profile.ini', 'administrator/language/en-GB/en-GB.plg_user_profile.sys.ini', 'language/en-GB/en-GB.com_contact.ini', 'language/en-GB/en-GB.com_finder.ini', 'language/en-GB/en-GB.com_newsfeeds.ini', 'language/en-GB/en-GB.com_search.ini', 'language/en-GB/en-GB.mod_articles_archive.ini', 'language/en-GB/en-GB.mod_articles_archive.sys.ini', 'language/en-GB/en-GB.mod_articles_categories.ini', 'language/en-GB/en-GB.mod_articles_categories.sys.ini', 'language/en-GB/en-GB.mod_articles_category.ini', 'language/en-GB/en-GB.mod_articles_category.sys.ini', 'language/en-GB/en-GB.mod_articles_latest.ini', 'language/en-GB/en-GB.mod_articles_latest.sys.ini', 'language/en-GB/en-GB.mod_articles_news.ini', 'language/en-GB/en-GB.mod_articles_news.sys.ini', 'language/en-GB/en-GB.mod_articles_popular.ini', 'language/en-GB/en-GB.mod_articles_popular.sys.ini', 'language/en-GB/en-GB.mod_banners.ini', 'language/en-GB/en-GB.mod_banners.sys.ini', 'language/en-GB/en-GB.mod_feed.ini', 'language/en-GB/en-GB.mod_feed.sys.ini', 'language/en-GB/en-GB.mod_finder.ini', 'language/en-GB/en-GB.mod_finder.sys.ini', 'language/en-GB/en-GB.mod_footer.ini', 'language/en-GB/en-GB.mod_footer.sys.ini', 'language/en-GB/en-GB.mod_random_image.ini', 'language/en-GB/en-GB.mod_random_image.sys.ini', 'language/en-GB/en-GB.mod_related_items.ini', 'language/en-GB/en-GB.mod_related_items.sys.ini', 'language/en-GB/en-GB.mod_search.ini', 'language/en-GB/en-GB.mod_search.sys.ini', 'language/en-GB/en-GB.mod_stats.ini', 'language/en-GB/en-GB.mod_stats.sys.ini', 'language/en-GB/en-GB.mod_tags_popular.ini', 'language/en-GB/en-GB.mod_tags_popular.sys.ini', 'language/en-GB/en-GB.mod_tags_similar.ini', 'language/en-GB/en-GB.mod_tags_similar.sys.ini', 'language/en-GB/en-GB.mod_users_latest.ini', 'language/en-GB/en-GB.mod_users_latest.sys.ini', 'language/en-GB/en-GB.mod_whosonline.ini', 'language/en-GB/en-GB.mod_whosonline.sys.ini', 'language/en-GB/en-GB.mod_wrapper.ini', 'language/en-GB/en-GB.mod_wrapper.sys.ini' ); foreach ($ignored as $file) { if (!file_exists(JPATH_SITE . '/' . $file)) { $results[$file] = (object) array( 'file' => $file, 'hash' => '', 'flag' => 'M', 'type' => 'ignore' ); } } return $results; } protected function _getIgnored() { if (empty($this->ignored)) { $this->ignored = array( 'folders' => array(), 'files' => array() ); $db = $this->getDbo(); $query = $db->getQuery(true); $query->select('*') ->from($db->qn('#__rsfirewall_ignored')) ->where($db->qn('type').'='.$db->q('ignore_folder').' OR '.$db->qn('type').'='.$db->q('ignore_file')); $db->setQuery($query); $results = $db->loadObjectList(); foreach ($results as $result) { $this->ignored[$result->type == 'ignore_folder' ? 'folders' : 'files'][] = $result->path; } // False positive $this->ignored['files'][] = str_replace('/', DIRECTORY_SEPARATOR, JPATH_SITE . '/libraries/vendor/symfony/http-client-contracts/Test/Fixtures/web/index.php'); } } protected function getOptionalFolders() { return $this->getConfig()->get('optional_folders'); } public function isAlpha() { return (new Version())->isInDevelopmentState(); } public function checkHashes($start=0, $limit=300) { // version information $version = $this->getCurrentJoomlaVersion(); // Below stable? if ($this->isAlpha()) { $this->setError(Text::sprintf('COM_RSFIREWALL_NO_HASHES_FOR_ALPHA', $version)); return false; } try { if ($hash_file = $this->getHash($version)) { if ($handle = @fopen($hash_file, 'r')) { // set pointer to last value fseek($handle, $start); $result = new stdClass(); $result->wrong = array(); // files with wrong checksums $result->missing = array(); // files missing $result->fstop = 0; // the pointer (bytes) where the scanning stopped $result->size = filesize($hash_file); // the file size so that we can compute the progress $result->ignored = array(); $ignored_files = $this->getIgnoredHashedFiles(); $ignored_folders = $this->getOptionalFolders(); // memory variables $memory_limit = $this->getMemoryLimitInBytes(); $memory_usage = memory_get_usage(); // read data while (($data = fgetcsv($handle, self::CHUNK_SIZE, ',')) !== false && $limit > 0) { list($file_path, $file_hash) = $data; $full_path = JPATH_SITE.'/'.$file_path; // is it an optional folder, that might have been uninstalled? $parts = explode('/', $file_path); // this removes the filename array_pop($parts); // we do this so that subfolders are ignored as well while ($parts) { $folder = implode('/', $parts); if (in_array($folder, $ignored_folders) && !is_dir(JPATH_SITE.'/'.$folder)) { continue 2; } array_pop($parts); } // get the new hash if (isset($ignored_files[$file_path])) { // if there's an M flag this means the file should be missing if ($ignored_files[$file_path]->flag == 'M') { // we check if the file is indeed missing... if (!is_file($full_path)) { // ... and skip the hash checks continue; } // ... because if it isn't, we need to check it since the administrator might have put it back after he noticed it was missing } else { // grab the hash from the file found in the database $file_hash = $ignored_files[$file_path]->hash; } if ($ignored_files[$file_path]->type == 'ignore') { $result->ignored[] = $file_path; } } if (file_exists($full_path)) { $file_size = filesize($full_path); // let's hope the file can be read if ($memory_usage + $file_size < $memory_limit) { // does this file have a wrong checksum ? if (md5_file($full_path) != $file_hash) { $result->wrong[] = $file_path; // refresh this $memory_usage = memory_get_usage(); } } } else { $result->missing[] = $file_path; // refresh this $memory_usage = memory_get_usage(); } $limit--; } // get the current pointer $result->fstop = ftell($handle); // we're done, close fclose($handle); return $result; } else { $this->setError(Text::sprintf('COM_RSFIREWALL_COULD_NOT_READ_HASH_FILE', $hash_file)); return false; } } } catch (Exception $e) { $this->setError($e->getMessage()); return false; } $this->setError(Text::sprintf('COM_RSFIREWALL_NO_HASHES_FOUND', $version)); return false; } public function checkPermissions($path) { if (!is_readable($path)) { return false; } return substr(decoct(@fileperms($path)),-3); } public function setOffsetLimit($limit) { $this->limit = $limit; } public function getFoldersRecursive($folder) { // cache the ignored items $this->_getIgnored(); $result = $this->getFoldersLimit($folder); // something has gone wrong, tell the controller to throw an error message if ($result === false) { return false; } if ($this->folders) { // found folders... return $this->folders; } else { // this most likely means we've reached the end return true; } } public function getFilesRecursive($startfile) { // cache the ignored items $this->_getIgnored(); $this->files = array(); $result = $this->getFilesLimit($startfile); // something has gone wrong, tell the controller to throw an error message if ($result === false) { return false; } $root = JPATH_SITE; // workaround to grab the correct root if ($root == '') { $root = '/'; } // This is an exceptional case when all files are ignored from the root. if (!$this->files && dirname($startfile) == $root) { $this->files = array($this->getLastFile($root)); } // found files return $this->files; } public function _loadSignatures() { $db = $this->getDbo(); $query = $db->getQuery(true); $query->select('*') ->from($db->qn('#__rsfirewall_signatures')); $db->setQuery($query); $signatures = $db->loadObjectList(); foreach ($signatures as $signature) { $signature->signature = base64_decode($signature->signature); } // Load MD5 signatures $file = JPATH_ADMINISTRATOR . self::SIGS_DIR . '/php.csv'; if (file_exists($file) && is_readable($file) && $this->getConfig()->get('check_md5')) { $lines = file($file, FILE_IGNORE_NEW_LINES); foreach ($lines as $line) { list($hash, $desc) = explode(',', $line); $signatures[] = (object) array( 'signature' => $hash, 'type' => 'md5', 'reason' => $desc ); } } return $signatures; } protected function readableFilesize($bytes, $decimals = 2) { $size = array('B','kB','MB','GB','TB','PB','EB','ZB','YB'); $factor = floor((strlen($bytes) - 1) / 3); return sprintf("%.{$decimals}f", $bytes / pow(1024, $factor)) . @$size[$factor]; } public function checkSignatures($file, $filename = null) { static $signatures; if (!is_array($signatures)) { $signatures = $this->_loadSignatures(); } if (empty($signatures)) { throw new Exception (Text::_('COM_RSFIREWALL_NO_MALWARE_SIGNATURES')); } if ($filename === null) { $filename = $this->basename($file); } $ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION)); if ($ext == 'php') { if (!is_readable($file)) { $this->addLogEntry("[checkSignatures] Error reading '$file'.", true); $this->setError(Text::sprintf('COM_RSFIREWALL_COULD_NOT_READ_FILE', $file)); return false; } $bytes = filesize($file); // More than 512 kb if ($bytes >= 524288) { $this->addLogEntry("[checkSignatures] File '$file' is {$this->readableFilesize($bytes)}.", true); $this->setError(Text::sprintf('COM_RSFIREWALL_BIG_FILE_PLEASE_SKIP', $file, $this->readableFilesize($bytes))); return false; } $this->addLogEntry("[checkSignatures] Opening '$file' ({$this->readableFilesize($bytes)}) for reading."); $contents = file_get_contents($file); $md5 = md5($contents); } $basename = $filename; $dirname = dirname($file); foreach ($signatures as $signature) { if (strpos($signature->type, 'regex') === 0 && $ext == 'php') { $flags = str_replace('regex', '', $signature->type); if (preg_match('#'.$signature->signature.'#'.$flags, $contents, $match)) { $this->addLogEntry("[checkSignatures] Malware found ({$signature->reason})"); return array('match' => $match[0], 'reason' => $signature->reason); } } elseif ($signature->type == 'filename') { if (preg_match('#'.$signature->signature.'#i', $basename, $match)) { $this->addLogEntry("[checkSignatures] Malware found ({$signature->reason})"); return array('match' => $match[0], 'reason' => $signature->reason); } } elseif ($signature->type == 'md5' && $ext == 'php') { if ($signature->signature === $md5) { $this->addLogEntry("[checkSignatures] Malware found ({$signature->reason})"); return array('match' => $signature->signature, 'reason' => $signature->reason); } } } if ($ext == 'php') { // Checking for base64 inside index.php if (in_array(strtolower($basename), array('index.php', 'home.php'))) { if (preg_match('#base64\_decode\((.*?)\)#is', $contents, $match)) { $this->addLogEntry("[checkSignatures] Malware found (".Text::_('COM_RSFIREWALL_BASE64_IN_FILE').")"); return array('match' => $match[0], 'reason' => Text::_('COM_RSFIREWALL_BASE64_IN_FILE')); } } // Check if there are php files in root if ($dirname == JPATH_SITE) { if (!in_array($basename, array('index.php', 'configuration.php'))) { $this->addLogEntry("[checkSignatures] Malware found (".Text::_('COM_RSFIREWALL_SUSPICIOUS_FILE_IN_ROOT').")"); return array('match' => $basename, 'reason' => Text::_('COM_RSFIREWALL_SUSPICIOUS_FILE_IN_ROOT')); } } // Check if there are php files in the /images folder if (strpos($dirname, JPATH_SITE.DIRECTORY_SEPARATOR.'images') === 0) { $this->addLogEntry("[checkSignatures] Malware found (".Text::sprintf('COM_RSFIREWALL_SUSPICIOUS_FILE_IN_FOLDER', 'images').")"); return array('match' => $basename, 'reason' => Text::sprintf('COM_RSFIREWALL_SUSPICIOUS_FILE_IN_FOLDER', 'images')); } $folders = array( // site view 'components', 'templates', 'plugins', 'modules', 'language', // admin view 'administrator'.DIRECTORY_SEPARATOR.'components', 'administrator'.DIRECTORY_SEPARATOR.'templates', 'administrator'.DIRECTORY_SEPARATOR.'modules', 'administrator'.DIRECTORY_SEPARATOR.'language'); foreach ($folders as $folder) { if ($dirname == JPATH_SITE.DIRECTORY_SEPARATOR.$folder) { $this->addLogEntry("[checkSignatures] Malware found (".Text::sprintf('COM_RSFIREWALL_SUSPICIOUS_FILE_IN_FOLDER', $folder).")"); return array('match' => $basename, 'reason' => Text::sprintf('COM_RSFIREWALL_SUSPICIOUS_FILE_IN_FOLDER', $folder)); } } } else { if (preg_match('/\.php\.[a-z]{3,4}$/i', $basename)) { return array('match' => $basename, 'reason' => Text::_('COM_RSFIREWALL_SUSPICIOUS_PHP_DOUBLE_EXTENSION_FILE')); } if (substr($basename, 0, 1) == ' ') { return array('match' => $basename, 'reason' => Text::_('COM_RSFIREWALL_SUSPICIOUS_SPACE_FILE')); } $ignoredDotFiles = $this->getDotFiles(); if (substr($basename, 0, 1) == '.' && !in_array(strtolower($basename), $ignoredDotFiles) && $ext != 'yml') { return array('match' => $basename, 'reason' => Text::_('COM_RSFIREWALL_SUSPICIOUS_HIDDEN_FILE')); } } $this->addLogEntry("[checkSignatures] File $basename appears to be clean. Moving on to next..."); return false; } private function getDotFiles() { $ignoredDotFiles = (array) array_filter($this->getConfig()->get('dot_files', array(), true)); $ignoredDotFiles = array_merge($ignoredDotFiles, array('.htaccess', '.htpasswd', '.htusers', '.htgroups')); return $ignoredDotFiles; } protected function basename($filename) { $parts = explode(DIRECTORY_SEPARATOR, $filename); return end($parts); } public function getLastFile($root) { static $last_file; if (!$last_file) { // cache the ignored items $this->_getIgnored(); $files = $this->getFiles($root, false, false); // must remove ignored files if ($this->ignored['files']) { // remove ignored files $files = array_diff($files, $this->ignored['files']); // renumber indexes $files = array_merge(array(), $files); } $last_file = end($files); // this shouldn't happen if (!$files) { $last_file = $root.DIRECTORY_SEPARATOR.'index.php'; } } return $last_file; } public function getOffset() { return RSFirewallConfig::getInstance()->get('offset'); } public function saveGrade() { $grade = Factory::getApplication()->input->get('grade', '', 'int'); $this->getConfig()->set('grade', $grade); $this->getConfig()->set('system_check_last_run', Factory::getDate()->toSql(true)); $this->addLogEntry("System check finished: $grade"); } }
| ver. 1.1 | |
.
| PHP 8.4.18 | Ð“ÐµÐ½ÐµÑ€Ð°Ñ†Ð¸Ñ Ñтраницы: 0 |
proxy
|
phpinfo
|
ÐаÑтройка