shell bypass 403
<?php
/**
* @package admintools
* @copyright Copyright (c)2010-2024 Nicholas K. Dionysopoulos / Akeeba Ltd
* @license GNU General Public License version 3, or later
*/
namespace Akeeba\Plugin\Actionlog\AdminTools\Extension;
defined('_JEXEC') or die;
use Akeeba\Component\AdminTools\Administrator\Controller\DatabasetoolsController;
use Akeeba\Component\AdminTools\Administrator\Model\DatabasetoolsModel;
use Akeeba\Component\AdminTools\Administrator\Model\ScanalertsModel;
use Joomla\CMS\Component\ComponentHelper;
use Joomla\CMS\MVC\Controller\BaseController;
use Joomla\CMS\User\User;
use Joomla\Component\Actionlogs\Administrator\Plugin\ActionLogPlugin;
use Joomla\Event\Event;
use Joomla\Event\SubscriberInterface;
use Joomla\String\Inflector;
use ReflectionMethod;
class AdminTools extends ActionLogPlugin implements SubscriberInterface
{
/**
* Load the language file on instantiation.
*
* @var boolean
* @since 3.1
*/
protected $autoloadLanguage = true;
private $defaultExtension = 'com_admintools';
/**
* Returns an array of events this subscriber will listen to.
*
* @return array
*
* @since 9.0.0
*/
public static function getSubscribedEvents(): array
{
// Only subscribe events if the component is installed and enabled
if (!ComponentHelper::isEnabled('com_akeebabackup'))
{
return [];
}
// Register all public onSomething methods as event handlers
$events = [];
$refClass = new \ReflectionClass(__CLASS__);
$methods = $refClass->getMethods(ReflectionMethod::IS_PUBLIC);
foreach ($methods as $method)
{
$name = $method->getName();
if (substr($name, 0, 2) != 'on')
{
continue;
}
$events[$name] = $name;
}
return $events;
}
public function onComAdmintoolsAdminallowlistControllerAfterApply($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_WHITELISTEDADDRESSES_EDIT_2');
}
public function onComAdmintoolsAdminallowlistControllerAfterSave($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_WHITELISTEDADDRESSES_EDIT_2');
}
public function onComAdmintoolsAdminallowlistControllerAfterSave2new($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_WHITELISTEDADDRESSES_EDIT_2');
}
public function onComAdmintoolsAdminallowlistsControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'ip', 'COM_ADMINTOOLS_LOGS_WHITELISTEDADDRESSES_DELETE');
}
public function onComAdmintoolsAdminpasswordControllerBeforeProtect($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_ADMINPASSWORD_ENABLE', 'com_admintools');
}
public function onComAdmintoolsAdminpasswordControllerBeforeUnprotect($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_ADMINPASSWORD_DISABLE', 'com_admintools');
}
public function onComAdmintoolsAutobannedaddressesControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'ip', 'COM_ADMINTOOLS_LOGS_AUTOBANNEDADDRESSES_DELETE');
}
public function onComAdmintoolsBadwordControllerAfterApply($event)
{
$this->logCRUDSave($event, 'id', 'word', 'COM_ADMINTOOLS_LOGS_BADWORDS_EDIT_2');
}
public function onComAdmintoolsBadwordControllerAfterSave($event)
{
$this->logCRUDSave($event, 'id', 'word', 'COM_ADMINTOOLS_LOGS_BADWORDS_EDIT_2');
}
public function onComAdmintoolsBadwordControllerAfterSave2new($event)
{
$this->logCRUDSave($event, 'id', 'word', 'COM_ADMINTOOLS_LOGS_BADWORDS_EDIT_2');
}
public function onComAdmintoolsBadwordsControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'word', 'COM_ADMINTOOLS_LOGS_BADWORDS_DELETE');
}
public function onComAdmintoolsBlockedrequestslogControllerBeforeBan($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_SECURITYEXCEPTIONS_BAN_2');
}
public function onComAdmintoolsBlockedrequestslogControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'ip', 'COM_ADMINTOOLS_LOGS_SECURITYEXCEPTIONS_DELETE');
}
public function onComAdmintoolsBlockedrequestslogControllerBeforeUnban($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_SECURITYEXCEPTIONS_UNBAN_2');
}
public function onComAdmintoolsChecktempandlogdirectoriesControllerBeforeCheck($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_CHECKTEMPANDLOGDIRECTORIES_RUN', 'com_admintools');
}
public function onComAdmintoolsCleantempdirectoryControllerBeforeMain($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_CLEANTEMPDIRECTORY_RUN', 'com_admintools');
}
public function onComAdmintoolsConfigurepermissionsControllerAfterSavedefaults($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_CONFIGUREFIXPERMISSIONS_DEFAULTS', 'com_admintools');
}
public function onComAdmintoolsConfigurepermissionsControllerBeforeSaveapplyperms($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_CONFIGUREFIXPERMISSIONS_SAVEAPPLYPERMS', 'com_admintools');
}
public function onComAdmintoolsConfigurepermissionsControllerBeforeSaveperms($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_CONFIGUREFIXPERMISSIONS_SAVEPERMS', 'com_admintools');
}
public function onComAdmintoolsConfigurewafControllerAfterApply($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_CONFIGUREWAF_EDIT', 'com_admintools');
}
public function onComAdmintoolsConfigurewafControllerAfterSave($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_CONFIGUREWAF_EDIT', 'com_admintools');
}
/**
* @param DatabasetoolsController $controller
*/
public function onComAdmintoolsDatabasetoolsControllerAfterOptimize($event)
{
$arguments = array_values($event->getArguments());
/** @var BaseController $controller */
$controller = $arguments[0];
/** @var DatabasetoolsModel $model */
$model = $controller->getModel();
$percent = $model->getState('percent', 0);
if ($percent >= 100)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_DATABASETOOLS_REPAIR', 'com_admintools');
}
}
public function onComAdmintoolsDatabasetoolsControllerBeforePurgesessions($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_DATABASETOOLS_PURGESESSIONS', 'com_admintools');
}
public function onComAdmintoolsEmergencyofflineControllerBeforeOffline($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_EMERGENCYOFFLINE_ENABLE', 'com_admintools');
}
public function onComAdmintoolsEmergencyofflineControllerBeforeOnline($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_EMERGENCYOFFLINE_DISABLE', 'com_admintools');
}
public function onComAdmintoolsExportimportControllerBeforeDoexport($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_IMPORANDEXPORT_EXPORT', 'com_admintools');
}
public function onComAdmintoolsExportimportControllerBeforeDoimport($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_IMPORANDEXPORT_IMPORT', 'com_admintools');
}
public function onComAdmintoolsFixpermissionsControllerBeforeMain($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_FIXPERMISSIONS_RUN', 'com_admintools');
}
public function onComAdmintoolsHtaccessmakerControllerAfterApply($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_HTACCESSMAKER_EDIT', 'com_admintools');
}
public function onComAdmintoolsHtaccessmakerControllerAfterSave($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_HTACCESSMAKER_EDIT', 'com_admintools');
}
public function onComAdmintoolsIPDenyListControllerAfterApply($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_BLACKLISTEDADDRESSES_EDIT_2');
}
/* Start of CRUD tasks */
public function onComAdmintoolsIPDenyListControllerAfterSave($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_BLACKLISTEDADDRESSES_EDIT_2');
}
public function onComAdmintoolsIPDenyListControllerAfterSave2new($event)
{
$this->logCRUDSave($event, 'id', 'ip', 'COM_ADMINTOOLS_LOGS_BLACKLISTEDADDRESSES_EDIT_2');
}
public function onComAdmintoolsIPDenyListsControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'ip', 'COM_ADMINTOOLS_LOGS_BLACKLISTEDADDRESSES_DELETE');
}
public function onComAdmintoolsIpautobanhistoriesControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'ip', 'COM_ADMINTOOLS_LOGS_IPAUTOBANHISTORIES_DELETE');
}
public function onComAdmintoolsMainpasswordControllerAfterApply($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_MASTERPASSWORD_EDIT', 'com_admintools');
}
public function onComAdmintoolsMainpasswordControllerAfterSave($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_MASTERPASSWORD_EDIT', 'com_admintools');
}
public function onComAdmintoolsNginxconfmakerControllerAfterApply($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_NGINXCONFMAKER_EDIT', 'com_admintools');
}
public function onComAdmintoolsNginxconfmakerControllerAfterSave($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_NGINXCONFMAKER_EDIT', 'com_admintools');
}
public function onComAdmintoolsQuickstartControllerAfterCommit($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_QUICKSTART_SAVE', 'com_admintools');
}
public function onComAdmintoolsScanalertsControllerAfterMarkallsafe($event)
{
$scan_id = $this->getApplication()->input->getInt('scan_id', 0);
if (empty($scan_id))
{
return;
}
$this->logUserAction($scan_id, 'COM_ADMINTOOLS_LOGS_SCANALERTS_MARKEDALLSAFE', 'com_admintools');
}
public function onComAdmintoolsScanalertsControllerAfterPublish($event)
{
$arguments = array_values($event->getArguments());
/** @var BaseController $controller */
$controller = $arguments[0];
/** @var ScanalertsModel $model */
$model = $controller->getModel();
$ids = $this->getIDsFromRequest();
if (!$ids)
{
return;
}
$table = $model->getTable('Scanalert', 'Administrator');
foreach ($ids as $id)
{
if (!$table->load($id))
{
continue;
}
$this->logUserAction($table->path, 'COM_ADMINTOOLS_LOGS_SCANALERTS_MARKEDSAFE', 'com_admintools');
}
}
public function onComAdmintoolsScanalertsControllerAfterUnpublish($event)
{
$arguments = array_values($event->getArguments());
/** @var BaseController $controller */
$controller = $arguments[0];
/** @var ScanalertsModel $model */
$model = $controller->getModel();
$ids = $this->getIDsFromRequest();
if (!$ids)
{
return;
}
$table = $model->getTable('Scanalert', 'Administrator');
foreach ($ids as $id)
{
if (!$table->load($id))
{
continue;
}
$this->logUserAction($table->path, 'COM_ADMINTOOLS_LOGS_SCANALERTS_MARKEDUNSAFE', 'com_admintools');
}
}
public function onComAdmintoolsScansControllerBeforeStartscan($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_SCANS_RUN', 'com_admintools');
}
public function onComAdmintoolsSeoandlinktoolsControllerAfterApply($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_SEOANDLINKTOOLS_EDIT', 'com_admintools');
}
public function onComAdmintoolsSeoandlinktoolsControllerAfterSave($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_SEOANDLINKTOOLS_EDIT', 'com_admintools');
}
public function onComAdmintoolsUrlredirectionControllerAfterApply($event)
{
$this->logCRUDSave($event, 'id', 'dest', 'COM_ADMINTOOLS_LOGS_REDIRECTIONS_EDIT_2');
}
public function onComAdmintoolsUrlredirectionControllerAfterSave($event)
{
$this->logCRUDSave($event, 'id', 'dest', 'COM_ADMINTOOLS_LOGS_REDIRECTIONS_EDIT_2');
}
public function onComAdmintoolsUrlredirectionControllerAfterSave2new($event)
{
$this->logCRUDSave($event, 'id', 'dest', 'COM_ADMINTOOLS_LOGS_REDIRECTIONS_EDIT_2');
}
public function onComAdmintoolsUrlredirectionsControllerAfterPublish($event)
{
$this->logCRUDAction($event, 'dest', 'COM_ADMINTOOLS_LOGS_REDIRECTIONS_PUBLISH_2');
}
public function onComAdmintoolsUrlredirectionsControllerAfterUnpublish($event)
{
$this->logCRUDAction($event, 'dest', 'COM_ADMINTOOLS_LOGS_REDIRECTIONS_UNPUBLISH_2');
}
public function onComAdmintoolsUrlredirectionsControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'dest', 'COM_ADMINTOOLS_LOGS_REDIRECTIONS_DELETE');
}
public function onComAdmintoolsWafdenylistControllerAfterApply($event)
{
$this->logCRUDSave($event, 'id', 'id', 'COM_ADMINTOOLS_LOGS_WAFBLACKLIST_EDIT_2');
}
public function onComAdmintoolsWafdenylistControllerAfterSave($event)
{
$this->logCRUDSave($event, 'id', 'id', 'COM_ADMINTOOLS_LOGS_WAFBLACKLIST_EDIT_2');
}
public function onComAdmintoolsWafdenylistControllerAfterSave2new($event)
{
$this->logCRUDSave($event, 'id', 'id', 'COM_ADMINTOOLS_LOGS_WAFBLACKLIST_EDIT_2');
}
public function onComAdmintoolsWafdenylistsControllerAfterDelete($event)
{
$this->logCRUDAction($event, 'id', 'COM_ADMINTOOLS_LOGS_WAFBLACKLIST_DELETE');
}
public function onComAdmintoolsWafdenylistsControllerAfterPublish($event)
{
$this->logCRUDAction($event, 'id', 'COM_ADMINTOOLS_LOGS_WAFBLACKLIST_PUBLISH_2');
}
public function onComAdmintoolsWafdenylistsControllerAfterUnpublish($event)
{
$this->logCRUDAction($event, 'id', 'COM_ADMINTOOLS_LOGS_WAFBLACKLIST_UNPUBLISH_2');
}
public function onComAdmintoolsWafexceptionControllerAfterApply($event)
{
$this->logCRUDSave($event, 'id', 'id', 'COM_ADMINTOOLS_LOGS_WAFEXCEPTIONS_EDIT_2');
}
public function onComAdmintoolsWafexceptionControllerAfterSave($event)
{
$this->logCRUDSave($event, 'id', 'id', 'COM_ADMINTOOLS_LOGS_WAFEXCEPTIONS_EDIT_2');
}
public function onComAdmintoolsWafexceptionControllerAfterSave2new($event)
{
$this->logCRUDSave($event, 'id', 'id', 'COM_ADMINTOOLS_LOGS_WAFEXCEPTIONS_EDIT_2');
}
public function onComAdmintoolsWafexceptionsControllerBeforeDelete($event)
{
$this->logCRUDAction($event, 'id', 'COM_ADMINTOOLS_LOGS_WAFEXCEPTIONS_DELETE');
}
public function onComAdmintoolsWebconfigmakerControllerAfterApply($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_WEBCONFIGMAKER_EDIT', 'com_admintools');
}
public function onComAdmintoolsWebconfigmakerControllerAfterSave($event)
{
$this->logUserAction('', 'COM_ADMINTOOLS_LOGS_WEBCONFIGMAKER_EDIT', 'com_admintools');
}
/* End of CRUD tasks */
/**
* Gets the list of IDs from the request data
*
* @return array
*/
private function getIDsFromRequest()
{
// Get the ID or list of IDs from the request or the configuration
$cid = $this->getApplication()->input->get('cid', [], 'array');
$id = $this->getApplication()->input->getInt('id', 0);
$ids = [];
if (is_array($cid) && !empty($cid))
{
$ids = $cid;
}
elseif (!empty($id))
{
$ids = [$id];
}
return $ids;
}
/**
* @param $controller
* @param string $displayKey
* @param string $translationKey
*/
private function logCRUDAction(Event $event, string $displayKey, string $translationKey): void
{
$arguments = array_values($event->getArguments());
/** @var BaseController $controller */
$controller = $arguments[0];
$ids = $this->getIDsFromRequest();
$model = $controller->getModel();
$tableName = $controller->getName();
try
{
$table = $model->getTable($tableName, 'Administrator');
}
catch (\Exception $e)
{
$tableName = Inflector::singularize($tableName);
$table = $model->getTable($tableName, 'Administrator');
}
foreach ($ids as $id)
{
if (!$table->load($id))
{
continue;
}
$primaryKey = $table->getKeyName(false);
$link = sprintf(
"index.php?option=com_admintools&view=%s&task=edit&%s=%s",
urlencode($tableName),
urlencode($primaryKey),
urlencode($table->{$primaryKey}));
$this->logUserAction([
'title' => $table->{$displayKey},
'link' => $link,
], $translationKey, 'com_admintools');
}
}
/**
* @param $controller
* @param string $primaryKey
* @param string $displayKey
* @param string $translationKey
*/
private function logCRUDSave(Event $event, string $primaryKey, string $displayKey, string $translationKey): void
{
$arguments = array_values($event->getArguments());
/** @var BaseController $controller */
$controller = $arguments[0];
$model = $controller->getModel();
$controllerName = $controller->getName();
$tableName = $controller->getName();
try
{
$table = $model->getTable($tableName, 'Administrator');
}
catch (\Exception $e)
{
$tableName = Inflector::singularize($tableName);
$table = $model->getTable($tableName, 'Administrator');
}
if (!$table->load($this->getApplication()->input->getInt($primaryKey)))
{
return;
}
$link = sprintf(
"index.php?option=com_admintools&view=%s&task=edit&%s=%s",
urlencode($controllerName),
urlencode($primaryKey),
urlencode($table->{$primaryKey}));
$this->logUserAction([
'title' => $table->{$displayKey},
'link' => $link,
], $translationKey, 'com_admintools');
}
/**
* Log a user action.
*
* This is a simple wrapper around self::addLog
*
* @param string|array $title Language key for title or an array of additional data to record in
* the audit log.
* @param string $messageLanguageKey Language key describing the user action taken.
* @param string|null $context The name of the extension being logged (default: use
* $this->defaultExtension).
* @param User|null $user User object taking this action (default: currently logged in user).
*
* @return void
*
* @see self::addLog
* @since 9.0.0
*/
private function logUserAction($title, string $messageLanguageKey, ?string $context = null, ?User $user = null): void
{
// Get the user if not defined
$user = $user ?? $this->getApplication()->getIdentity();
// No log for guests
if (empty($user) || ($user->guest))
{
return;
}
// Default extension if none defined
$context = $context ?? $this->defaultExtension;
$message = [
'username' => $user->username,
'accountlink' => 'index.php?option=com_users&task=user.edit&id=' . $user->id,
];
if (!is_array($title))
{
$title = [
'title' => $title,
];
}
$message = array_merge($message, $title);
$this->addLog([$message], $messageLanguageKey, $context, $user->id);
}
}