public function onAfterInitialise($args = array()) { //Are we enabled? if (!$this->params->get('enabled', 1)) { return 0; } //DB item. $db = JFactory::getDbo(); $this->add_log('JHackGuard initialised', 'debug'); /* Maintenance steps start */ $probability = rand(0, 100); //Clear the expired logs (probability of running 10%) if ($probability < 11) { $days = (int) $this->params->get('log_garbage_collection', 7); if (!$days) { $days = 7; } $query = $db->getQuery(true); $query->delete($db->quoteName('#__jhackguard_logs')); $query->where($db->quoteName('time') . ' < DATE_SUB(CURRENT_DATE, INTERVAL ' . $days . ' DAY)'); $db->setQuery($query); $db->query(); $this->add_log('Logs garbage collector ran.', 'debug'); } //Clear the expired IP address filters (probability: 60%) if ($probability < 61) { $query = $db->getQuery(true); $query->delete($db->quoteName('#__jhackguard_ip_filters')); $query->where($db->quoteName('expires') . ' BETWEEN DATE_SUB(CURRENT_DATE, INTERVAL 36500 DAY) AND DATE_SUB(CURRENT_DATE, INTERVAL 1 DAY)'); $db->setQuery($query); $db->query(); $this->add_log('IP filters garbage collector ran.', 'debug'); } /* Maintenance steps end */ /* Whitelisted Groups Check */ $user = JFactory::getUser(); $whg = $this->params->get('whitelisted_groups', array()); foreach ($user->groups as $g) { if (in_array($g, $whg)) { $this->add_log('JHackGuard execution stopped because user group is whitelisted.', 'debug'); return 0; } } /* IP black/white listing check */ if ($this->ip_is('whitelisted')) { //Cease further processing $this->add_log('Encountered whitelisted IP', 'debug'); return 0; } if ($this->ip_is('blacklisted')) { $this->add_log('Found blacklisted IP address. Script terminated.', 'standard'); die(include_once JPATH_ADMINISTRATOR . '/components/com_jhackguard/blocked.html'); } /* Administrator secret key addon */ if ($this->params->get('admin_protection', 0)) { //Verify we have a secret word setup in the configuration. if (strlen($this->params->get('admin_keyword', '')) < 1) { $this->add_log('Administrator folder protection enabled but no keyword found.', 'debug'); } else { //Check if the current page is in the administrator area. if (JFactory::getApplication()->isAdmin() and JFactory::getUser()->guest) { if (is_array($_POST) and isset($_POST['option']) and $_POST['option'] == "com_login" and isset($_POST['task']) and $_POST['task'] == "login") { //This is post login processing script and we do not want to filter it. //TODO: check if we have actually came from a login page. //Probably CSRF token would do the trick here. } else { if (!array_key_exists($this->params->get('admin_keyword', ''), $_GET)) { //We have no secret word added to the URL. Redirecting to main page. $this->add_log('No admin keyword found in request to administrator folder. Redirecting to main page. ', 'debug'); header("Location: " . JURI::base() . ".."); die; } } } } } /* Administrator secret word checks end */ /* Filter Administrator panel, jHackGuard pages. We do not want to filter our own content, after all */ if (JFactory::getApplication()->isAdmin() and !JFactory::getUser()->guest) { if (isset($_REQUEST['option']) and $_REQUEST['option'] == "com_jhackguard") { $this->add_log('Admin page com_jhackguard is whitelisted. Filters skipped.', 'debug'); return 0; } } /* Input filters Start */ if (file_exists(JPATH_ADMINISTRATOR . '/components/com_jhackguard/data/input_rules.php') and !file_exists(JPATH_ADMINISTRATOR . '/components/com_jhackguard/data/.disable_input_rules')) { require_once JPATH_ADMINISTRATOR . '/components/com_jhackguard/data/input_rules.php'; if (class_exists('JHackGuard_Input_Filters')) { $rules = new JHackGuard_Input_Filters(); $rules->run(); } else { $this->add_log('Cannot locate JHackGuard_Input_Filters class in data/input_rules.php. Perhaps no rules have been defined yet.', 'debug'); } } else { $this->add_log('No input filters found or .disable_input_rules was defined.', 'debug'); } /* End of Input filters */ /* Scan through or disable the upload files, if configured */ if ($this->params->get('disable_uploads', 0)) { if (is_array($_FILES) and count($_FILES) > 0) { JFactory::getApplication()->enqueueMessage("File upload denied by JHackGuard.", "warning"); $_FILES = array(); //TADAAA. This is not OK. We should probably delete the tmp files. } } //Scan using or own rules. if ($this->params->get('scan_uploads', 1)) { if (is_array($_FILES) and count($_FILES) > 0 and is_readable(JPATH_ADMINISTRATOR . '/components/com_jhackguard/data/scans/rules.php')) { foreach ($_FILES as $key => $file) { $hit = 0; if (isset($file['tmp_name'])) { if (is_array($file['tmp_name'])) { foreach ($file['tmp_name'] as $tmp_file) { include_once JPATH_ADMINISTRATOR . '/components/com_jhackguard/data/scans/rules.php'; $it = new SplFileInfo($tmp_file); if ($it->isFile() and $it->isReadable()) { $s = new JHackGuard_OnDemand_Scan_Rules(); $s->scan($it); if ($s->score > 99) { $hit = 1; JFactory::getApplication()->enqueueMessage("File upload denied by JHackGuard. Internal scan hit.", "warning"); $this->add_log('Possible malicious file upload (score:' . $s->score . ').File deleted.', 'standard'); } else { $this->add_log('Clean file upload (score:' . $s->score . ').', 'debug'); } } } } } //Do we have a hit? if ($hit) { unset($_FILES[$key]); } } //End foreach in $_FILES } } //End if scan_uploads //Scan using CYMRU Malware Hash Registry. if ($this->params->get('use_cymru', 1)) { if (is_array($_FILES) and count($_FILES) > 0) { foreach ($_FILES as $key => $file) { $hit = 0; if (isset($file['tmp_name'])) { if (is_array($file['tmp_name'])) { foreach ($file['tmp_name'] as $tmp_file) { if ($tmp_file != NULL) { $hash = md5_file($tmp_file); if (checkdnsrr($hash . ".malware.hash.cymru.com", "A")) { JFactory::getApplication()->enqueueMessage("File upload denied by JHackGuard. Cymru malware hash database hit.", "warning"); $this->add_log('Possible malicious file upload (CYMRU Hash DB Hit).File deleted.', 'standard'); $hit = 1; } } } } } //Do we have a hit? if ($hit) { unset($_FILES[$key]); } } //End foreach in $_FILES } } //End if use_cymru option. //END OF UPLOADED FILES CHECKS }
public function scan_files() { $dir = JPATH_ROOT; $id = 0; $maxFiles = 100; $start = 0; /* Files to be ignored by the scanner */ $ignoreFiles = array(JPATH_ROOT . '/libraries/phpmailer/smtp.php', JPATH_ROOT . '/libraries/joomla/microdata/types.json', JPATH_ROOT . '/administrator/components/com_jhackguard/data/input_rules.php', JPATH_ROOT . '/administrator/components/com_jhackguard/data/backups/input_rules.backup.php', JPATH_ROOT . '/administrator/components/com_jhackguard/data/temp_rules.php', JPATH_ROOT . '/administrator/components/com_jhackguard/data/scans/rules.php', JPATH_ROOT . '/media/editors/codemirror/js/php.js', JPATH_ROOT . '/media/editors/tinymce/tinymce.min.js'); if (isset($_POST['maxFiles'])) { $maxFiles = (int) $_POST['maxFiles']; if ($maxFiles == 0) { $maxFiles = 100; } } if (isset($_POST['startFrom'])) { $start = (int) $_POST['startFrom']; } if (isset($_POST['id']) and strlen($_POST['id']) > 0) { $id = (int) $_POST['id']; } else { echo json_encode(array("success" => false, "msg" => "Missing request id value.")); return false; } chdir(JPATH_ROOT); //Rules file, verified by a previous AJAX call. TODO: verify it exists anyway... include_once JPATH_ADMINISTRATOR . '/components/com_jhackguard/data/scans/rules.php'; //Hits, if any, will be written here $hits = array(); //DB stuff.. $db = JFactory::getDbo(); // Create a new query object. $query = $db->getQuery(true); $query->select("DISTINCT (" . $db->quoteName('fname') . ")"); $query->from($db->quoteName('#__jhackguard_scan_files')); $query->order('id ASC'); $db->setQuery($query, $start, $maxFiles); $list = $db->loadObjectList(); foreach ($list as $file) { //Check if file is to be ignored. if (in_array($file->fname, $ignoreFiles)) { continue; } //Not an ignored file.Continue checking... $it = new SplFileInfo($file->fname); if ($it->isFile() and $it->isReadable()) { $s = new JHackGuard_OnDemand_Scan_Rules(); $s->scan($it); if ($s->score > 99) { $hits[] = array('filename' => $file->fname, 'score' => $s->score, 'details' => $s->explain); } } } //We should insert the hits now, if any. if (count($hits) > 0) { $db = JFactory::getDbo(); $query = $db->getQuery(true); $query->insert($db->quoteName('#__jhackguard_scan_hits')); $query->columns('fname, score, details, scan_id'); foreach ($hits as $hit) { $ins = array($db->quote($hit['filename']), $db->quote($hit['score']), $db->quote(serialize($hit['details'])), $db->quote($id)); $query->values(implode(',', $ins)); } $db->setQuery($query); $db->query(); } //Shall we continue? if (count($list) < $maxFiles) { $continue = false; //Seems like results from db were less than the max files. } else { $continue = true; } echo json_encode(array("success" => true, "continue" => $continue, "totalChecked" => count($list))); }