|
Server : Apache/2.4.18 (Ubuntu) System : Linux canvaswebdesign 3.13.0-71-generic #114-Ubuntu SMP Tue Dec 1 02:34:22 UTC 2015 x86_64 User : oppastar ( 1041) PHP Version : 7.0.33-0ubuntu0.16.04.15 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority, Directory : /var/www/andreassugianto.com/public_html/plugins/system/admintools/admintools/ |
Upload File : |
<?php
/*
* Administrator Tools
* Copyright (C) 2010-2013 Nicholas K. Dionysopoulos / AkeebaBackup.com
*
* 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/>.
*/
defined('_JEXEC') or die();
// Compatibility with @securejoomla audit service
if (defined('_BF_AUDIT'))
return;
JLoader::import('joomla.application.plugin');
class plgSystemAdmintoolsPro extends JPlugin
{
private $cparams = null;
private $hasGeoIPPECL = false;
private $exceptions = array();
private $skipFiltering = false;
private $timestamps = array();
public function __construct(& $subject, $config = array())
{
JLoader::import('joomla.html.parameter');
JLoader::import('joomla.plugin.helper');
JLoader::import('joomla.application.component.helper');
$plugin = JPluginHelper::getPlugin('system', 'admintools');
$defaultConfig = (array) ($plugin);
$config = array_merge($defaultConfig, $config);
// Use the parent constructor to create the plugin object
parent::__construct($subject, $config);
// Work around non-transparent proxy and reverse proxy IP issues
include_once JPATH_ADMINISTRATOR . '/components/com_admintools/helpers/ip.php';
if (class_exists('AdmintoolsHelperIp', false))
{
AdmintoolsHelperIp::workaroundIPIssues();
}
// Load the components parameters
JLoader::import('joomla.application.component.model');
require_once JPATH_ROOT . '/administrator/components/com_admintools/models/storage.php';
if (interface_exists('JModel'))
{
$this->cparams = JModelLegacy::getInstance('Storage', 'AdmintoolsModel');
}
else
{
$this->cparams = JModel::getInstance('Storage', 'AdmintoolsModel');
}
// Check if the GeoIP PECL extension is loaded, otherwise load the
// PHP-based implementation of the library.
if (@file_exists(JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'geoip' . DIRECTORY_SEPARATOR . 'GeoIP.dat'))
{
if (!function_exists('geoip_country_code_by_name'))
{
require_once JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'geoip.php';
$this->hasGeoIPPECL = false;
}
else
{
$this->hasGeoIPPECL = true;
}
}
// Load WAF exceptions
$this->loadExceptions();
if (empty($this->exceptions))
{
$this->exceptions = array();
}
else
{
if (empty($this->exceptions[0]))
{
$this->skipFiltering = true;
}
}
}
/**
* Log a security exception coming from a third party application. It's
* supposed to be used by 3PD to log security exceptions in Admin Tools'
* log.
*
* @param string $message The blocking reason to show to the administrator. MANDATORY.
* @param string $message The message to show to the user being blocked. MANDATORY.
* @param array $extraInfo Any extra information to record to the log file (hash array).
* @param boolean $autoban Should we also auto-ban this IP immediately?
*
* @return void
*/
public function onAdminToolsThirdpartyException($reason, $message, $extraInfo = array(), $autoban = false)
{
if (empty($message))
{
return;
}
// Block the request
$this->blockRequest('external', $message, $extraInfo, $reason);
// Automatically ban the IP if auto IP banning is enabled and the $autoban flag is set
$autobanipenabled = $this->cparams->getValue('tsrenable', 0);
if ($autobanipenabled && $autoban)
{
$this->autoBan('external');
}
}
/**
* Hooks to the onAfterInitialize system event, the first time in the
* Joomla! page load workflow which fires a plug-in event
*/
public function onAfterInitialise()
{
// Automatic banning
$this->AutoIPFiltering();
// IP Blacklisting
if ($this->cparams->getValue('ipbl', 0) == 1)
$this->IPFiltering();
// GeoBlocking
$cnt = $this->cparams->getValue('geoblockcountries', '');
$con = $this->cparams->getValue('geoblockcontinents', '');
if (!empty($cnt) || !empty($con))
{
$this->geoBlocking();
}
// Check for admin access
if ($this->isAdminAccessAttempt())
{
// IP Whitelist filtering for back-end access
if ($this->cparams->getValue('ipwl', 0) == 1)
$this->adminIPFiltering();
// Administrator "secret word" protection
$this->adminPasswordProtection();
if ($this->cparams->getValue('twofactorauth', 0) == 1)
{
$version = explode('.', JVERSION);
$version = $version[0] . $version[1];
$template = JFactory::getApplication()->getTemplate();
$cssAlt = array(
"login.css",
"login-$version.css",
"login-$version-$template.css",
);
$paths = array(
'../media/com_admintools/css',
"templates/$template/media/com_admintools/css"
);
JLoader::import('joomla.filesystem.file');
foreach ($paths as $path)
{
foreach ($cssAlt as $cssFile)
{
$url = $path . '/' . $cssFile;
$filename = JPATH_ADMINISTRATOR . '/' . $url;
if (JFile::exists($filename))
{
JFactory::getDocument()->addStyleSheet($url);
}
}
}
}
}
if ($this->isAdminAccessAttempt(true))
{
if ($this->cparams->getValue('twofactorauth', 0) == 1)
{
$this->twoFactorAuthentication_verify();
}
}
// Remove inactive users
if ($this->params->get('deleteinactive', 0) == 1)
$this->removeInactiveUsers();
// Remove old log records
if ($this->params->get('maxlogentries', 0) > 0)
$this->removeOldLogEntries();
$app = JFactory::getApplication();
// Back-end stuff
if (in_array($app->getName(), array('administrator', 'admin')))
{
// Block access to the extensions installer
if ($this->cparams->getValue('blockinstall', 0) > 0)
$this->blockInstall();
// Disable editing of back-end users
if ($this->cparams->getValue('nonewadmins', 0) == 1)
$this->noNewAdmins();
// Email on administrator access
$emailonadmin = $this->cparams->getValue('emailonadminlogin', '');
if (!empty($emailonadmin))
$this->emailOnAdminLogin();
// If there is an administrator secret word set, upon logout redirect to the site's home page
$password = $this->cparams->getValue('adminpw', '');
if (!empty($password))
{
if (version_compare(JVERSION, '3.0', 'ge'))
{
$input = new JInput();
$option = $input->getCmd('option', '');
$task = $input->getCmd('task', '');
$uid = $input->getInt('uid', 0);
}
else
{
$option = JRequest::getCmd('option', '');
$task = JRequest::getCmd('task', '');
$uid = JRequest::getInt('uid', 0);
}
$loggingMeOut = true;
if (!empty($uid))
{
$myUID = JFactory::getUser()->id;
$loggingMeOut = $myUID == $uid;
}
if (($option == 'com_login') && ($task == 'logout') && $loggingMeOut)
{
// Logout and redirect to the homepage
$result = $app->logout();
$baseURL = JURI::base();
$baseURL = str_replace('/administrator', '', $baseURL);
$app->redirect($baseURL);
}
}
}
else
// Front-end stuff
{
if (!$this->skipFiltering)
{
// HTTP:BL integration
if ($this->cparams->getValue('httpblenable', 0) == 1)
$this->ProjectHoneypotHTTPBL();
// SQL Injection shielding
if ($this->cparams->getValue('sqlishield', 0) == 1)
$this->SQLiShield();
// XSS shielding
if ($this->cparams->getValue('xssshield', 0) == 1)
$this->XSSShield();
// Malicious User Agent shielding
if ($this->cparams->getValue('muashield', 0) == 1)
$this->MUAShield();
// CSRF shield / anti-spam form filtering
if ($this->cparams->getValue('csrfshield', 0) == 1)
{
$this->CSRFShield_BASIC();
}
elseif ($this->cparams->getValue('csrfshield', 0) == 2)
{
$this->CSRFShield_ADVANCED();
}
// RFIShield
if ($this->cparams->getValue('rfishield', 1) == 1)
$this->RFIShield();
// DFIShield
if ($this->cparams->getValue('dfishield', 1) == 1)
$this->DFIShield();
// UploadShield
if ($this->cparams->getValue('uploadshield', 1) == 1)
$this->UploadShield();
// Anti-spam
if ($this->cparams->getValue('antispam', 0) == 1)
$this->antiSpam();
// Disable template switching (tmpl)
if ($this->cparams->getValue('tmpl', 0) == 1)
$this->disableTmplSwitch();
// Disable template switching (template)
if ($this->cparams->getValue('template', 0) == 1)
$this->disableTemplateSwitch();
}
// Custom URL redirection
if ($this->cparams->getValue('urlredirection', 1) == 1)
$this->customRouter();
// Session optimizer
if ($this->params->get('sesoptimizer', 0) == 1)
$this->sessionOptimizer();
// Session cleaner
if ($this->params->get('sescleaner', 0) == 1)
$this->sessionCleaner();
// Cache cleaner
if ($this->params->get('cachecleaner', 0) == 1)
$this->cacheCleaner();
// Cache expiration
if ($this->params->get('cacheexpire', 0) == 1)
$this->cacheExpire();
// Temp-directory cleaning
if ($this->params->get('cleantemp', 0) == 1)
$this->cleanTemp();
// Log purging
if ($this->params->get('purgelog', 0) == 1)
$this->purgeLog();
}
}
public function onAfterRender()
{
$app = JFactory::getApplication();
if ($this->isAdminAccessAttempt())
{
if ($this->cparams->getValue('twofactorauth', 0) == 1)
{
// Two factor authentication
$this->twoFactorAuthentication_process();
}
}
if (in_array($app->getName(), array('administrator', 'admin')))
{
}
else
{
if ($this->cparams->getValue('csrfshield', 0) == 2)
{
$this->CSRFShield_PROCESS();
}
}
}
public function onAfterRoute()
{
// Naughty, naughty trick
if (JFactory::getSession()->get('block', false, 'com_admintools'))
{
// This is an underhanded way to short-circuit Joomla!'s internal router.
JRequest::set(array(
'option' => 'com_admintools'
), 'get', true);
}
}
public function onAfterDispatch()
{
$app = JFactory::getApplication();
// Back-end stuff
if (in_array($app->getName(), array('administrator', 'admin')))
{
// Email on failed administrator access
if (version_compare(JVERSION, '2.5.0', 'lt'))
{
$emailonfailedadmin = $this->cparams->getValue('emailonfailedadminlogin', '');
if (!empty($emailonfailedadmin))
$this->emailOnFailedAdminLogin();
}
} else
{
// Front-end stuff
// Meta generator cloaking
if ($this->cparams->getValue('custgenerator', 0) == 1)
$this->cloakGenerator();
}
}
/**
* Joomla! 1.5 failed login handler
* @param array $response
*/
public function onLoginFailure($response)
{
if ($this->cparams->getValue('trackfailedlogins', 0))
{
$this->trackFailedLogin();
}
else
{
$app = JFactory::getApplication();
// Back-end stuff
if (in_array($app->getName(), array('administrator', 'admin')))
{
// Email on failed administrator access
$emailonfailedadmin = $this->cparams->getValue('emailonfailedadminlogin', '');
if (!empty($emailonfailedadmin))
$this->emailOnFailedAdminLogin(true);
}
}
}
/**
* Joomla! 1.6+ failed login handler
* @param array $response
*/
public function onUserLoginFailure($response)
{
$this->onLoginFailure($response);
}
/**
* User login event fired by Joomla! 1.5, redirected to the Joomla! 1.6 event
* @param JUser $user
* @param array $options
*/
public function onUserLogin($user, $options)
{
return $this->onLoginUser($user, $options);
}
/**
* User login event fired by Joomla! 1.6
* @param unknown_type $user
* @param unknown_type $options
*/
public function onLoginUser($user, $options)
{
$app = JFactory::getApplication();
$instance = $this->_getUser($user, $options);
// Disallow front-end Super Administrator login
if ($this->cparams->getValue('nofesalogin', 0) == 1)
{
if (!in_array($app->getName(), array('administrator', 'admin')))
{
// Is the user a Super Administrator
$isSuperAdmin = false;
// Joomla! 1.6+ - Check all groups for core.admin privileges
foreach ($instance->groups as $group)
{
$isSuperAdmin |= JAccess::checkGroup($group, 'core.admin');
}
// Block SAs
if ($isSuperAdmin)
{
$newopts = array();
$app->logout($instance->id, $newopts);
// Damn you, Joomla! Since 2.5.5 you have to close the session before throwing
// an error, otherwise the user isn't logged out. What the hell?!
$session = JFactory::getSession();
$session->close();
// Throw error
$this->loadLanguage('plg_system_admintools');
JError::raiseError(403, JText::_('JGLOBAL_AUTH_ACCESS_DENIED'));
return false;
}
}
}
return true;
}
public function onUserAfterSave($user, $isnew, $success, $msg)
{
// Save the user's signup IP
if ($this->cparams->getValue('saveusersignupip', 0) == 1)
{
$process = true;
// Only trigger on successful user creation
if (!$success)
{
$process = false;
}
// Only trigger on new user creation, not subsequent edits
if (!$isnew)
{
$process = false;
}
// Only trigger on front-end user creation.
if (JFactory::getApplication()->isAdmin())
{
$process = false;
}
// Create a new user note
if ($process)
{
// Get the user's ID
$user_id = (int) $user['id'];
// Get the IP address
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
{
$ip = substr($ip, strrpos($ip, ':') + 1);
}
// Get the user agent string
$user_agent = $_SERVER['HTTP_USER_AGENT'];
// Get current date and time in database format
JLoader::import('joomla.utilities.date');
$now = new JDate();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$now = $now->toSql();
}
else
{
$now = $now->toSql();
}
// Load the component's administrator translation files
$jlang = JFactory::getLanguage();
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);
// Create and save the user note
$userNote = (object) array(
'user_id' => $user_id,
'catid' => 0,
'subject' => JText::_('ATOOLS_LBL_WAF_SIGNUPIP_SUBJECT'),
'body' => JText::sprintf('ATOOLS_LBL_WAF_SIGNUPIP_BODY', $ip, $user_agent),
'state' => 1,
'created_user_id' => 42,
'created_time' => $now
);
$db = JFactory::getDbo();
$db->insertObject('#__user_notes', $userNote, 'id');
}
}
}
/**
* Filters back-end access by IP. If the IP of the visitor is not included
* in the whitelist, he gets redirected to the home page
*/
private function adminIPFiltering()
{
// Let's get a list of allowed IP ranges
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->select($db->qn('ip'))
->from($db->qn('#__admintools_adminiplist'));
$db->setQuery($sql);
if (version_compare(JVERSION, '3.0', 'ge'))
{
$ipTable = $db->loadColumn();
}
else
{
$ipTable = $db->loadResultArray();
}
if (empty($ipTable))
return;
$inList = $this->IPinList($ipTable);
if ($inList === false)
{
if (!$this->logBreaches('ipwl'))
return;
$autoban = $this->cparams->getValue('tsrenable', 0);
if ($autoban)
$this->autoBan('ipwl');
$this->redirectAdminToHome();
}
}
/**
* Filters visitor access by IP. If the IP of the visitor is included in the
* blacklist, he gets a 403 error
*/
private function IPFiltering()
{
// Let's get a list of blocked IP ranges
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->select($db->qn('ip'))
->from($db->qn('#__admintools_ipblock'));
$db->setQuery($sql);
if (version_compare(JVERSION, '3.0', 'ge'))
{
$ipTable = $db->loadColumn();
}
else
{
$ipTable = $db->loadResultArray();
}
if (empty($ipTable))
return;
$inList = $this->IPinList($ipTable);
if ($inList === true)
{
$message = $this->cparams->getValue('custom403msg', '');
if (empty($message))
{
$message = 'ADMINTOOLS_BLOCKED_MESSAGE';
}
// Merge the default translation with the current translation
$jlang = JFactory::getLanguage();
// Front-end translation
$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, null, true);
// Do we have an override?
$langOverride = $this->params->get('language_override', '');
if (!empty($langOverride))
{
$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, $langOverride, true);
}
if ((JText::_('ADMINTOOLS_BLOCKED_MESSAGE') == 'ADMINTOOLS_BLOCKED_MESSAGE') && ($message == 'ADMINTOOLS_BLOCKED_MESSAGE'))
{
$message = "Access Denied";
}
else
{
$message = JText::_($message);
}
// Show the 403 message
if ($this->cparams->getValue('use403view', 0))
{
// Using a view
if (!JFactory::getSession()->get('block', false, 'com_admintools') || JFactory::getApplication()->isAdmin())
{
// This is inside an if-block so that we don't end up in an infinite rediretion loop
JFactory::getSession()->set('block', true, 'com_admintools');
JFactory::getSession()->set('message', $message, 'com_admintools');
JFactory::getSession()->close();
$base = JURI::base();
if (JFactory::getApplication()->isAdmin())
{
$base = rtrim($base);
$base = substr($base, -13);
}
JFactory::getApplication()->redirect($base);
}
}
else
{
if (JFactory::getApplication()->isAdmin())
{
// You can't use Joomla!'s error page in the admin area. Improvise!
header('HTTP/1.1 403 Forbidden');
echo $message;
JFactory::getApplication()->close();
}
else
{
// Using Joomla!'s error page
JError::raiseError('403', $message);
}
}
}
}
/**
* Checks if the secret word is set in the URL query, or redirects the user
* back to the home page.
*/
private function adminPasswordProtection()
{
$password = $this->cparams->getValue('adminpw', '');
if (empty($password))
return;
$myURI = JURI::getInstance();
// If the "password" query param is not defined, the default value
// "thisisnotgood" is returned. If it is defined, it will return null or
// the value after the equal sign.
$check = $myURI->getVar($password, 'thisisnotgood');
if ($check == 'thisisnotgood')
{
// Uh oh... Unauthorized access! Let's redirect the perp back to the
// site's home page.
if (!$this->logBreaches('adminpw'))
return;
$autoban = $this->cparams->getValue('tsrenable', 0);
if ($autoban)
$this->autoBan('adminpw');
$this->redirectAdminToHome();
}
}
/**
* Cloak the generator meta tag
*/
private function cloakGenerator()
{
// Only do this for the front-end application
$app = JFactory::getApplication();
if ($app->getName() != 'site')
return;
$generator = $this->cparams->getValue('generator', '');
if (empty($generator))
$generator = 'MYOB'; // Mind Your Own Business, peeping Tom!
$document = JFactory::getDocument();
$document->setGenerator($generator);
}
/**
* Disable template switching in the URL
*/
private function disableTmplSwitch()
{
$tmpl = JRequest::getCmd('tmpl', null);
if (empty($tmpl))
return;
$whitelist = $this->cparams->getValue('tmplwhitelist', 'component,system');
if (empty($whitelist))
$whitelist = 'component,system';
$temp = explode(',', $whitelist);
$whitelist = array();
foreach ($temp as $item)
{
$whitelist[] = trim($item);
}
$whitelist = array_merge(array('component', 'system'), $whitelist);
if (!is_null($tmpl) && !in_array($tmpl, $whitelist))
{
if (!$this->logBreaches('tmpl'))
return;
$autoban = $this->cparams->getValue('tsrenable', 0);
if ($autoban)
$this->autoBan('tmpl');
JRequest::setVar('tmpl', null);
}
}
/**
* Disable template switching in the URL
*/
private function disableTemplateSwitch()
{
static $siteTemplates = array();
$template = JRequest::getCmd('template', null);
$block = true;
if (!empty($template))
{
// Exception: existing site templates are allowed
if (JRequest::getCmd('option', '') == 'com_mailto')
{
// com_email URLs in Joomla! 1.7 and later have template= defined; force $allowsitetemplate in this case
$allowsitetemplate = true;
}
else
{
// Otherwise, allow only of the switch is set
$allowsitetemplate = $this->cparams->getValue('allowsitetemplate', 0);
}
if ($allowsitetemplate)
{
if (empty($siteTemplates))
{
JLoader::import('joomla.filesystem.folder');
$siteTemplates = JFolder::folders(JPATH_SITE . '/templates');
}
$block = !in_array($template, $siteTemplates);
}
if ($block)
{
if (!$this->logBreaches('template'))
return;
$autoban = $this->cparams->getValue('tsrenable', 0);
if ($autoban)
$this->autoBan('template');
JRequest::setVar('template', null);
}
}
}
/**
* Fend off most common types of SQLi attacks. See the comments in the code
* for more security-minded information.
*/
private function SQLiShield()
{
// We filter all hashes separately to guard against underhanded injections.
// For example, if the parameter registration to the $_REQUEST array is
// GPCS, a GET variable will "hide" a POST variable during a POST request.
// If the vulnerable component is, however, *explicitly* asking for the
// POST variable, if we only check the $_REQUEST superglobal array we will
// miss the attack: we will see the innocuous GET variable which is
// registered to the $_REQUEST array due to higher precedence, while the
// malicious POST payload makes it through to the component. When you are
// talking about security you can leave NOTHING in the hands of Fate, or
// it will come back to bite your sorry ass.
$hashes = array('get', 'post');
// Removing the jos_/#__ filter as it throws false positives on posts regarding SQL commands
//$regex = '#[^\s]*([\s]|/\*(.*)\*/|;|\'|"|%22){1,}(union([\s]{1,}|/\*(.*)\*/){1,}select|select(([\s]{1,}|/\*(.*)\*/|`){1,}([\w]|_|-|\.|\*){1,}([\s]{1,}|/\*(.*)\*/|`){1,}(,){0,})*from([\s]{1,}|/\*(.*)\//){1,}[a-z0-9]{1,}_|(insert|replace)(([\s]{1,}|/\*(.*)\*/){1,})((low_priority|delayed|high_priority|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}into|drop([\s]{1,}|/\*(.*)\*/){1,}(database|schema|event|procedure|function|trigger|view|index|server|(temporary([\s]{1,}|/\*(.*)\*/){1,}){0,1}table){1,1}([\s]{1,}|/\*(.*)\*/){1,}|update([\s]{1,}|/\*[^\w]*\/){1,}(low_priority([\s]{1,}|/\*[^\w]*\/){1,}|ignore([\s]{1,}|/\*[^\w]*\/){1,})?`?[\w]*_.*set|delete([\s]{1,}|/\*(.*)\*/){1,}((low_priority|quick|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}from|benchmark([\s]{1,}|/\*(.*)\*/){0,}\(([\s]{1,}|/\*(.*)\*/){0,}[0-9]{1,}|\#__|jos_){1}#i';
//$regex = '#[^\s]*([\s]|/\*(.*)\*/|;|\'|"|%22){1,}(union([\s]{1,}|/\*(.*)\*/){1,}select|select(([\s]{1,}|/\*(.*)\*/|`){1,}([\w]|_|-|\.|\*){1,}([\s]{1,}|/\*(.*)\*/|`){1,}(,){0,})*from([\s]{1,}|/\*(.*)\//){1,}[a-z0-9]{1,}_|(insert|replace)(([\s]{1,}|/\*(.*)\*/){1,})((low_priority|delayed|high_priority|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}into|drop([\s]{1,}|/\*(.*)\*/){1,}(database|schema|event|procedure|function|trigger|view|index|server|(temporary([\s]{1,}|/\*(.*)\*/){1,}){0,1}table){1,1}([\s]{1,}|/\*(.*)\*/){1,}|update([\s]{1,}|/\*[^\w]*\/){1,}(low_priority([\s]{1,}|/\*[^\w]*\/){1,}|ignore([\s]{1,}|/\*[^\w]*\/){1,})?`?[\w]*_.*set|delete([\s]{1,}|/\*(.*)\*/){1,}((low_priority|quick|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}from|benchmark([\s]{1,}|/\*(.*)\*/){0,}\(([\s]{1,}|/\*(.*)\*/){0,}[0-9]{1,}){1}#i';
$regex = '#[^\s]*([\s]|/\*(.*)\*/|;|\'|"|%22){1,}(union([\s]{1,}|/\*(.*)\*/){1,}(all([\s]{1,}|/\*(.*)\*/){1,})?select|select(([\s]{1,}|/\*(.*)\*/|`){1,}([\w]|_|-|\.|\*){1,}([\s]{1,}|/\*(.*)\*/|`){1,}(,){0,})*from([\s]{1,}|/\*(.*)\//){1,}[a-z0-9]{1,}_|(insert|replace)(([\s]{1,}|/\*(.*)\*/){1,})((low_priority|delayed|high_priority|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}into|drop([\s]{1,}|/\*(.*)\*/){1,}(database|schema|event|procedure|function|trigger|view|index|server|(temporary([\s]{1,}|/\*(.*)\*/){1,}){0,1}table){1,1}([\s]{1,}|/\*(.*)\*/){1,}|update([\s]{1,}|/\*[^\w]*\/){1,}(low_priority([\s]{1,}|/\*[^\w]*\/){1,}|ignore([\s]{1,}|/\*[^\w]*\/){1,})?`?[\w]*_.*set|delete([\s]{1,}|/\*(.*)\*/){1,}((low_priority|quick|ignore)([\s]{1,}|/\*(.*)\*/){1,}){0,}from|benchmark([\s]{1,}|/\*(.*)\*/){0,}\(([\s]{1,}|/\*(.*)\*/){0,}[0-9]{1,}){1}#i';
foreach ($hashes as $hash)
{
$allVars = JRequest::get($hash, 2);
if (empty($allVars))
continue;
if ($this->match_array($regex, $allVars))
{
$extraInfo = "Hash : $hash\n";
$extraInfo .= "Variables :\n";
$extraInfo .= print_r($allVars, true);
$extraInfo .= "\n";
$this->blockRequest('sqlishield', null, $extraInfo);
}
}
}
/**
* Runs a RegEx match against a string or recursively against an array.
* In the case of an array, the first positive match against any level element
* of the array returns true and breaks the RegEx matching loop. If you pass
* any other data type except an array or string, it returns false.
*
* @param string $regex The regular expressions to feed to preg_match
* @param mixed $array
* @return <type>
*/
private function match_array($regex, $array, $striptags = false)
{
$result = false;
if (is_array($array))
{
foreach ($array as $key => $value)
{
if (is_array($value))
{
$result = $this->match_array($regex, $value, $striptags);
}
else
{
$v = $striptags ? strip_tags($value) : $value;
$result = preg_match($regex, $v);
}
if ($result)
break;
}
} elseif (is_string($array))
{
$v = $striptags ? strip_tags($array) : $array;
$result = preg_match($regex, $v);
}
return $result;
}
/**
* The simplest anti-spam solution imagineable. Just blocks a request if a prohibited word is found.
*/
private function antiSpam()
{
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->select($db->qn('word'))
->from($db->qn('#__admintools_badwords'))
->group($db->qn('word'));
$db->setQuery($sql);
if (version_compare(JVERSION, '3.0', 'ge'))
{
$badwords = $db->loadColumn();
}
else
{
$badwords = $db->loadResultArray();
}
if (empty($badwords))
return;
$hashes = array('get', 'post');
foreach ($hashes as $hash)
{
$allVars = JRequest::get($hash, 2);
if (empty($allVars))
continue;
foreach ($badwords as $word)
{
$regex = '#\b' . $word . '\b#i';
if ($this->match_array($regex, $allVars, true))
{
$extraInfo = "Hash : $hash\n";
$extraInfo .= "Variables :\n";
$extraInfo .= print_r($allVars, true);
$extraInfo .= "\n";
$this->blockRequest('antispam', null, $extraInfo);
}
}
}
}
/**
* Performs custom redirections defined in the back-end of the component.
* It doesn't even require SEF to be turned on, he he!
*/
private function customRouter()
{
// Get the base path
$basepath = ltrim(JURI::base(true), '/');
$myURL = JURI::getInstance();
$fullurl = ltrim($myURL->toString(array('path', 'query', 'fragment')), '/');
$path = ltrim($myURL->getPath(), '/');
$pathLength = strlen($path);
$baseLength = strlen($basepath);
if ($baseLength != 0)
{
if ($pathLength > $baseLength)
{
$path = ltrim(substr($path, $baseLength), '/');
}
elseif ($pathLength = $baseLength)
{
$path = '';
}
}
$pathLength = strlen($fullurl);
if ($baseLength != 0)
{
if ($pathLength > $baseLength)
{
$fullurl = ltrim(substr($fullurl, $baseLength), '/');
}
elseif ($pathLength = $baseLength)
{
$fullurl = '';
}
}
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->select(array($db->qn('source'), $db->qn('keepurlparams')))
->from($db->qn('#__admintools_redirects'))
->where(
'(' . $db->qn('dest') . ' = ' . $db->q($path) . ')' .
' OR ' .
'(' . $db->qn('dest') . ' = ' . $db->q($fullurl) . ')'
)->where($db->qn('published') . ' = ' . $db->q('1'))
->order($db->qn('ordering') . ' DESC')
;
$db->setQuery($sql, 0, 1);
$newURLStruct = $db->loadRow();
if (!empty($newURLStruct))
{
list ($newURL, $keepQueryParams) = $newURLStruct;
$new = JURI::getInstance($newURL);
$host = $new->getHost();
$fragment = $new->getFragment();
$query = $new->getQuery();
if (empty($host))
{
$base = JURI::getInstance(JURI::base());
$new->setHost($base->getHost());
$new->setPort($base->getPort());
}
if ($keepQueryParams)
{
if (empty($query))
{
$new->setQuery($myURL->getQuery());
}
if (empty($fragment))
{
$new->setFragment($myURL->getFragment());
}
}
$path = $new->getPath();
if (!empty($path))
{
if (substr($path, 0, 1) != '/')
{
$new->setPath('/' . $path);
}
}
$new->setScheme($myURL->getScheme());
$targetURL = $new->toString();
$app = JFactory::getApplication();
$app->redirect($targetURL, '', 'message', true);
}
}
private function sessionOptimizer()
{
$minutes = (int) $this->params->get('sesopt_freq', 0);
if ($minutes <= 0)
return;
$lastJob = $this->getTimestamp('session_optimize');
$nextJob = $lastJob + $minutes * 60;
JLoader::import('joomla.utilities.date');
$now = new JDate();
if ($now->toUnix() >= $nextJob)
{
$this->setTimestamp('session_optimize');
$this->sessionOptimize();
}
}
/**
* Run the session cleaner (garbage collector) on a schedule
*/
private function sessionCleaner()
{
$minutes = (int) $this->params->get('ses_freq', 0);
if ($minutes <= 0)
return;
$lastJob = $this->getTimestamp('session_clean');
$nextJob = $lastJob + $minutes * 60;
JLoader::import('joomla.utilities.date');
$now = new JDate();
if ($now->toUnix() >= $nextJob)
{
$this->setTimestamp('session_clean');
$this->purgeSession();
}
}
private function cacheCleaner()
{
$minutes = (int) $this->params->get('cache_freq', 0);
if ($minutes <= 0)
return;
$lastJob = $this->getTimestamp('cache_clean');
$nextJob = $lastJob + $minutes * 60;
JLoader::import('joomla.utilities.date');
$now = new JDate();
if ($now->toUnix() >= $nextJob)
{
$this->setTimestamp('cache_clean');
$this->purgeCache();
}
}
private function cacheExpire()
{
$minutes = (int) $this->params->get('cacheexp_freq', 0);
if ($minutes <= 0)
return;
$lastJob = $this->getTimestamp('cache_expire');
$nextJob = $lastJob + $minutes * 60;
JLoader::import('joomla.utilities.date');
$now = new JDate();
if ($now->toUnix() >= $nextJob)
{
$this->setTimestamp('cache_expire');
$this->expireCache();
}
}
private function cleanTemp()
{
$minutes = (int) $this->params->get('cleantemp_freq', 0);
if ($minutes <= 0)
return;
$lastJob = $this->getTimestamp('clean_temp');
$nextJob = $lastJob + $minutes * 60;
JLoader::import('joomla.utilities.date');
$now = new JDate();
if ($now->toUnix() >= $nextJob)
{
$this->setTimestamp('clean_temp');
$this->tempDirectoryCleanup();
}
}
/**
* Checks if a non logged in user is trying to access the administrator
* application
*
* @param $onlySubmit bool Return true only if the form is submitted
*/
private function isAdminAccessAttempt($onlySubmit = false)
{
$app = JFactory::getApplication();
$user = JFactory::getUser();
if (in_array($app->getName(), array('administrator', 'admin')))
{
if ($user->guest)
{
if (version_compare(JVERSION, '3.0', 'ge'))
{
$input = new JInput();
$option = $input->getCmd('option', null);
$task = $input->getCmd('task', null);
}
else
{
$option = JRequest::getCmd('option', null);
$task = JRequest::getCmd('task', null);
}
if (($option == 'com_login') && ($task == 'login'))
{
// Check for malicious direct post without a valid token
// In this case, we "cheat" by pretending that it is a
// login attempt we need to filter. If it's a legitimate
// login request (username & password posted) we stop
// filtering so as to allow Joomla! to parse the login
// request.
JLoader::import('joomla.utiltiites.utility');
$token = null;
if (class_exists('JUtility'))
{
if (method_exists('JUtility', 'getToken'))
{
$token = JUtility::getToken();
}
}
if (is_null($token))
{
$token = JFactory::getSession()->getToken();
}
$token = JRequest::getVar($token, false);
if (!$onlySubmit)
{
if (($token === false) && method_exists('JSession', 'checkToken'))
{
return !JSession::checkToken('request');
}
else
{
return $token === false;
}
}
else
{
if (($token === false) && method_exists('JSession', 'checkToken'))
{
return JSession::checkToken('request');
}
else
{
return $token !== false;
}
}
}
else
{
// Back-end login attempt
if ($onlySubmit)
{
return false;
}
return true;
}
}
else
{
// Logged in admin user
return false;
}
}
else
{
// The request doesn't belong to the Administrator application
return false;
}
}
/**
* Checks if the user's IP is contained in a list of IPs or IP expressions
* @param array $ipTable The list of IP expressions
* @return null|bool True if it's in the list, null if the filtering can't proceed
*/
private function IPinList($ipTable = array())
{
// Get our IP address
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
return AdmintoolsHelperIp::IPinList($ip, $ipTable);
}
/**
* Blocks acess to com_install
*/
private function blockInstall()
{
if (version_compare(JVERSION, '3.0', 'ge'))
{
$input = new JInput();
$option = $input->getCmd('option', '');
}
else
{
$option = JRequest::getCmd('option', '');
}
if (!in_array($option, array('com_installer', 'com_plugins')))
return;
$blockSetting = $this->cparams->getValue('blockinstall', 0);
if ($blockSetting == 0)
return;
$user = JFactory::getUser();
if (!$user->guest)
{
// Joomla! 1.6 -- Only Super Users have the core.admin global privilege
$coreAdmin = $user->authorise('core.admin');
if (!empty($coreAdmin) && ($coreAdmin === true))
{
$coreAdmin = true;
}
else
{
$coreAdmin = false;
}
if (($blockSetting == 1) && ($coreAdmin))
return;
$jlang = JFactory::getLanguage();
$jlang->load('joomla', JPATH_ROOT, 'en-GB', true);
$jlang->load('joomla', JPATH_ROOT, $jlang->getDefault(), true);
$jlang->load('joomla', JPATH_ROOT, null, true);
$this->loadLanguage('plg_system_admintools');
JError::raiseError(403, JText::_('JGLOBAL_AUTH_ACCESS_DENIED'));
}
}
/**
* Disabled creating new admins or updating new ones
*/
private function noNewAdmins()
{
if (version_compare(JVERSION, '3.0', 'ge'))
{
$input = new JInput();
$option = $input->getCmd('option', '');
$task = $input->getCmd('task', '');
$gid = $input->getInt('gid', 0);
}
else
{
$option = JRequest::getCmd('option', '');
$task = JRequest::getCmd('task', '');
$gid = JRequest::getInt('gid', 0);
}
if ($option != 'com_users')
return;
$jform = JRequest::getVar('jform', array(), 'default', 'array');
if (($task == 'save') || ($task == 'apply') || ($task = 'user.apply'))
{
// Joomla! 1.6
if (empty($jform))
return; // Not editing, just core devs using the same task throughout the component, dammit
$groups = $jform['groups'];
$user = JFactory::getUser((int) $jform['id']);
if (!empty($user->groups))
foreach ($user->groups as $title => $gid)
{
if (!in_array($gid, $groups))
$groups[] = $gid;
}
$isAdmin = false;
if (!empty($groups))
foreach ($groups as $group)
{
// First try to see if the group has explicit backend login privileges
$backend = JAccess::checkGroup($group, 'core.login.admin');
// If not, is it a Super Admin (ergo inherited privileges)?
if (is_null($backend))
$backend = JAccess::checkGroup($group, 'core.admin');
$isAdmin |= $backend;
}
if ($isAdmin)
{
$jlang = JFactory::getLanguage();
$jlang->load('joomla', JPATH_ROOT, 'en-GB', true);
$jlang->load('joomla', JPATH_ROOT, $jlang->getDefault(), true);
$jlang->load('joomla', JPATH_ROOT, null, true);
$this->loadLanguage('plg_system_admintools');
JError::raiseError(403, JText::_('JGLOBAL_AUTH_ACCESS_DENIED'));
}
}
}
/**
* Redirects an administrator request back to the home page
*/
private function redirectAdminToHome()
{
// Get the current URI
$myURI = JURI::getInstance();
$path = $myURI->getPath();
// Pop the administrator from the URI path
$path_parts = explode('/', $path);
$path_parts = array_slice($path_parts, 0, count($path_parts) - 2);
$path = implode('/', $path_parts);
$myURI->setPath($path);
// Unset any query parameters
$myURI->setQuery('');
// Redirect
$app = JFactory::getApplication();
$app->redirect($myURI->toString());
}
/**
* Blocks the request in progress and, optionally, logs the details of the
* blocked request for the admin to review later
*
* @param string $reason Block reason code
* @param string $message The message to be shown to the user
* @param string $extraLogInformation Extra information to be written to the text log file
* @param string $extraLogTableInformation Extra information to be written to the extradata field of the log table (useful for JSON format)
*/
private function blockRequest($reason = 'other', $message = '', $extraLogInformation = '', $extraLogTableInformation = '')
{
if (empty($message))
{
$customMessage = $this->cparams->getValue('custom403msg', '');
if (!empty($customMessage))
{
$message = $customMessage;
}
else
{
$message = 'ADMINTOOLS_BLOCKED_MESSAGE';
}
}
$r = $this->logBreaches($reason, $extraLogInformation, $extraLogTableInformation);
if (!$r)
return;
$autoban = $this->cparams->getValue('tsrenable', 0);
if ($autoban)
$this->autoBan($reason);
// Merge the default translation with the current translation
$jlang = JFactory::getLanguage();
// Front-end translation
$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('plg_system_admintools', JPATH_ADMINISTRATOR, null, true);
if ((JText::_('ADMINTOOLS_BLOCKED_MESSAGE') == 'ADMINTOOLS_BLOCKED_MESSAGE') && ($message == 'ADMINTOOLS_BLOCKED_MESSAGE'))
{
$message = "Access Denied";
}
else
{
$message = JText::_($message);
}
// Show the 403 message
if ($this->cparams->getValue('use403view', 0))
{
// Using a view
if (!JFactory::getSession()->get('block', false, 'com_admintools'))
{
// This is inside an if-block so that we don't end up in an infinite rediretion loop
JFactory::getSession()->set('block', true, 'com_admintools');
JFactory::getSession()->set('message', $message, 'com_admintools');
JFactory::getSession()->close();
JFactory::getApplication()->redirect(JURI::base());
}
}
else
{
// Using Joomla!'s error page
JError::raiseError('403', $message);
}
}
private function logBreaches($reason, $extraLogInformation = '', $extraLogTableInformation = '')
{
$reasons_nolog = $this->cparams->getValue('reasons_nolog', 'geoblocking');
$reasons_noemail = $this->cparams->getValue('reasons_noemail', 'geoblocking');
$reasons_nolog = explode(',', $reasons_nolog);
$reasons_noemail = explode(',', $reasons_noemail);
// === SANITY CHECK - BEGIN ===
// Get our IP address
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
{
$ip = substr($ip, strrpos($ip, ':') + 1);
}
// No point continuing if we can't get an address, right?
if (empty($ip) || ($ip == '0.0.0.0'))
{
return false;
}
// Make sure it's not an IP in the safe list
$safeIPs = $this->cparams->getValue('neverblockips', '');
if (!empty($safeIPs))
{
$safeIPs = explode(',', $safeIPs);
if (!empty($safeIPs))
{
if ($this->IPinList($safeIPs))
{
return false;
}
}
}
// Make sure we don't have a list in the administrator white list
if ($this->cparams->getValue('ipwl', 0) == 1)
{
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->select($db->qn('ip'))
->from($db->qn('#__admintools_adminiplist'));
$db->setQuery($sql);
if (version_compare(JVERSION, '3.0', 'ge'))
{
$ipTable = $db->loadColumn();
}
else
{
$ipTable = $db->loadResultArray();
}
if (!empty($ipTable))
{
if ($this->IPinList($ipTable))
{
return false;
}
}
}
// === SANITY CHECK - END ===
if ($this->cparams->getValue('logbreaches', 0) && !in_array($reason, $reasons_nolog))
{
// Logging requested. Fetch log information...
$uri = JURI::getInstance();
$url = $uri->toString(array('scheme', 'user', 'pass', 'host', 'port', 'path', 'query', 'fragment'));
JLoader::import('joomla.utilities.date');
$date = new JDate();
$user = JFactory::getUser();
if ($user->guest)
{
$username = 'Guest';
}
else
{
$username = $user->username . ' (' . $user->name . ' <' . $user->email . '>)';
}
if (AdmintoolsHelperIp::isIPv6($ip))
{
$country = 'N/A (IPv6)';
$continent = 'N/A (IPv6)';
}
else
{
if (@file_exists(JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'geoip' . DIRECTORY_SEPARATOR . 'GeoIP.dat'))
{
if (!$this->hasGeoIPPECL)
{
require_once JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'geoip.php';
$gi = geoip_open(JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'geoip' . DIRECTORY_SEPARATOR . 'GeoIP.dat', GEOIP_STANDARD);
$country = geoip_country_code_by_addr($gi, $ip);
$continent = geoip_region_by_addr($gi, $ip);
geoip_close($gi);
}
else
{
$country = geoip_country_code_by_name($ip);
$continent = geoip_continent_code_by_name($ip);
}
}
else
{
$country = '(unknown country)';
$continent = '(unknown continent)';
}
}
// Logging to file
$config = JFactory::getConfig();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$logpath = $config->get('log_path');
}
else
{
$logpath = $config->getValue('log_path');
}
$fname = $logpath . DIRECTORY_SEPARATOR . 'admintools_breaches.log';
// -- Check the file size. If it's over 1Mb, archive and start a new log.
if (@file_exists($fname))
{
$fsize = filesize($fname);
if ($fsize > 1048756)
{
if (@file_exists($fname . '.1'))
{
unlink($fname . '.1');
}
@copy($fname, $fname . '.1');
@unlink($fname);
}
}
// -- Log the exception
$fp = @fopen($fname, 'at');
if ($fp !== false)
{
fwrite($fp, str_repeat('-', 79) . "\n");
fwrite($fp, "Blocking reason: " . $reason . "\n" . str_repeat('-', 79) . "\n");
fwrite($fp, 'Date/time : ' . gmdate('Y-m-d H:i:s') . " GMT\n");
fwrite($fp, 'URL : ' . $url . "\n");
fwrite($fp, 'User : ' . $username . "\n");
fwrite($fp, 'IP : ' . $ip . "\n");
fwrite($fp, 'Country : ' . $country . "\n");
fwrite($fp, 'Continent : ' . $continent . "\n");
fwrite($fp, 'UA : ' . $_SERVER['HTTP_USER_AGENT'] . "\n");
if (!empty($extraLogInformation))
fwrite($fp, $extraLogInformation . "\n");
fwrite($fp, "\n\n");
fclose($fp);
}
// ...and write a record to the log table
$db = JFactory::getDBO();
$logEntry = (object) array(
'logdate' => $date->toSql(),
'ip' => $ip,
'url' => $url,
'reason' => $reason,
'extradata' => $extraLogTableInformation,
);
$db->insertObject('#__admintools_log', $logEntry);
}
$emailbreaches = $this->cparams->getValue('emailbreaches', '');
if (!empty($emailbreaches) && !in_array($reason, $reasons_noemail))
{
// Load the component's administrator translation files
$jlang = JFactory::getLanguage();
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);
// Get the site name
$config = JFactory::getConfig();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$sitename = $config->get('sitename');
}
else
{
$sitename = $config->getValue('config.sitename');
}
// Create a link to lookup the IP
$ip_link = $this->cparams->getValue('iplookupscheme', 'http') . '://' . $this->cparams->getValue('iplookup', 'ip-lookup.net/index.php?ip={ip}');
$ip_link = str_replace('{ip}', $ip, $ip_link);
// Get the reason in human readable format
$txtReason = JText::_('ATOOLS_LBL_REASON_' . strtoupper($reason));
// Get extra information
if ($extraLogTableInformation)
{
list($logReason, $techURL) = explode('|', $extraLogTableInformation);
$txtReason .= " ($logReason)";
}
// Send the email
$mailer = JFactory::getMailer();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$mailfrom = $config->get('mailfrom');
$fromname = $config->get('fromname');
}
else
{
$mailfrom = $config->getValue('config.mailfrom');
$fromname = $config->getValue('config.fromname');
}
$mailer->setSender(array($mailfrom, $fromname));
$mailer->addRecipient($this->cparams->getValue('emailbreaches', ''));
$mailer->setSubject(JText::sprintf('ATOOLS_LBL_WAF_EMAILBREACHES_SUBJECT', $sitename));
$mailer->setBody(JText::sprintf('ATOOLS_LBL_WAF_EMAILBREACHES_BODY', $sitename, $ip, $ip_link, $txtReason, $sitename));
$mailer->Send();
}
return true;
}
/**
* Optimizes the session table. The idea is that as users log in and out,
* vast amounts of records are created and deleted, slowly fragmenting the
* underlying database file and slowing down user session operations. At
* some point, your site might even crash. By doing a periodic optimization
* of the sessions table this is prevented. An optimization per hour should
* be adequate, even for huge sites.
*
* Note: this is not necessary if you're not using the database to save
* session data. Using disk files, memcache, APC or other alternative caches
* has no impact on your database performance. In this case you should not
* enable this option, as you have nothing to gain.
*/
private function sessionOptimize()
{
$db = JFactory::getDBO();
// First, make sure this is MySQL!
$dbClass = get_class($db);
if (substr($dbClass, 0, 15) == 'JDatabaseDriver')
{
$dbClass = substr($dbClass, 15);
}
else
{
$dbClass = str_replace('JDatabase', '', $dbClass);
}
if (!in_array(strtolower($dbClass), array('mysql', 'mysqli')))
{
return;
}
$db->setQuery('CHECK TABLE ' . $db->quoteName('#__session'));
$result = $db->loadObjectList();
$isOK = false;
if (!empty($result))
foreach ($result as $row)
{
if (($row->Msg_type == 'status') && (
($row->Msg_text == 'OK') ||
($row->Msg_text == 'Table is already up to date')
))
$isOK = true;
}
// Run a repair only if it is required
if (!$isOK)
{
// The table needs repair
$db->setQuery('REPAIR TABLE ' . $db->quoteName('#__session'));
$db->execute();
}
// Finally, optimize
$db->setQuery('OPTIMIZE TABLE ' . $db->quoteName('#__session'));
$db->execute();
}
/**
* Purges expired sessions
*/
private function purgeSession()
{
JLoader::import('joomla.session.session');
$options = array();
$conf = JFactory::getConfig();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$handler = $conf->get('session_handler', 'none');
}
else
{
$handler = $conf->getValue('config.session_handler', 'none');
}
// config time is in minutes
if (version_compare(JVERSION, '3.0', 'ge'))
{
$options['expire'] = ($conf->get('lifetime')) ? $conf->get('lifetime') * 60 : 900;
}
else
{
$options['expire'] = ($conf->getValue('config.lifetime')) ? $conf->getValue('config.lifetime') * 60 : 900;
}
$storage = JSessionStorage::getInstance($handler, $options);
$storage->gc($options['expire']);
}
/**
* Completely purges the cache
*/
private function purgeCache()
{
// Site client
$client = JApplicationHelper::getClientInfo(0);
$er = @error_reporting(0);
$cache = JFactory::getCache('');
$cache->clean('sillylongnamewhichcantexistunlessyouareacompletelyparanoiddeveloperinwhichcaseyoushouldnotbewritingsoftwareokay', 'notgroup');
@error_reporting($er);
}
/**
* Expires cache items
*/
private function expireCache()
{
$er = @error_reporting(0);
$cache = JFactory::getCache('');
$cache->gc();
@error_reporting($er);
}
/**
* Cleans up the temporary director
*/
private function tempDirectoryCleanup()
{
$file = JPATH_ADMINISTRATOR . '/components/com_admintools/models/cleantmp.php';
if (@file_exists($file))
{
include_once($file);
$model = new AdmintoolsModelCleantmp();
$model->startScanning(); // This also runs the first batch of deletions
$model->run(); // and this runs more deletions until the time is up
}
}
/**
* Sets the timestamp for a specific scheduling task
* @param $key string The scheduling task key to set the timestamp parameter for
*/
private function setTimestamp($key)
{
JLoader::import('joomla.utilities.date');
$date = new JDate();
$pk = 'timestamp_' . $key;
$timestamp = $date->toUnix();
$oldTimestamp = $this->getTimestamp($key); // Make sure the array is populated
$db = JFactory::getDbo();
// This is necessary because using an UPDATE query results in Joomla!
// throwing a JLIB_APPLICATION_ERROR_COMPONENT_NOT_LOADING or blank
// page. HUH!!!!!!
$query = $db->getQuery(true)
->delete($db->qn('#__admintools_storage'))
->where($db->qn('key') . ' = ' . $db->q($pk));
$db->setQuery($query);
$db->execute();
$query = $db->getQuery(true)
->insert($db->qn('#__admintools_storage'))
->columns(array(
$db->qn('key'),
$db->qn('value'),
))->values(
$db->q($pk) . ', ' . $db->q($timestamp)
);
$db->setQuery($query);
$db->execute();
$this->timestamps[$pk] = $timestamp;
}
/**
* Gets the last recorded timestamp for a specific scheduling task
* @param $key string The scheduling task key to retrieve the timestamp parameter
* @return int UNIX timestamp
*/
private function getTimestamp($key)
{
if (empty($this->timestamps))
{
$this->loadTimestamps();
}
JLoader::import('joomla.utilities.date');
$pk = 'timestamp_' . $key;
if (!array_key_exists($pk, $this->timestamps))
{
return 0;
}
return $this->timestamps[$pk];
}
/**
* Sends an email upon accessing an administrator page other than the login screen
*/
private function emailOnAdminLogin()
{
// Make sure we don't fire when someone is still in the login page
if ($this->isAdminAccessAttempt())
return;
// Double check
$user = JFactory::getUser();
if ($user->guest)
return;
// Check if the session flag is set (avoid sending thousands of emails!)
$session = JFactory::getSession();
$flag = $session->get('waf.loggedin', 0, 'plg_admintools');
if ($flag == 1)
return;
// Load the component's administrator translation files
$jlang = JFactory::getLanguage();
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);
// Get the username
$username = $user->username;
// Get the site name
$config = JFactory::getConfig();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$sitename = $config->get('sitename');
}
else
{
$sitename = $config->getValue('config.sitename');
}
// Get the IP address
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
{
$ip = substr($ip, strrpos($ip, ':') + 1);
}
if (@file_exists(JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'geoip' . DIRECTORY_SEPARATOR . 'GeoIP.dat'))
{
if (!$this->hasGeoIPPECL)
{
require_once JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'geoip.php';
$gi = geoip_open(JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'geoip' . DIRECTORY_SEPARATOR . 'GeoIP.dat', GEOIP_STANDARD);
$country = geoip_country_code_by_addr($gi, $ip);
$continent = geoip_region_by_addr($gi, $ip);
geoip_close($gi);
}
else
{
$country = geoip_country_code_by_name($ip);
$continent = geoip_continent_code_by_name($ip);
}
}
else
{
$country = '(unknown country)';
$continent = '(unknown country)';
}
// Construct the replacement table
$substitutions = array(
'[SITENAME]' => $sitename,
'[USERNAME]' => $username,
'[IP]' => $ip,
'[UASTRING]' => $_SERVER['HTTP_USER_AGENT'],
'[COUNTRY]' => $country,
'[CONTINENT]' => $continent
);
$subject = JText::_('ATOOLS_LBL_WAF_EMAILADMINLOGIN_SUBJECT_21');
$body = JText::_('ATOOLS_LBL_WAF_EMAILADMINLOGIN_BODY_21');
foreach ($substitutions as $k => $v)
{
$subject = str_replace($k, $v, $subject);
$body = str_replace($k, $v, $body);
}
// Send the email
$mailer = JFactory::getMailer();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$mailfrom = $config->get('mailfrom');
$fromname = $config->get('fromname');
}
else
{
$mailfrom = $config->getValue('config.mailfrom');
$fromname = $config->getValue('config.fromname');
}
$mailer->setSender(array($mailfrom, $fromname));
$mailer->addRecipient($this->cparams->getValue('emailonadminlogin', ''));
$mailer->setSubject($subject);
$mailer->setBody($body);
$mailer->Send();
// Set the flag to prevent sending more emails
$session->set('waf.loggedin', 1, 'plg_admintools');
}
/**
* Sends an email upon a failed administrator login
*
* @param $forcedFailure bool Wt to true to force a login failure trigger
*/
private function emailOnFailedAdminLogin($forcedFailure = false)
{
// Make sure we don't fire unless someone is still in the login page
$user = JFactory::getUser();
if (!$user->guest)
return;
if (version_compare(JVERSION, '3.0', 'ge'))
{
$input = new JInput();
$option = $input->getCmd('option');
$task = $input->getCmd('task');
}
else
{
$option = JRequest::getCmd('option');
$task = JRequest::getCmd('task');
}
if (($option != 'com_login') && !$forcedFailure)
return;
if (($task == 'login') || $forcedFailure)
{
// If we are STILL in the login task WITHOUT a valid user, we had a login failure.
// Load the component's administrator translation files
$jlang = JFactory::getLanguage();
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);
// Fetch the username
$username = JRequest::getString('username');
// Get the site name
$config = JFactory::getConfig();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$sitename = $config->get('sitename');
}
else
{
$sitename = $config->getValue('config.sitename');
}
// Get the IP address
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
if ((strpos($ip, '::') === 0) && (strstr($ip, '.') !== false))
{
$ip = substr($ip, strrpos($ip, ':') + 1);
}
// Send the email
$mailer = JFactory::getMailer();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$mailfrom = $config->get('mailfrom');
$fromname = $config->get('fromname');
}
else
{
$mailfrom = $config->getValue('config.mailfrom');
$fromname = $config->getValue('config.fromname');
}
$mailer->setSender(array($mailfrom, $fromname));
$mailer->addRecipient($this->cparams->getValue('emailonfailedadminlogin', ''));
$mailer->setSubject(JText::sprintf('ATOOLS_LBL_WAF_EMAILADMINFAILEDLOGIN_SUBJECT', $username, $sitename));
$mailer->setBody(JText::sprintf('ATOOLS_LBL_WAF_EMAILADMINFAILEDLOGIN_BODY', $username, $sitename, $ip, $sitename));
$mailer->Send();
}
}
private function trackFailedLogin()
{
$user = JRequest::getCmd('username', null);
$pass = JRequest::getCmd('password', null);
if (empty($pass))
$pass = JRequest::getCmd('passwd', null);
$extraInfo = null;
if (!empty($user))
{
if ($this->cparams->getValue('showpwonloginfailure', 1))
{
$extraInfo = 'Username: ' . $user . ' -- Password: ' . $pass;
}
else
{
$extraInfo = 'Username: ' . $user;
}
}
$this->logBreaches('loginfailure', $user, $extraInfo);
$autoban = $this->cparams->getValue('tsrenable', 0);
if ($autoban)
$this->autoBan('loginfailure');
}
/**
* Protects against a malicious User Agent string
*/
private function MUAShield()
{
// Some PHP binaries don't set the $_SERVER array under all platforms
if (!isset($_SERVER))
return;
if (!is_array($_SERVER))
return;
// Some user agents don't set a UA string at all
if (!array_key_exists('HTTP_USER_AGENT', $_SERVER))
return;
$mua = $_SERVER['HTTP_USER_AGENT'];
if (strstr($mua, '<?'))
{
$this->blockRequest('muashield');
}
}
private function CSRFShield_BASIC()
{
// Do not activate on GET, HEAD and TRACE requests
$method = strtoupper($_SERVER['REQUEST_METHOD']);
if (in_array($method, array('GET', 'HEAD', 'TRACE')))
return;
// Check the referer, if available
$valid = true;
$referer = array_key_exists('HTTP_REFERER', $_SERVER) ? $_SERVER['HTTP_REFERER'] : '';
if (!empty($referer))
{
$jRefURI = JURI::getInstance($referer);
$refererURI = $jRefURI->toString(array('host', 'port'));
$jSiteURI = JURI::getInstance();
$siteURI = $jSiteURI->toString(array('host', 'port'));
$valid = ($siteURI == $refererURI);
}
if (!$valid)
{
$this->blockRequest('csrfshield');
}
}
/**
* Applies basic HTTP referer filtering to POST, PUT, DELETE etc HTTP requests,
* usually associated with form submission.
*/
private function CSRFShield_GetFieldName()
{
static $fieldName = null;
if (empty($fieldName))
{
$config = JFactory::getConfig();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$sitename = $config->get('sitename');
$secret = $config->get('secret');
}
else
{
$sitename = $config->getValue('config.sitename');
$secret = $config->getValue('config.secret');
}
$fieldName = md5($sitename . $secret);
}
return $fieldName;
}
/**
* Applies advanced reverse CAPTCHA checks to POST, PUT, DELETE etc HTTP
* requests, usually associated with form submission.
*/
private function CSRFShield_ADVANCED()
{
// Do not activate on GET, HEAD and TRACE requests
$method = strtoupper($_SERVER['REQUEST_METHOD']);
if (in_array($method, array('GET', 'HEAD', 'TRACE')))
return;
// Check for the existence of a hidden field
$valid = true;
$hashes = array('get', 'post');
$hiddenFieldName = $this->CSRFShield_GetFieldName();
foreach ($hashes as $hash)
{
$allVars = JRequest::get('default', 2);
if (!array_key_exists($hiddenFieldName, $allVars))
continue;
if (!empty($allVars[$hiddenFieldName]))
{
$this->blockRequest('csrfshield');
}
}
}
/**
* Processes all forms on the page, adding a reverse CAPTCHA field
* for advanced filtering
*/
private function CSRFShield_PROCESS()
{
$hiddenFieldName = $this->CSRFShield_GetFieldName();
$buffer = JResponse::getBody();
$buffer = preg_replace('#<[\s]*/[\s]*form[\s]*>#iU', '<input type="text" name="' . $hiddenFieldName . '" value="" style="float: left; position: absolute; z-index: 1000000; left: -10000px; top: -10000px;" /></form>', $buffer);
JResponse::setBody($buffer);
}
/**
* Processes all forms on the page, adding a reverse CAPTCHA field
* for advanced filtering
*/
private function twoFactorAuthentication_process()
{
// Load the component's administrator translation files
$jlang = JFactory::getLanguage();
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);
$label = JText::_('COM_ADMINTOOLS_LOGIN_TWOFACTOR_LABEL');
$title = JText::_('COM_ADMINTOOLS_LOGIN_TWOFACTOR_TITLE');
// The are the "plain vanilla", catch-all settings
$regex = '#<[\s]*form.*>#iU';
$input = <<<ENDINPUT
<div class="admintools-security-code">
<label for="admintools-securitycode" title="$title">$label</label>
<input name="securitycode" id="admintools-securitycode" type="password" size="6" autocomplete="off" autofocus="autofocus" title="$title" />
<div class="clear"></div>
</div>
ENDINPUT;
if (version_compare(JVERSION, '3.0', 'lt'))
{
$template = JFactory::getApplication()->getTemplate();
if ($template == 'hathor')
{
// Joomla! 2.5, Hathor
$regex = '#<[\s]*fieldset[\s]*class[\s]*=[\s]*"loginform">#';
}
elseif ($template == 'rt_missioncontrol')
{
// Joomla! 2.5 Mission Control by RocketTheme
$regex = '#<[\s]*input[\s]*name[\s]*=[\s]*"passwd".*>#';
$input = <<<ENDINPUT
<input name="securitycode" id="admintools-securitycode" type="password" size="6" autocomplete="off" title="$title" placeholder="$label" class="inputbox" />
ENDINPUT;
}
}
else
{
// Joomla! 3.0 template conventions (Bootstrap FTW!)
$regex = '#<[\s]*fieldset[\s]*class[\s]*=[\s]*"loginform">#';
$input = <<<ENDINPUT
<div class="control-group">
<div class="controls">
<div class="input-prepend input-append">
<span class="add-on">
<i class="icon-puzzle" rel="tooltip" data-placement="left" data-original-title="$title"></i>
<label for="admintools-securitycode" class="element-invisible">$label</label>
</span><input tabindex="1" name="securitycode" id="admintools-securitycode" type="password" class="input-medium" size="6" autocomplete="off" title="$title" placeholder="$label" autofocus="autofocus" />
</div>
</div>
</div>
ENDINPUT;
}
$buffer = JResponse::getBody();
$buffer = preg_replace($regex, '\\0 ' . $input, $buffer);
JResponse::setBody($buffer);
}
private function twoFactorAuthentication_verify()
{
// Get the secret key
$secret = $this->cparams->getValue('twofactorauth_secret', '');
if (empty($secret))
return;
// Include Google Authenticator library
include_once dirname(__FILE__) . '/gaphp/googleauthenticator.php';
if (!class_exists('GoogleAuthenticator'))
return;
if (!class_exists('FixedBitNotation'))
return;
$code = JRequest::getVar('securitycode', '');
// Check for the panic code
$panic = $this->cparams->getValue('twofactorauth_panic', '');
$panic = preg_replace('#[^0-9]#', '', $panic);
$code = preg_replace('#[^0-9]#', '', $code);
if ($code == $panic)
return;
$googleAuth = new GoogleAuthenticator();
if (!$googleAuth->checkCode($secret, $code))
{
// Uh oh... Unauthorized access!
if (!$this->logBreaches('securitycode'))
return;
$autoban = $this->cparams->getValue('tsrenable', 0);
if ($autoban)
$this->autoBan('securitycode');
$this->redirectAdminToHome();
}
}
/**
* Simple Remote Files Inclusion block. If any query string parameter contains a reference to an http[s]:// or ftp[s]://
* address it will be scanned. If the remote file looks like a PHP script, we block access.
*/
private function RFIShield()
{
$hashes = array('get', 'post');
$regex = '#(http|ftp){1,1}(s){0,1}://.*#i';
foreach ($hashes as $hash)
{
$allVars = JRequest::get($hash, 2);
if (empty($allVars))
continue;
if ($this->match_array_and_scan($regex, $allVars))
{
$extraInfo = "Hash : $hash\n";
$extraInfo .= "Variables :\n";
$extraInfo .= print_r($allVars, true);
$extraInfo .= "\n";
$this->blockRequest('rfishield', null, $extraInfo);
}
}
}
private function match_array_and_scan($regex, $array)
{
$result = false;
if (is_array($array))
{
foreach ($array as $key => $value)
{
if (in_array($key, $this->exceptions))
continue;
if (is_array($value))
{
$result = $this->match_array_and_scan($regex, $value);
}
else
{
$result = preg_match($regex, $value);
}
if ($result)
{
// Can we fetch the file directly?
$fContents = @file_get_contents($value);
if (!empty($fContents))
{
$result = (strstr($fContents, '<?php') !== false);
if ($result)
break;
} else
{
$result = false;
}
}
}
}
elseif (is_string($array))
{
$result = preg_match($regex, $array);
if ($result)
{
// Can we fetch the file directly?
$fContents = @file_get_contents($value);
if (!empty($fContents))
{
$result = (strstr($fContents, '<?php') !== false);
if ($result)
break;
} else
{
$result = false;
}
}
}
return $result;
}
/**
* Runs the Project Honeypot HTTP:BL integration
*/
private function ProjectHoneypotHTTPBL()
{
// Load parameters
$httpbl_key = $this->cparams->getValue('bbhttpblkey', '');
$minthreat = $this->cparams->getValue('httpblthreshold', 25);
$maxage = $this->cparams->getValue('httpblmaxage', 30);
$suspicious = $this->cparams->getValue('httpblblocksuspicious', 0);
// Make sure we have an HTTP:BL key set
if (empty($httpbl_key))
return;
// Get the IP address
$reqip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
if ($reqip == '0.0.0.0')
return false;
if (strpos($reqip, '::') === 0)
{
$reqip = substr($reqip, strrpos($reqip, ':') + 1);
}
// No point continuing if we can't get an address, right?
if (empty($reqip))
return false;
// IPv6 addresses are not supported by HTTP:BL yet
if (strpos($reqip, ":"))
return false;
$find = implode('.', array_reverse(explode('.', $reqip)));
$result = gethostbynamel($httpbl_key . ".${find}.dnsbl.httpbl.org.");
if (!empty($result))
{
$ip = explode('.', $result[0]);
if ($ip[0] != 127)
return; // Make sure it's a valid response
if ($ip[3] == 0)
return; // Do not block search engines
$block = ($ip[3] & 2) || ($ip[3] & 4); // Block harvesters and comment spammers
if (!$suspicious && ($ip[3] & 1))
$block = false; // Do not block "suspicious" (not confirmed) IPs unless asked so
$block = $block && ($ip[1] <= $maxage);
$block = $block && ($ip[2] >= $minthreat);
if ($block)
{
$classes = array();
if ($ip[3] & 1)
$classes[] = 'Suspicious';
if ($ip[3] & 2)
$classes[] = 'Email Harvester';
if ($ip[3] & 4)
$classes[] = 'Comment Spammer';
$class = implode(', ', $classes);
$extraInfo = <<<ENDINFO
HTTP:BL analysis for blocked spammer's IP address $reqip
Attacker class : $class
Last activity : $ip[1] days ago
Threat level : $ip[2] --> see http://is.gd/mAwMTo for more info
ENDINFO;
$this->blockRequest('httpbl', '', $extraInfo);
}
}
}
private function geoBlocking()
{
if (!isset($_SERVER['REMOTE_ADDR']))
return;
$ip = $_SERVER['REMOTE_ADDR'];
$continents = $this->cparams->getValue('geoblockcontinents', '');
$continents = empty($continents) ? array() : explode(',', $continents);
$countries = $this->cparams->getValue('geoblockcountries', '');
$countries = empty($countries) ? array() : explode(',', $countries);
if (@file_exists(JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'geoip' . DIRECTORY_SEPARATOR . 'GeoIP.dat'))
{
if (!$this->hasGeoIPPECL)
{
require_once JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'helpers' . DIRECTORY_SEPARATOR . 'geoip.php';
$gi = geoip_open(JPATH_ADMINISTRATOR . DIRECTORY_SEPARATOR . 'components' . DIRECTORY_SEPARATOR . 'com_admintools' . DIRECTORY_SEPARATOR . 'assets' . DIRECTORY_SEPARATOR . 'geoip' . DIRECTORY_SEPARATOR . 'GeoIP.dat', GEOIP_STANDARD);
$country = geoip_country_code_by_addr($gi, $ip);
$continent = geoip_region_by_addr($gi, $ip);
geoip_close($gi);
}
else
{
$country = geoip_country_code_by_name($ip);
$continent = geoip_continent_code_by_name($ip);
}
}
else
{
$country = '(unknown country)';
$continent = '(unknown continent)';
}
if (($continent) && !empty($continents))
{
if (in_array($continent, $continents))
{
$extraInfo = 'Continent : ' . $continent;
$this->blockRequest('geoblocking', null, $extraInfo);
}
}
if (($country) && !empty($countries))
{
if (in_array($country, $countries))
{
$extraInfo = 'Country : ' . $country;
$this->blockRequest('geoblocking', null, $extraInfo);
}
}
}
/**
* Blocks visitors coming from an automatically banned IP. These suckers are repeat
* offenders. No courtesy from our part.
*/
private function AutoIPFiltering()
{
// We need to be able to get our own IP, right?
if (!function_exists('inet_pton'))
{
return;
}
// Get our IP address
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
if (empty($ip) || ($ip == '0.0.0.0'))
{
return;
}
$myIP = @inet_pton($ip);
if ($myIP === false)
{
return;
}
$myIP = inet_ntop($myIP);
// Let's get a list of blocked IP ranges
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->select('*')
->from($db->qn('#__admintools_ipautoban'))
->where($db->qn('ip') . ' = ' . $db->q($myIP));
$db->setQuery($sql);
$record = $db->loadObject();
if (empty($record))
{
return;
}
// Is this record expired?
JLoader::import('joomla.utilities.date');
$jNow = new JDate();
$jUntil = new JDate($record->until);
$now = $jNow->toUnix();
$until = $jUntil->toUnix();
if ($now > $until)
{
// Ban expired. Clear the entry and allow the request to proceed.
$sql = $db->getQuery(true)
->delete($db->qn('#__admintools_ipautoban'))
->where($db->qn('ip') . ' = ' . $db->q($myIPv4));
$db->setQuery($sql);
$db->execute();
return;
}
// Clean up old entries
$sql = $db->getQuery(true)
->delete($db->qn('#__admintools_ipautoban'))
->where($db->qn('until') . ' < ' . $db->q($jNow->toSql()));
$db->setQuery($sql);
$db->execute();
@ob_end_clean();
header("HTTP/1.0 403 Forbidden");
$spammerMessage = $this->cparams->getValue('spammermessage', '');
echo $spammerMessage;
JFactory::getApplication()->close();
}
private function autoBan($reason = 'other')
{
// We need to be able to get our own IP, right?
if (!function_exists('inet_pton'))
{
return;
}
// Get the IP
$ip = array_key_exists('REMOTE_ADDR', $_SERVER) ? htmlspecialchars($_SERVER['REMOTE_ADDR']) : '0.0.0.0';
// No point continuing if we can't get an address, right?
if (empty($ip) || ($ip == '0.0.0.0'))
{
return;
}
// Check for repeat offenses
$db = JFactory::getDBO();
$strikes = $this->cparams->getValue('tsrstrikes', 3);
$numfreq = $this->cparams->getValue('tsrnumfreq', 1);
$frequency = $this->cparams->getValue('tsrfrequency', 'hour');
$mindatestamp = 0;
switch ($frequency)
{
case 'second':
break;
case 'minute':
$numfreq *= 60;
break;
case 'hour':
$numfreq *= 3600;
break;
case 'day':
$numfreq *= 86400;
break;
case 'ever':
$mindatestamp = 946706400; // January 1st, 2000
break;
}
JLoader::import('joomla.utilities.date');
$jNow = new JDate();
if ($mindatestamp == 0)
{
$mindatestamp = $jNow->toUnix() - $numfreq;
}
$jMinDate = new JDate($mindatestamp);
$minDate = $jMinDate->toSql();
$sql = $db->getQuery(true)
->select('COUNT(*)')
->from($db->qn('#__admintools_log'))
->where($db->qn('logdate') . ' >= ' . $db->q($minDate))
->where($db->qn('ip') . ' = ' . $db->q($ip));
$db->setQuery($sql);
$numOffenses = $db->loadResult();
if ($numOffenses < $strikes)
{
return;
}
// Block the IP
$myIP = @inet_pton($ip);
if ($myIP === false)
{
return;
}
$myIP = inet_ntop($myIP);
$until = $jNow->toUnix();
$numfreq = $this->cparams->getValue('tsrbannum', 1);
$frequency = $this->cparams->getValue('tsrbanfrequency', 'hour');
switch ($frequency)
{
case 'second':
$until += $numfreq;
break;
case 'minute':
$numfreq *= 60;
$until += $numfreq;
break;
case 'hour':
$numfreq *= 3600;
$until += $numfreq;
break;
case 'day':
$numfreq *= 86400;
$until += $numfreq;
break;
case 'ever':
$until = 2145938400; // January 1st, 2038 (mind you, UNIX epoch runs out on January 19, 2038!)
break;
}
JLoader::import('joomla.utilities.date');
$jMinDate = new JDate($until);
$minDate = $jMinDate->toSql();
$record = (object) array(
'ip' => $myIP,
'reason' => $reason,
'until' => $minDate
);
$db->insertObject('#__admintools_ipautoban', $record);
// Send an optional email
if ($this->cparams->getValue('emailafteripautoban', ''))
{
// Get the site name
$config = JFactory::getConfig();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$sitename = $config->get('sitename');
}
else
{
$sitename = $config->getValue('config.sitename');
}
$substitutions = array(
'[SITENAME]' => $sitename,
'[IP]' => $myIP,
'[UNTIL]' => $minDate
);
// Load the component's administrator translation files
$jlang = JFactory::getLanguage();
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, 'en-GB', true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, $jlang->getDefault(), true);
$jlang->load('com_admintools', JPATH_ADMINISTRATOR, null, true);
$subject = JText::_('ATOOLS_LBL_WAF_AUTOIPBLOCKEMAIL_SUBJECT');
$body = JText::_('ATOOLS_LBL_WAF_AUTOIPBLOCKEMAIL_BODY');
foreach ($substitutions as $k => $v)
{
$subject = str_replace($k, $v, $subject);
$body = str_replace($k, $v, $body);
}
// Send the email
$mailer = JFactory::getMailer();
if (version_compare(JVERSION, '3.0', 'ge'))
{
$mailfrom = $config->get('mailfrom');
$fromname = $config->get('fromname');
}
else
{
$mailfrom = $config->getValue('config.mailfrom');
$fromname = $config->getValue('config.fromname');
}
$mailer->setSender(array($mailfrom, $fromname));
$mailer->addRecipient($this->cparams->getValue('emailafteripautoban', ''));
$mailer->setSubject($subject);
$mailer->setBody($body);
$mailer->Send();
}
}
/**
* Simple Direct Files Inclusion block.
*/
private function DFIShield()
{
if (version_compare(JVERSION, '3.0', 'ge'))
{
$input = new JInput();
$option = $input->getCmd('option', '');
$view = $input->getCmd('view', '');
$layout = $input->getCmd('layout', '');
}
else
{
$option = JRequest::getCmd('option', '');
$view = JRequest::getCmd('view', '');
$layout = JRequest::getCmd('layout', '');
}
// Special case: JCE
if (($option == 'com_jce') && ($view == 'editor') && ($layout == 'plugin'))
return;
$hashes = array('get', 'post');
foreach ($hashes as $hash)
{
$allVars = JRequest::get($hash, 2);
if (empty($allVars))
continue;
if ($this->match_array_dfi($allVars))
{
$extraInfo = "Hash : $hash\n";
$extraInfo .= "Variables :\n";
$extraInfo .= print_r($allVars, true);
$extraInfo .= "\n";
$this->blockRequest('dfishield', null, $extraInfo);
}
}
}
private function match_array_dfi($array)
{
$result = false;
if (is_array($array))
{
foreach ($array as $key => $value)
{
if (in_array($key, $this->exceptions))
continue;
// If there's a null byte in the key, break
if (strstr($key, "\u0000"))
{
$result = true;
break;
}
// If there's no value, treat the key as a value
if (empty($value))
$value = $key;
// Scan the value
if (is_array($value))
{
$result = $this->match_array_dfi($value);
}
else
{
// If there's a null byte, break
if (strstr($value, "\u0000"))
{
$result = true;
break;
}
// If the value starts with a /, ../ or [a-z]{1,2}:, block
if (preg_match('#^(/|\.\.|[a-z]{1,2}:\\\)#i', $value))
{
// Fix 2.0.1: Check that the file exists
$result = @file_exists($value);
if (!$result)
{
$sillyParts = explode('../', $value);
$realParts = array();
foreach ($sillyParts as $p)
if (!empty($p))
$realParts[] = $p;
$path = implode('/', $realParts);
$result = @file_exists($path);
}
break;
}
if ($result)
break;
}
}
}
return $result;
}
/**
* Scans all uploaded files for PHP tags. This prevents uploading PHP files or crafted
* images with raw PHP code in them which may lead to arbitrary code execution under
* several common circumstances. It will also block files with null bytes in their
* filenames or with double extensions which include PHP in them (e.g. .php.jpg).
*/
private function UploadShield()
{
// Do we have uploaded files?
$filesHash = JRequest::get('FILES', 2);
if (empty($filesHash))
return;
$extraInfo = '';
foreach ($filesHash as $key => $descriptor)
{
if (is_array($descriptor) && !array_key_exists('tmp_name', $descriptor))
{
$descriptors = $descriptor;
}
else
{
$descriptors[] = $descriptor;
}
unset($descriptor);
foreach ($descriptors as $descriptor)
{
$files = array();
if (is_array($descriptor['tmp_name']))
{
foreach ($descriptor['tmp_name'] as $key => $value)
{
$files[] = array(
'name' => $descriptor['name'][$key],
'type' => $descriptor['type'][$key],
'tmp_name' => $descriptor['tmp_name'][$key],
'error' => $descriptor['error'][$key],
'size' => $descriptor['size'][$key],
);
}
}
else
{
$files[] = $descriptor;
}
foreach ($files as $fileDescriptor)
{
$tempNames = $fileDescriptor['tmp_name'];
$intendedNames = $fileDescriptor['name'];
if (!is_array($tempNames))
{
$tempNames = array($tempNames);
}
if (!is_array($intendedNames))
{
$intendedNames = array($intendedNames);
}
$len = count($tempNames);
for ($i = 0; $i < $len; $i++)
{
$tempName = array_shift($tempNames);
$intendedName = array_shift($intendedNames);
$extraInfo = "File descriptor :\n";
$extraInfo .= print_r($fileDescriptor, true);
$extraInfo .= "\n";
// 1. Null byte check
if (strstr($intendedName, "\u0000"))
{
$this->blockRequest('uploadshield', null, $extraInfo);
return;
}
// 2. PHP-in-extension check
$explodedName = explode('.', $intendedName);
array_reverse($explodedName);
// 2a. File extension is .php
if ((count($explodedName) > 1) && (strtolower($explodedName[0]) == 'php'))
{
$this->blockRequest('uploadshield', null, $extraInfo);
return;
}
// 2a. File extension is php.xxx
if ((count($explodedName) > 2) && (strtolower($explodedName[1]) == 'php'))
{
$this->blockRequest('uploadshield', null, $extraInfo);
return;
}
// 2b. File extensions is php.xxx.yyy
if ((count($explodedName) > 3) && (strtolower($explodedName[2]) == 'php'))
{
$this->blockRequest('uploadshield', null, $extraInfo);
return;
}
// 3. Contents scanner
$fp = @fopen($tempName, 'r');
if ($fp !== false)
{
$data = '';
$extension = strtolower($explodedName[0]);
while (!feof($fp))
{
$buffer = @fread($fp, 131072);
$data .= $buffer;
if (strstr($buffer, '<?php'))
{
$this->blockRequest('uploadshield', null, $extraInfo);
return;
}
if (in_array($extension, array('inc', 'phps', 'class', 'php3', 'php4', 'txt', 'dat', 'tpl', 'tmpl')))
{
// These are suspicious text files which may have the short tag (<?) in them
if (strstr($buffer, '<?'))
{
$this->blockRequest('uploadshield', null, $extraInfo);
return;
}
}
$data = substr($data, -4);
}
fclose($fp);
}
} // end for
} // end foreach
}
}
}
/**
* Tries to figure out if the given query string looks like an XSS attack. It's not watertight,
* but it's better than nothing.
*
* Based largely on CodeIgniter's XSS cleanup code by EllisLab
*
* @param string $str The string to filter
*/
private function looksLikeXSS($str)
{
// 1. Non-displayable character filtering
static $non_displayables = null;
if (is_null($non_displayables))
{
// All control characters except newline, carriage return, and horizontal tab (dec 09)
$non_displayables = array(
'/%0[0-8bcef]/', // url encoded 00-08, 11, 12, 14, 15
'/%1[0-9a-f]/', // url encoded 16-31
'/[\x00-\x08]/', // 00-08
'/\x0b/', '/\x0c/', // 11, 12
'/[\x0e-\x1f]/' // 14-31
);
}
foreach ($non_displayables as $pattern)
{
$result = preg_match($pattern, $str);
if ($result)
return true;
}
// 2. Partial standard character entities
$test = preg_replace('#(&\#?[0-9a-z]{2,})([\x00-\x20])*;?#i', "\\1;\\2", $str);
if ($test != $str)
return true;
// 3. Partial UTF16 two byte encoding
$test = preg_replace('#(&\#x?)([0-9A-F]+);?#i', "\\1\\2;", $str);
if ($test != $str)
return true;
// 4. Conditioning
// In this step we try to unwrap commonly encoded payloads for the next steps to work
// 4a. URL decoding, in case an attacker tries to use URL-encoded payloads
// Note: rawurldecode() is used to avoid decoding plus signs
$str = rawurldecode($str);
// 4b. Convert character entities to ASCII, as they are used a lot in XSS attacks
$str = preg_replace_callback("/[a-z]+=([\'\"]).*?\\1/si", array($this, 'attribute_callback'), $str);
$str = preg_replace_callback("/<\w+.*?(?=>|<|$)/si", array($this, 'html_entity_decode_callback'), $str);
// 5. Non-displayable character filtering (second pass, now that we decoded some more entities!)
foreach ($non_displayables as $pattern)
{
$result = preg_match($pattern, $str);
if ($result)
return true;
}
// 6. Convert tab to spaces. Attackers may use ja vascript to pass malicious code to us.
if (strpos($str, "\t") !== FALSE)
{
$str = str_replace("\t", ' ', $str);
}
// Store the converted string for later comparison
$converted_string = $str;
// 7. Filter out unsafe strings from list
static $never_allowed_str = null;
if (is_null($never_allowed_str))
{
$never_allowed_str = array(
'document.cookie',
'document.write',
'.parentNode',
'.innerHTML',
'window.location',
'-moz-binding',
'<!--',
'-->',
'<![CDATA['
);
}
foreach ($never_allowed_str as $never)
{
if (strstr($str, $never) !== false)
return true;
}
// 8. Filter out unsafe strings from list of regular expressions
static $never_allowed_regex = null;
if (empty($never_allowed_regex))
{
$never_allowed_regex = array(
"javascript\s*:",
"expression\s*(\(|&\#40;)",
"vbscript\s*:",
"Redirect\s+302",
);
}
foreach ($never_allowed_regex as $pattern)
{
if (preg_match('#' . $pattern . '#i', $str))
return true;
}
// 9. PHP filtering
// Let's make sure that PHP tags (<? or <?php) are not present, while ensuring that
// XML tags (<?xml) are not touched
if ($this->cparams->getValue('xssshield_allowphp', 0) != 1)
{
$safe = str_replace('<?xml', '--xml', $str);
if (strstr($safe, '<?'))
return true;
}
// 10. Compact exploded words like j a v a s c r i p t => javascript
static $words = null;
if (is_null($words))
{
$words = array('javascript', 'expression', 'vbscript', 'script', 'applet', 'alert', 'document', 'write', 'cookie', 'window');
}
foreach ($words as $word)
{
$temp = '';
for ($i = 0, $wordlen = strlen($word); $i < $wordlen; $i++)
{
$temp .= substr($word, $i, 1) . "\s*";
}
// We only want to do this when it is followed by a non-word character
$str = preg_replace_callback('#(' . substr($temp, 0, -3) . ')(\W)#is', array($this, 'compact_exploded_words_callback'), $str);
}
// 11. Check for disallowed Javascript in links or img tags
$original = $str;
if (preg_match("/<a/i", $str))
{
$str = preg_replace_callback("#<a\s+([^>]*?)(>|$)#si", array($this, 'js_link_removal'), $str);
}
if ($str != $original)
return true;
if (preg_match("/<img/i", $str))
{
$str = preg_replace_callback("#<img\s+([^>]*?)(\s?/?>|$)#si", array($this, 'js_img_removal'), $str);
}
if ($str != $original)
return true;
if (preg_match("/script/i", $str) OR preg_match("/xss/i", $str))
{
$str = preg_replace("#<(/*)(script|xss)(.*?)\>#si", '[removed]', $str);
}
if ($str != $original)
return true;
// 11. Detect Javascript event handlers
$event_handlers = array('[^a-z_\-]on\w*', 'xmlns');
$str = preg_replace("#<([^><]+?)(" . implode('|', $event_handlers) . ")(\s*=\s*[^><]*)([><]*)#i", "<\\1\\4", $str);
if ($str != $original)
return true;
// 12. Detect naughty PHP and Javascript code commonly used in exploits
$result = preg_match('#(alert|cmd|passthru|eval|exec|expression|system|fopen|fsockopen|file|file_get_contents|readfile|unlink)(\s*)\((.*?)\)#si', $str);
if ($result)
return true;
// -- At this point, the string has passed all XSS filters. We hope it contains nothing malicious
// -- so we will report it as non-XSS.
return false;
}
private function attribute_callback($match)
{
return str_replace(array('>', '<', '\\'), array('>', '<', '\\\\'), $match[0]);
}
private function html_entity_decode_callback($match)
{
$str = $match[0];
if (stristr($str, '&') === FALSE)
return $str;
$str = html_entity_decode($str, ENT_COMPAT, 'UTF-8');
$str = preg_replace('~&#x(0*[0-9a-f]{2,5})~ei', 'chr(hexdec("\\1"))', $str);
return preg_replace('~&#([0-9]{2,4})~e', 'chr(\\1)', $str);
}
private function compact_exploded_words_callback($matches)
{
return preg_replace('/\s+/s', '', $matches[1]) . $matches[2];
}
private function js_link_removal($match)
{
$attributes = $this->filter_attributes(str_replace(array('<', '>'), '', $match[1]));
return str_replace($match[1], preg_replace("#href=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
}
function js_img_removal($match)
{
$attributes = $this->filter_attributes(str_replace(array('<', '>'), '', $match[1]));
return str_replace($match[1], preg_replace("#src=.*?(alert\(|alert&\#40;|javascript\:|charset\=|window\.|document\.|\.cookie|<script|<xss|base64\s*,)#si", "", $attributes), $match[0]);
}
function filter_attributes($str)
{
$out = '';
if (preg_match_all('#\s*[a-z\-]+\s*=\s*(\042|\047)([^\\1]*?)\\1#is', $str, $matches))
{
foreach ($matches[0] as $match)
{
$out .= preg_replace("#/\*.*?\*/#s", '', $match);
}
}
return $out;
}
private function match_array_xss($array)
{
// Safe keys, i.e. keys which may contain stuff which looks like an XSS attack
// TODO Move them to WAF Configuration
static $safe_keys = array('password', 'passwd', 'token', '_token', 'password1', 'password2', 'text');
$result = false;
if (is_array($array))
{
foreach ($array as $key => $value)
{
if (in_array($key, $safe_keys))
continue;
if (!in_array($key, $this->exceptions))
continue;
// If there's no value, treat the key as a value
if (empty($value))
$value = $key;
// Make sure the key is not an XSS attack
// if($this->looksLikeXSS($key)) return true;
// Scan the value
if (is_array($value))
{
$result = $this->match_array_xss($value);
}
else
{
$result = $this->looksLikeXSS($value);
if ($result)
break;
}
}
}
return $result;
}
/**
* Simple XSS attack block.
*/
private function XSSShield()
{
$hashes = array('get', 'post');
foreach ($hashes as $hash)
{
$allVars = JRequest::get($hash, 2);
if (empty($allVars))
continue;
if ($this->match_array_xss($allVars))
{
$extraInfo = "Hash : $hash\n";
$extraInfo .= "Variables :\n";
$extraInfo .= print_r($allVars, true);
$extraInfo .= "\n";
$this->blockRequest('xssshield', null, $extraInfo);
}
}
}
/**
* Purges old log entries
*/
private function purgeLog()
{
$minutes = (int) $this->params->get('purgelog_freq', 0);
if ($minutes <= 0)
return;
$lastJob = $this->getTimestamp('purge_log');
$nextJob = $lastJob + $minutes * 60;
JLoader::import('joomla.utilities.date');
$now = new JDate();
if ($now->toUnix() >= $nextJob)
{
$this->setTimestamp('purge_log');
$maxage = (int) $this->params->get('purgelog_age', 0);
$maxage = 24 * 3600 * $maxage;
if ($maxage > 0)
{
$now = time();
$oldest = $now - $maxage;
$jOldest = new JDate($oldest);
$mOldest = $jOldest->toSql();
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->delete($db->qn('#__admintools_log'))
->where($db->qn('logdate') . ' < ' . $db->q($mOldest));
$db->setQuery($sql);
$db->execute();
}
}
}
function &_getUser($user, $options = array())
{
JLoader::import('joomla.user.helper');
$instance = new JUser();
if ($id = intval(JUserHelper::getUserId($user['username'])))
{
$instance->load($id);
return $instance;
}
JLoader::import('joomla.application.component.helper');
$config = JComponentHelper::getParams('com_users');
$defaultUserGroup = $config->get('new_usertype', 2);
$acl = JFactory::getACL();
$instance->set('id', 0);
$instance->set('name', $user['fullname']);
$instance->set('username', $user['username']);
$instance->set('password_clear', $user['password_clear']);
$instance->set('email', $user['email']); // Result should contain an email (check)
$instance->set('usertype', 'deprecated');
$instance->set('groups', array($defaultUserGroup));
return $instance;
}
private function loadExceptions()
{
// REMOVED - This doesn't work if this plugin is published BEFORE the
// SEF router plugin (default)
/*
$app = JFactory::getApplication();
if(!in_array($app->getName(),array('administrator','admin'))) {
// We have to run the SQLiShield once, before parsing the URL through the router
if($this->cparams->getValue('sqlishield',0) == 1) $this->SQLiShield();
}
// Break down the route
$uri = clone JURI::getInstance();
$app = JFactory::getApplication();
$router = $app->getRouter();
$result = $router->parse($uri);
JRequest::set($result, 'get', false);
*/
// Now, proceed
if (version_compare(JVERSION, '3.0', 'ge'))
{
$input = new JInput();
$option = $input->getCmd('option', '');
$view = $input->getCmd('view', '');
}
else
{
$option = JRequest::getCmd('option', '');
$view = JRequest::getCmd('view', '');
}
/*
if(empty($option) && array_key_exists('option', $result)) $option = $result['option'];
if(empty($view) && array_key_exists('view', $result)) $view = $result['view'];
*/
$db = JFactory::getDBO();
$sql = $db->getQuery(true)
->select($db->qn('query'))
->from($db->qn('#__admintools_wafexceptions'));
if (empty($option))
{
$sql->where(
'(' . $db->qn('option') . ' IS NULL OR ' .
$db->qn('option') . ' = ' . $db->q('')
. ')'
);
}
else
{
$sql->where(
'(' . $db->qn('option') . ' IS NULL OR ' .
$db->qn('option') . ' = ' . $db->q('') . ' OR ' .
$db->qn('option') . ' = ' . $db->q($option)
. ')'
);
}
if (empty($view))
{
$sql->where(
'(' . $db->qn('view') . ' IS NULL OR ' .
$db->qn('view') . ' = ' . $db->q('')
. ')'
);
}
else
{
$sql->where(
'(' . $db->qn('view') . ' IS NULL OR ' .
$db->qn('view') . ' = ' . $db->q('') . ' OR ' .
$db->qn('view') . ' = ' . $db->q($view)
. ')'
);
}
$sql->group($db->qn('query'))
->order($db->qn('query') . ' ASC');
$db->setQuery($sql);
if (version_compare(JVERSION, '3.0', 'ge'))
{
$this->exceptions = $db->loadColumn();
}
else
{
$this->exceptions = $db->loadResultArray();
}
}
private function removeInactiveUsers()
{
// If the days are not at least 1, bail out
$filtertype = (int) $this->params->get('deleteinactive', 1);
$days = (int) $this->params->get('deleteinactive_days', 0);
if ($days <= 0)
return;
// Get up to 5 ids of users to remove
$db = JFactory::getDbo();
$sql = $db->getQuery(true)
->select($db->qn('id'))
->from($db->qn('#__users'))
->where($db->qn('lastvisitDate') . ' = ' . $db->q($db->getNullDate()))
->where($db->qn('registerDate') . ' <= ' . "DATE_SUB(NOW(), INTERVAL $days DAY)")
;
switch ($filtertype)
{
case 1:
// Only users not yet activated
$sql->where($db->qn('activation') . ' != ' . $db->quote(''));
break;
case 2:
// Only users already activated
$sql->where($db->qn('activation') . ' = ' . $db->quote(''));
break;
case 3:
// All users who haven't logged in
break;
}
$db->setQuery($sql, 0, 5);
if (version_compare(JVERSION, '3.0', 'ge'))
{
$ids = $db->loadColumn();
}
else
{
$ids = $db->loadResultArray();
}
// Remove those inactive users
if (!empty($ids))
{
foreach ($ids as $id)
{
$userToKill = JFactory::getUser($id);
$userToKill->delete();
}
}
}
private function loadTimestamps()
{
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select('*')
->from($db->quoteName('#__admintools_storage'))
->where($db->quoteName('key') . ' LIKE ' . $db->quote('timestamp_%'));
$db->setQuery($query);
$temp = $db->loadAssocList();
$this->timestamps = array();
if (!empty($temp))
foreach ($temp as $item)
{
$this->timestamps[$item['key']] = $item['value'];
}
}
private function removeOldLogEntries()
{
// Delete up to 100 old entries
$maxEntries = $this->params->get('maxlogentries', 0);
$db = JFactory::getDbo();
$query = $db->getQuery(true)
->select($db->qn('id'))
->from($db->qn('#__admintools_log'))
->order($db->qn('id') . ' DESC');
$db->setQuery($query, $maxEntries, 100);
$ids = $db->loadColumn(0);
if (!count($ids))
return;
$temp = array();
foreach ($ids as $id)
{
$temp = $db->q($id);
}
$ids = implode(',', $ids);
$query = $db->getQuery(true)
->delete($db->qn('#__admintools_log'))
->where($db->qn('id') . ' IN(' . $ids . ')');
$db->setQuery($query);
try
{
$db->execute();
}
catch (Exception $exc)
{
// Do nothing on DB exception
}
}
}