From 8fd1488ac2537836bb1c3fdb3e8a2d3a8ae70b4f Mon Sep 17 00:00:00 2001 From: Benjamin Burkhardt Date: Sun, 20 Mar 2022 11:57:35 +0100 Subject: [PATCH 01/32] added function file for fixing permissions --- src/SubCommands/FixFileAndDirPermissions.php | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 src/SubCommands/FixFileAndDirPermissions.php diff --git a/src/SubCommands/FixFileAndDirPermissions.php b/src/SubCommands/FixFileAndDirPermissions.php new file mode 100644 index 0000000..176c8a7 --- /dev/null +++ b/src/SubCommands/FixFileAndDirPermissions.php @@ -0,0 +1,6 @@ + \ No newline at end of file From 784e832cf3d3834f82791daa8e51b34d9cf831a4 Mon Sep 17 00:00:00 2001 From: Janw Oostendorp Date: Sun, 20 Mar 2022 12:29:58 +0100 Subject: [PATCH 02/32] Merged block-php in one sub command instead of several. --- src/FileManager.php | 12 +-- src/SecureCommand.php | 138 ++++++++++----------------------- src/SubCommands/SubCommand.php | 59 +++++++------- 3 files changed, 73 insertions(+), 136 deletions(-) diff --git a/src/FileManager.php b/src/FileManager.php index 14df81c..5a3d90f 100644 --- a/src/FileManager.php +++ b/src/FileManager.php @@ -82,7 +82,7 @@ private function setFileContent() : array { } if(!$this->isReadable()) { - throw new (FileIsNotReadable::class); + throw new FileIsNotReadable(); } return $this->read(); @@ -156,7 +156,7 @@ private function fileExist() : bool { * * @return array|string */ - private static function removeZeroSpace($content): array|string + private static function removeZeroSpace($content) { if(is_array($content)) { return array_map([static::class, 'removeZeroSpace'], $content); @@ -205,7 +205,7 @@ public function extractRuleBlock(string $marker) : array { * * @return int|bool */ - private function findInFile(string $needle) : int|bool { + private function findInFile(string $needle) { return array_search($needle, $this->file); } @@ -214,7 +214,7 @@ private function findInFile(string $needle) : int|bool { * * @return array|bool */ - public function extractSecureBlock(): bool|array { + public function extractSecureBlock() { $start = $this->findInFile(self::MARKER_GLOBAL_START . self::SPACE_DELIMITER . self::MARKER_WP_CLI_SECURE); $end = $this->findInFile(self::MARKER_GLOBAL_END . self::SPACE_DELIMITER . self::MARKER_WP_CLI_SECURE); @@ -330,7 +330,7 @@ private function backup() : bool public function add(array $content, string $marker = ''): bool { //If the rule block already exist, there is no reason to add it again if($this->hasRuleBlock($marker)) { - throw new(RuleAlreadyExist::class); + throw new RuleAlreadyExist(); } //Check if file exist? @@ -339,7 +339,7 @@ public function add(array $content, string $marker = ''): bool { } if(!$this->isWritable()) { - throw new(FileIsNotWritable::class); + throw new FileIsNotWritable(); } //Wrap the rule block with markers diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 4581823..d4b5158 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -86,71 +86,6 @@ public function disable_directory_browsing($args, $assoc_args) : void { (new DisableDirectoryBrowsing($assoc_args))->output(); } - /** - * Disables execution of PHP files in Themes. - * - * PHP files in themes directory shouldn't be directly accessible. This is important in case of malware injection as it prevents attacker from directly - * accessing infected PHP files - * - * ## OPTIONS - * - * [--remove] - * : Removes the rule from .htaccess or nginx.conf. - * - * [--output] - * : Use this option to display the actual code that you can manually copy and paste into some other file - * - * [--file-path=] - * : Set a custom path to the file which command should use to write rules into - * - * [--server=] - * : Set a server type. Possible options are "apache" and "nginx". Default is "apache" and all rules are stored in - * .htaccess file - * - * ## EXAMPLES - * - * $ wp secure block_php_execution_in_themes - * Success: Block Execution In Themes rule has been deployed. - * - * @when before_wp_load - */ - public function block_php_execution_in_themes($args, $assoc_args) : void { - (new BlockPhpExecutionInThemes($assoc_args))->output(); - } - - /** - * Disables execution of PHP files in Uploads. - * - * PHP files in `wp-content/uploads` directory shouldn't be directly accessible. This is important in case of malware injection as it prevents attacker from - * directly - * accessing infected PHP files - * - * ## OPTIONS - * - * [--remove] - * : Removes the rule from .htaccess or nginx.conf. - * - * [--output] - * : Use this option to display the actual code that you can manually copy and paste into some other file - * - * [--file-path=] - * : Set a custom path to the file which command should use to write rules into - * - * [--server=] - * : Set a server type. Possible options are "apache" and "nginx". Default is "apache" and all rules are stored in - * .htaccess file - * - * ## EXAMPLES - * - * $ wp secure block_php_execution_in_uploads - * Success: Block Execution In Uploads Directory rule has been deployed. - * - * @when before_wp_load - */ - public function block_php_execution_in_uploads($args, $assoc_args) : void { - (new BlockPhpExecutionInUploads($assoc_args))->output(); - } - /** * Disables execution of PHP files in Plugins. * @@ -159,6 +94,9 @@ public function block_php_execution_in_uploads($args, $assoc_args) : void { * * ## OPTIONS * + * + * : Required. accepts: plugins, uploads, includes, themes or all. + * * [--remove] * : Removes the rule from .htaccess or nginx.conf. * @@ -174,45 +112,47 @@ public function block_php_execution_in_uploads($args, $assoc_args) : void { * * ## EXAMPLES * - * $ wp secure block_php_execution_in_plugins + * # Apply the block rules for plugins + * $ wp secure block-php plugins * Success: Block Execution In Plugins Directory rule has been deployed. * - * @when before_wp_load - */ - public function block_php_execution_in_plugins($args, $assoc_args) : void { - (new BlockPhpExecutionInPlugins($assoc_args))->output(); - } - - /** - * Disables execution of PHP files in wp-includes directory. - * - * PHP files in `wp-includes` directory shouldn't be directly accessible. This is important in case of malware injection as it prevents attacker - * from directly accessing infected PHP files - * - * ## OPTIONS - * - * [--remove] - * : Removes the rule from .htaccess or nginx.conf. - * - * [--output] - * : Use this option to display the actual code that you can manually copy and paste into some other file - * - * [--file-path=] - * : Set a custom path to the file which command should use to write rules into - * - * [--server=] - * : Set a server type. Possible options are "apache" and "nginx". Default is "apache" and all rules are stored in - * .htaccess file - * - * ## EXAMPLES - * - * $ wp secure block_php_execution_in_wp_includes - * Success: Block Execution In wp-includes Directory rule has been deployed. + * # Apply the block rules for all parts. + * $ wp secure block-php all + * Success: Block Execution In Plugins Directory rule has been deployed. * * @when before_wp_load + * + * @subcommand block-php */ - public function block_php_execution_in_wp_includes($args, $assoc_args) : void { - (new BlockPhpExecutionInWpIncludes($assoc_args))->output(); + public function block_php($args, $assoc_args) : void { + + $block_part = $args[0]; + + // Failure first. + if ( ! in_array( $block_part, + array( 'plugins', 'uploads', 'includes', 'themes', 'all' ), + true ) + ) { + WP_CLI::error( sprintf( 'Invalid block part "%s" was provided. Allowed values are "plugins", "uploads", "includes", "themes" or "all"', + $block_part ) ); + } + + if ( 'all' === $block_part || 'plugins' === $block_part ) { + var_dump( __LINE__ ); + ( new BlockPhpExecutionInPlugins( $assoc_args ) )->output(); + } + if ( 'all' === $block_part || 'uploads' === $block_part ) { + var_dump( __LINE__ ); + ( new BlockPhpExecutionInWpIncludes( $assoc_args ) )->output(); + } + if ( 'all' === $block_part || 'includes' === $block_part ) { + var_dump( __LINE__ ); + ( new BlockPhpExecutionInUploads( $assoc_args ) )->output(); + } + if ( 'all' === $block_part || 'themes' === $block_part ) { + var_dump( __LINE__ ); + ( new BlockPhpExecutionInThemes( $assoc_args ) )->output(); + } } /** diff --git a/src/SubCommands/SubCommand.php b/src/SubCommands/SubCommand.php index e5ec3ea..6483d14 100644 --- a/src/SubCommands/SubCommand.php +++ b/src/SubCommands/SubCommand.php @@ -33,7 +33,7 @@ class SubCommand { /** * @var mixed The content of the rule template file */ - public mixed $ruleContent; + public $ruleContent; /** * @var string Rule template name @@ -102,7 +102,7 @@ private function setFilePath() : string { * * @return string|array */ - private function setRuleContent() : string|array { + private function setRuleContent() { //Return an empty array in case when the executed command does not require a template if($this->ruleTemplate === '') { return []; @@ -147,34 +147,31 @@ private function getOutputMessage(string $type = 'success') : string { * @throws WP_CLI\ExitException */ public function output() { - if($this->output) { - try { - $fileManager = new FileManager($this->filePath); - $content = $fileManager->wrap($this->ruleContent, 'block', $this->ruleName); - WP_CLI::line(implode(PHP_EOL, $content)); - } catch(FileDoesNotExist|RuleAlreadyExist|FileIsNotWritable|FileIsNotReadable $e) { - WP_CLI::error($e->getMessage()); - } - } else { - try { - $fileManager = new FileManager($this->filePath); - - if(isset($this->commandArguments['remove']) && $this->commandArguments['remove'] === true) { - //We need to remove the rule from file - $result = $fileManager->remove($this->ruleName); - - if($result) { - WP_CLI::success($this->getOutputMessage('removal')); - } - } else { - //Add the rule - $fileManager->add($this->ruleContent, $this->ruleName); - - WP_CLI::success($this->getOutputMessage('success')); - } - } catch(FileDoesNotExist|RuleAlreadyExist|FileIsNotWritable|FileIsNotReadable $e) { - WP_CLI::error($e->getMessage()); - } - } + try { + $fileManager = new FileManager( $this->filePath ); + if ( $this->output ) { + $content = $fileManager->wrap( $this->ruleContent, 'block', $this->ruleName ); + WP_CLI::line( implode( PHP_EOL, $content ) ); + } else { + if ( isset( $this->commandArguments['remove'] ) && $this->commandArguments['remove'] === true ) { + //We need to remove the rule from file + $result = $fileManager->remove( $this->ruleName ); + + if ( $result ) { + WP_CLI::success( $this->getOutputMessage( 'removal' ) ); + } + } else { + //Add the rule + $fileManager->add( $this->ruleContent, $this->ruleName ); + + WP_CLI::success( $this->getOutputMessage( 'success' ) ); + } + + } + } catch ( FileDoesNotExist | FileIsNotWritable | FileIsNotReadable $e ) { + WP_CLI::error( $e->getMessage() ); + } catch ( RuleAlreadyExist $e ) { + WP_CLI::warning( $e->getMessage() ); + } } } \ No newline at end of file From 7df3b4e150d2ad33ed81823d28b4c2cdbb1dc2bf Mon Sep 17 00:00:00 2001 From: Janw Oostendorp Date: Sun, 20 Mar 2022 12:48:14 +0100 Subject: [PATCH 03/32] Added proper debug. --- src/SecureCommand.php | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index d4b5158..8003895 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -3,8 +3,6 @@ namespace WP_CLI_Secure; use WP_CLI; -use WP_CLI\Process; -use WP_CLI\Utils; use WP_CLI_Command; use WP_CLI_Secure\SubCommands\BlockAccessToHtaccess; use WP_CLI_Secure\SubCommands\BlockAccessToSensitiveDirectories; @@ -138,19 +136,19 @@ public function block_php($args, $assoc_args) : void { } if ( 'all' === $block_part || 'plugins' === $block_part ) { - var_dump( __LINE__ ); + WP_CLI::debug( 'Securing the plugins folder.', 'secure'); ( new BlockPhpExecutionInPlugins( $assoc_args ) )->output(); } if ( 'all' === $block_part || 'uploads' === $block_part ) { - var_dump( __LINE__ ); + WP_CLI::debug( 'Securing the uploads folder.', 'secure'); ( new BlockPhpExecutionInWpIncludes( $assoc_args ) )->output(); } if ( 'all' === $block_part || 'includes' === $block_part ) { - var_dump( __LINE__ ); + WP_CLI::debug( 'Securing the includes folder.', 'secure'); ( new BlockPhpExecutionInUploads( $assoc_args ) )->output(); } if ( 'all' === $block_part || 'themes' === $block_part ) { - var_dump( __LINE__ ); + WP_CLI::debug( 'Securing the themes folder.', 'secure'); ( new BlockPhpExecutionInThemes( $assoc_args ) )->output(); } } From df75a5df17d2ce359860c2c2290d919695ea7d37 Mon Sep 17 00:00:00 2001 From: Janw Oostendorp Date: Sun, 20 Mar 2022 14:09:22 +0100 Subject: [PATCH 04/32] Split up the secure files/dir command. --- src/SecureCommand.php | 123 ++++++++++++------------------------------ 1 file changed, 35 insertions(+), 88 deletions(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 8003895..6e6f984 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -160,6 +160,9 @@ public function block_php($args, $assoc_args) : void { * * ## OPTIONS * + * + * : Required. accepts: files, directories, htaccess, xmlrpc or all. + * * [--remove] * : Removes the rule from .htaccess or nginx.conf. * @@ -175,75 +178,51 @@ public function block_php($args, $assoc_args) : void { * * ## EXAMPLES * - * $ wp secure block_access_to_sensitive_files + * # Secure the sensitive files. + * $ wp secure block-access files + * Success: Block Access to Sensitive Files rule has been deployed. + * + * # Secure all files & directories. + * $ wp secure block-access all * Success: Block Access to Sensitive Files rule has been deployed. * + * @subcommand block-access + * * @when before_wp_load */ - public function block_access_to_sensitive_files($args, $assoc_args): void { - (new BlockAccessToSensitiveFiles($assoc_args))->output(); + public function block_access($args, $assoc_args): void { + $block_part = $args[0]; + + // Failure first. + if ( ! in_array( $block_part, array( 'files', 'directories', 'htaccess', 'xmlrpc', 'all' ), true ) ) { + WP_CLI::error( sprintf( 'Invalid block part "%s" was provided. Allowed values are "files", "directories", "htaccess", "xmlrpc" or "all"', $block_part ) ); + } + + if ( 'all' === $block_part || 'files' === $block_part ) { + WP_CLI::debug( 'Blocking access to the sensitive files.', 'secure'); + (new BlockAccessToSensitiveFiles($assoc_args))->output(); + } + if ( 'all' === $block_part || 'directories' === $block_part ) { + WP_CLI::debug( 'Blocking access to the directories.', 'secure'); + ( new BlockAccessToSensitiveDirectories( $assoc_args ) )->output(); + } + if ( 'all' === $block_part || 'htaccess' === $block_part ) { + WP_CLI::debug( 'Blocking access to the htaccess.', 'secure'); + (new BlockAccessToHtaccess($assoc_args))->output(); + } + if ( 'all' === $block_part || 'xmlrpc' === $block_part ) { + WP_CLI::debug( 'Blocking access to the xmlrpc.', 'secure'); + (new BlockAccessToXmlRpc($assoc_args))->output(); + } } /** * Blocks direct access to sensitive directories. * * Blocks direct access to files in .git, svn and vendor directories - * - * ## OPTIONS - * - * [--remove] - * : Removes the rule from .htaccess or nginx.conf. - * - * [--output] - * : Use this option to display the actual code that you can manually copy and paste into some other file - * - * [--file-path=] - * : Set a custom path to the file which command should use to write rules into - * - * [--server=] - * : Set a server type. Possible options are "apache" and "nginx". Default is "apache" and all rules are stored in - * .htaccess file - * - * ## EXAMPLES - * - * $ wp secure block_access_to_sensitive_directories - * Success: Block Access to Sensitive Directories rule has been deployed. - * - * @when before_wp_load */ public function block_access_to_sensitive_directories($args, $assoc_args) : void { - (new BlockAccessToSensitiveDirectories($assoc_args))->output(); - } - /** - * Blocks direct access to .htaccess - * - * Blocks direct access to .htaccess file - * - * ## OPTIONS - * - * [--remove] - * : Removes the rule from .htaccess or nginx.conf. - * - * [--output] - * : Use this option to display the actual code that you can manually copy and paste into some other file - * - * [--file-path=] - * : Set a custom path to the file which command should use to write rules into - * - * [--server=] - * : Set a server type. Possible options are "apache" and "nginx". Default is "apache" and all rules are stored in - * .htaccess file - * - * ## EXAMPLES - * - * $ wp secure block_access_to_htaccess - * Success: Block Access to .htaccess rule has been deployed - * - * @when before_wp_load - */ - public function block_access_to_htaccess($args, $assoc_args): void { - (new BlockAccessToHtaccess($assoc_args))->output(); } /** @@ -278,38 +257,6 @@ public function block_author_scanning($args, $assoc_args) : void { (new BlockAuthorScanning($assoc_args))->output(); } - /** - * Blocks access to XML-RPC - * - * XML-RPC is a remote procedure call which uses XML to encode its calls and HTTP as a transport mechanism. If you want to access and publish to your blog remotely, then you need XML-RPC enabled. - * For majority of WordPress installations, XML-RPC is not required and poses a significant security risk. - * - * ## OPTIONS - * - * [--remove] - * : Removes the rule from .htaccess or nginx.conf. - * - * [--output] - * : Use this option to display the actual code that you can manually copy and paste into some other file - * - * [--file-path=] - * : Set a custom path to the file which command should use to write rules into - * - * [--server=] - * : Set a server type. Possible options are "apache" and "nginx". Default is "apache" and all rules are stored in - * .htaccess file - * - * ## EXAMPLES - * - * $ wp secure block_author_scanning - * Success: Block Author Scanning rule has been deployed. - * - * @when before_wp_load - */ - public function block_access_to_xmlrpc($args, $assoc_args) : void { - (new BlockAccessToXmlRpc($assoc_args))->output(); - } - /** * Removes all WP CLI Secure rules * From 8607a6b95885a83190d46fdccee5c362bdf28d8b Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 14:16:01 +0100 Subject: [PATCH 05/32] fix: Removed incomplete GHA workflow --- .github/workflows/tests.yml | 26 -------------------------- 1 file changed, 26 deletions(-) delete mode 100644 .github/workflows/tests.yml diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml deleted file mode 100644 index c1d4036..0000000 --- a/.github/workflows/tests.yml +++ /dev/null @@ -1,26 +0,0 @@ ---- -name: Web server integration tests - -on: - pull_request: - branches: - - master - -jobs: - container-job: - runs-on: ubuntu-latest - steps: - - name: Setup ddev - uses: jonaseberle/github-action-setup-ddev@v1 - run: ddev --help -# services: -# mysql: -# image: mysql:5.7 -# env: -# MYSQL_DATABASE: testdb -# MYSQL_USER: testdb -# MYSQL_PASSWORD: mysqlpass -# MYSQL_ROOT_PASSWORD: mysqlpass -# ports: -# - 3306:3306 -# options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=3 \ No newline at end of file From 0c66c63ad0ee7f4716402da5cdea281faad98727 Mon Sep 17 00:00:00 2001 From: Thomas Stauer Date: Sun, 20 Mar 2022 12:33:06 +0100 Subject: [PATCH 06/32] Make the used types compatible with PHP 7.4 --- src/FileManager.php | 16 ++++++++-------- src/SubCommands/SubCommand.php | 10 +++++----- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/src/FileManager.php b/src/FileManager.php index 14df81c..4767224 100644 --- a/src/FileManager.php +++ b/src/FileManager.php @@ -82,7 +82,7 @@ private function setFileContent() : array { } if(!$this->isReadable()) { - throw new (FileIsNotReadable::class); + throw new FileIsNotReadable(); } return $this->read(); @@ -156,7 +156,7 @@ private function fileExist() : bool { * * @return array|string */ - private static function removeZeroSpace($content): array|string + private static function removeZeroSpace($content) { if(is_array($content)) { return array_map([static::class, 'removeZeroSpace'], $content); @@ -203,9 +203,9 @@ public function extractRuleBlock(string $marker) : array { * * @param string $needle * - * @return int|bool + * @return bool|int|string */ - private function findInFile(string $needle) : int|bool { + private function findInFile(string $needle) { return array_search($needle, $this->file); } @@ -214,7 +214,7 @@ private function findInFile(string $needle) : int|bool { * * @return array|bool */ - public function extractSecureBlock(): bool|array { + public function extractSecureBlock() { $start = $this->findInFile(self::MARKER_GLOBAL_START . self::SPACE_DELIMITER . self::MARKER_WP_CLI_SECURE); $end = $this->findInFile(self::MARKER_GLOBAL_END . self::SPACE_DELIMITER . self::MARKER_WP_CLI_SECURE); @@ -330,7 +330,7 @@ private function backup() : bool public function add(array $content, string $marker = ''): bool { //If the rule block already exist, there is no reason to add it again if($this->hasRuleBlock($marker)) { - throw new(RuleAlreadyExist::class); + throw new RuleAlreadyExist(); } //Check if file exist? @@ -339,7 +339,7 @@ public function add(array $content, string $marker = ''): bool { } if(!$this->isWritable()) { - throw new(FileIsNotWritable::class); + throw new FileIsNotWritable(); } //Wrap the rule block with markers @@ -450,4 +450,4 @@ private function flattenArray(array $array, int $depth = 1) : array { return $result; } -} \ No newline at end of file +} diff --git a/src/SubCommands/SubCommand.php b/src/SubCommands/SubCommand.php index e5ec3ea..04d7339 100644 --- a/src/SubCommands/SubCommand.php +++ b/src/SubCommands/SubCommand.php @@ -33,7 +33,7 @@ class SubCommand { /** * @var mixed The content of the rule template file */ - public mixed $ruleContent; + public $ruleContent; /** * @var string Rule template name @@ -98,11 +98,11 @@ private function setFilePath() : string { } /** - * Reads rule template file. Depending on output type, returns string or an array + * Reads rule template file. Depending on output type, returns an array * - * @return string|array + * @return array */ - private function setRuleContent() : string|array { + private function setRuleContent() : array { //Return an empty array in case when the executed command does not require a template if($this->ruleTemplate === '') { return []; @@ -177,4 +177,4 @@ public function output() { } } } -} \ No newline at end of file +} From 0312966566b8714ea26703453e33c8ba7435628f Mon Sep 17 00:00:00 2001 From: Thomas Stauer Date: Sun, 20 Mar 2022 15:49:32 +0100 Subject: [PATCH 07/32] add commands to disable and enable the file editor --- README.md | 18 ++++++++++++++++++ src/SecureCommand.php | 20 +++++++++++++++++++- 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f4463dd..b62cdd6 100644 --- a/README.md +++ b/README.md @@ -95,6 +95,24 @@ Removes all security rules. wp secure flush ``` +### wp secure disable-file-editor + +Disables the Wordpress file editor. It could be used to edit arbitrary files using the web interface. +This makes it easier for attackers to change files on the server using a web browser. +We suggest to disable the file editor off. + +``` +wp secure disable-file-editor +``` + +### wp secure enable-file-editor + +Enables the Wordpress file editor. See wp secure disable-file-editor. + +``` +wp secure enable-file-editor +``` + ## Global options ### Remove single security rule diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 6e6f984..8c63ccc 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -301,4 +301,22 @@ public function flush($args, $assoc_args) : void { public function integrityscan($args, $assoc_args) : void { WP_CLI::runcommand('core verify-checksums'); } -} \ No newline at end of file + + /** + * Disable the file editor in Wordpress. + * + * @return void + */ + public function disable_file_editor() : void { + WP_CLI::runcommand('config set DISALLOW_FILE_EDIT true'); + } + + /** + * Enable the file editor in Wordpress. + * + * @return void + */ + public function allow_file_editor() : void { + WP_CLI::runcommand('config set DISALLOW_FILE_EDIT false'); + } +} From a7f97900a18ce1abc27fa447275b3f63a6323ae2 Mon Sep 17 00:00:00 2001 From: Benjamin Burkhardt Date: Sun, 20 Mar 2022 16:14:34 +0100 Subject: [PATCH 08/32] Implemented function & added to SecureCommand --- src/SecureCommand.php | 19 +++++++++++++++++ src/SubCommands/FixFileAndDirPermissions.php | 22 +++++++++++++++++++- 2 files changed, 40 insertions(+), 1 deletion(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 4581823..656dd0f 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -16,6 +16,7 @@ use WP_CLI_Secure\SubCommands\BlockPhpExecutionInUploads; use WP_CLI_Secure\SubCommands\BlockPhpExecutionInWpIncludes; use WP_CLI_Secure\SubCommands\DisableDirectoryBrowsing; +use WP_CLI_Secure\SubCommands\FixFileAndDirPermissions; use WP_CLI_Secure\SubCommands\Flush; /** @@ -416,4 +417,22 @@ public function flush($args, $assoc_args) : void { public function integrityscan($args, $assoc_args) : void { WP_CLI::runcommand('core verify-checksums'); } + + /** + * Fix all directory and file permissions of the wordpress installation + * + * Use this command to verify that the permissions of all files and directories are set according the wordpress recommendations. + * IMPORTANT: Don't use this command if you don't know what you are doing here! + * + * ## EXAMPLES + * + * $ wp secure fix_permissions + * Success: All permission are reset to wordpress default. + * + * @when before_wp_load + */ + public function fix_permissions($args, $assoc_args) : void { + (new FixFileAndDirPermissions($assoc_args))->fixPermissions(); + WP_CLI::success("Permission successfully updated."); + } } \ No newline at end of file diff --git a/src/SubCommands/FixFileAndDirPermissions.php b/src/SubCommands/FixFileAndDirPermissions.php index 176c8a7..57592f1 100644 --- a/src/SubCommands/FixFileAndDirPermissions.php +++ b/src/SubCommands/FixFileAndDirPermissions.php @@ -1,6 +1,26 @@ \ No newline at end of file + $iterator = new \RecursiveDirectoryIterator(ABSPATH); + + foreach($iterator as $file) + { + if (is_file($file)) { + chmod($file, 0666); + } elseif (is_dir($file)) { + chmod($file, 0755); + } + } + } +} \ No newline at end of file From 4cb8a0aaf09c1f4045c27b7d4eeff983af606c31 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 18:31:25 +0100 Subject: [PATCH 09/32] docs: Updated documentation with new commands --- README.md | 107 +++++++++++++++++++----------------------------------- 1 file changed, 38 insertions(+), 69 deletions(-) diff --git a/README.md b/README.md index b62cdd6..80dca49 100644 --- a/README.md +++ b/README.md @@ -4,78 +4,56 @@ Manages common security aspects of WordPress. Supports nginx and Apache. ## Basic Usage This package implements the following commands: -**wp secure block_access_to_htaccess** +**wp secure block-access** -Blocks access to `.htaccess` and `nginx.conf` files. +Blocks direct access to sensitive files and directories: +`readme.txt`, `readme.html`, `xmlrpc.php`, `wp-config.php`, `wp-admin/install.php`, `wp-admin/upgrade.php`, `.git`, `svn`, `cache` and `vendors` -``` -wp secure block_access_to_htaccess [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] -``` - -**wp secure block_access_to_sensitive_directories** - -Blocks direct access to sensitive directories - `.git`, `svn`, `cache` and `vendors` - -``` -wp secure block_access_to_sensitive_directories [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] -``` - -**wp secure block_access_to_sensitive_files** - -Blocks direct access to sensitive files - `readme.txt`, `readme.html`, `wp-config.php`, `wp-admin/install.php` and `wp-admin/upgrade.php` - -``` -wp secure block_access_to_sensitive_files [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] -``` - -**wp secure block_access_to_xmlrpc** - -Blocks direct access XML-RPC +Possible options are: +- sensitive-files +- sensitive-directories +- xmlrpc +- htaccess +- all (does all the above) ``` -wp secure block_access_to_xmlrpc [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] +wp secure block-access +wp secure block-access sensitive-files +wp secure block-access sensitive-directories +wp secure block-access xmlrpc +wp secure block-access htaccess +wp secure block-access all ``` -### wp secure block_author_scanning +### wp secure block-author-scanning Blocks author scanning. Author scanning is a common technique of brute force attacks on WordPress. It is used to crack passwords for the known usernames and to gather additional information about the WordPress itself. ``` -wp secure block_author_scanning [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] -``` - -### wp secure block_php_execution_in_plugins - -Blocks direct access and execution of PHP files in `wp-content/plugins` directory. - -``` -wp secure block_php_execution_in_plugins [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] -``` - -### wp secure block_php_execution_in_uploads - -Blocks direct access and execution of PHP files in `wp-content/uploads` directory. - -``` -wp secure block_php_execution_in_uploads [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] +wp secure block-author-scanning ``` -### wp secure block_php_execution_in_themes +### wp secure block-php-execution -Blocks direct access and execution of PHP files in `wp-content/themes` directory. +Blocks direct access and execution of PHP files in `wp-content/plugins`, `wp-content/uploads`, `wp-content/themes` and `wp-includes` directories. -``` -wp secure block_php_execution_in_themes [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] -``` - -### wp secure block_php_execution_in_wp_includes -Blocks direct access and execution of PHP files in include directories - `wp-admin/includes`, `wp-includes/*.php`, `wp-includes/js/tinymce/langs/*.php`, `wp-includes/theme-compat` +You need to specify where you want to prevent direct access to PHP files. Possible options are: +- all +- plugins +- uploads +- themes +- wp-includes ``` -wp secure block_php_execution_in_wp_includes [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] +wp secure block-php-execution +wp secure block-php-execution all +wp secure block-php-execution plugins +wp secure block-php-execution uploads +wp secure block-php-execution themes +wp secure block-php-execution wp-includes ``` -### wp secure disable_directory_browsing +### wp secure disable-directory-browsing Disables directory browsing. @@ -84,7 +62,7 @@ automatically displays an index page showing the contents of the directory. This could make your site vulnerable to hack attacks by revealing important information needed to exploit a vulnerability in a WordPress plugin, theme, or your server in general. ``` -wp secure disable_directory_browsing [--remove] [--file-path=/alternative/path] [--output] [--server=apache|nginx] +wp secure disable-directory-browsing ``` ### wp secure flush @@ -105,37 +83,28 @@ We suggest to disable the file editor off. wp secure disable-file-editor ``` -### wp secure enable-file-editor - -Enables the Wordpress file editor. See wp secure disable-file-editor. - -``` -wp secure enable-file-editor -``` - ## Global options ### Remove single security rule Using `--remove` with any rule command, you can remove it from configuration. ``` -wp secure block_php_execution_in_wp_includes --remove +wp secure block-access xmlrpc --remove ``` ### Get the output instead of writing in configuration files Using `--output` option with any rule command, you can see actual rule code which you can inspect or manually copy to any file of your choice. ``` -wp secure block_php_execution_in_wp_includes --output -wp secure block_php_execution_in_wp_includes --output --server=nginx +wp secure block-access htaccess --output +wp secure block-access htaccess --output --server=nginx ``` ### Specify server type By default, all rules are generated for Apache or LiteSpeed web servers that utilize `.htaccess` file. However, you can use `--server` to specify nginx if you want. ``` -wp secure block_php_execution_in_wp_includes --server=nginx -wp secure block_php_execution_in_wp_includes --server=--file-path=/home/user/mysite.com/nginx.conf +wp secure block-access htaccess --server=nginx ``` ### Specify custom file path @@ -143,7 +112,7 @@ By default, all commands assume that rules should be written in the root of Word However, you can specify a custom file path that is going to be used for storing security rules. ``` -wp secure block_php_execution_in_plugins --file-path=/home/user/mysite.com/.htaccess +wp secure block-access htaccess --file-path=/home/user/mysite.com/.htaccess ``` ## Important Note for nginx users From ba8c206286d5346578290e669b32ab6b3d48de29 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 18:31:45 +0100 Subject: [PATCH 10/32] feat: Refactoring of command names and arguments --- src/SecureCommand.php | 57 ++++++++++++++++++++----------------------- 1 file changed, 26 insertions(+), 31 deletions(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 4911cb7..ec481e3 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -79,6 +79,8 @@ class SecureCommand extends WP_CLI_Command { * $ wp secure disable_directory_browsing * Success: Directory Browsing security rule is now active. * + * @subcommand disable-directory-browsing + * * @when before_wp_load */ public function disable_directory_browsing($args, $assoc_args) : void { @@ -121,7 +123,7 @@ public function disable_directory_browsing($args, $assoc_args) : void { * * @when before_wp_load * - * @subcommand block-php + * @subcommand block-php-execution */ public function block_php($args, $assoc_args) : void { @@ -129,7 +131,7 @@ public function block_php($args, $assoc_args) : void { // Failure first. if ( ! in_array( $block_part, - array( 'plugins', 'uploads', 'includes', 'themes', 'all' ), + array( 'plugins', 'uploads', 'wp-includes', 'themes', 'all' ), true ) ) { WP_CLI::error( sprintf( 'Invalid block part "%s" was provided. Allowed values are "plugins", "uploads", "includes", "themes" or "all"', @@ -142,11 +144,11 @@ public function block_php($args, $assoc_args) : void { } if ( 'all' === $block_part || 'uploads' === $block_part ) { WP_CLI::debug( 'Securing the uploads folder.', 'secure'); - ( new BlockPhpExecutionInWpIncludes( $assoc_args ) )->output(); + ( new BlockPhpExecutionInUploads( $assoc_args ) )->output(); } - if ( 'all' === $block_part || 'includes' === $block_part ) { + if ( 'all' === $block_part || 'wp-includes' === $block_part ) { WP_CLI::debug( 'Securing the includes folder.', 'secure'); - ( new BlockPhpExecutionInUploads( $assoc_args ) )->output(); + ( new BlockPhpExecutionInWpIncludes( $assoc_args ) )->output(); } if ( 'all' === $block_part || 'themes' === $block_part ) { WP_CLI::debug( 'Securing the themes folder.', 'secure'); @@ -155,14 +157,14 @@ public function block_php($args, $assoc_args) : void { } /** - * Blocks direct access to sensitive files. + * Blocks direct access to various sensitive files and directories * * Blocks direct access to readme.html, readme.txt, wp-config.php and wp-admin/install.php files. * * ## OPTIONS * * - * : Required. accepts: files, directories, htaccess, xmlrpc or all. + * : This option is required. Accepts one of the following values: sensitive-files, sensitive-directories, htaccess, xmlrpc or all. * * [--remove] * : Removes the rule from .htaccess or nginx.conf. @@ -195,15 +197,15 @@ public function block_access($args, $assoc_args): void { $block_part = $args[0]; // Failure first. - if ( ! in_array( $block_part, array( 'files', 'directories', 'htaccess', 'xmlrpc', 'all' ), true ) ) { + if ( ! in_array( $block_part, array( 'sensitive-files', 'sensitive-directories', 'htaccess', 'xmlrpc', 'all' ), true ) ) { WP_CLI::error( sprintf( 'Invalid block part "%s" was provided. Allowed values are "files", "directories", "htaccess", "xmlrpc" or "all"', $block_part ) ); } - if ( 'all' === $block_part || 'files' === $block_part ) { + if ( 'all' === $block_part || 'sensitive-files' === $block_part ) { WP_CLI::debug( 'Blocking access to the sensitive files.', 'secure'); (new BlockAccessToSensitiveFiles($assoc_args))->output(); } - if ( 'all' === $block_part || 'directories' === $block_part ) { + if ( 'all' === $block_part || 'sensitive-directories' === $block_part ) { WP_CLI::debug( 'Blocking access to the directories.', 'secure'); ( new BlockAccessToSensitiveDirectories( $assoc_args ) )->output(); } @@ -217,15 +219,6 @@ public function block_access($args, $assoc_args): void { } } - /** - * Blocks direct access to sensitive directories. - * - * Blocks direct access to files in .git, svn and vendor directories - */ - public function block_access_to_sensitive_directories($args, $assoc_args) : void { - - } - /** * Blocks author scanning * @@ -252,6 +245,8 @@ public function block_access_to_sensitive_directories($args, $assoc_args) : void * $ wp secure block_author_scanning * Success: Block Author Scanning rule has been deployed. * + * @subcommand block-author-scanning + * * @when before_wp_load */ public function block_author_scanning($args, $assoc_args) : void { @@ -297,6 +292,7 @@ public function flush($args, $assoc_args) : void { * * @return void * + * @subcommand integrity-scan * @when before_wp_load */ public function integrityscan($args, $assoc_args) : void { @@ -304,23 +300,20 @@ public function integrityscan($args, $assoc_args) : void { } /** - * Disable the file editor in Wordpress. + * Disable the file editor in WordPress * - * @return void - */ - public function disable_file_editor() : void { - WP_CLI::runcommand('config set DISALLOW_FILE_EDIT true'); - } - - /** - * Enable the file editor in Wordpress. + * @subcommand disable-directory-browsing * + * @param $args + * @param $assoc_args + * + * @when before_wp_load * @return void */ - public function allow_file_editor() : void { - WP_CLI::runcommand('config set DISALLOW_FILE_EDIT false'); + public function disable_file_editor($args, $assoc_args) : void { + WP_CLI::runcommand('config set DISALLOW_FILE_EDIT' . !isset($assoc_args['remove'])); } -} + /** * Fix all directory and file permissions of the wordpress installation * @@ -332,10 +325,12 @@ public function allow_file_editor() : void { * $ wp secure fix_permissions * Success: All permission are reset to wordpress default. * + * @subcommand fix-permissions * @when before_wp_load */ public function fix_permissions($args, $assoc_args) : void { (new FixFileAndDirPermissions($assoc_args))->fixPermissions(); + WP_CLI::success("Permission successfully updated."); } } \ No newline at end of file From 69d2a3f17aee0f730177e391c2208429d30721fd Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 18:32:30 +0100 Subject: [PATCH 11/32] fix: Fixed formatting issue --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 80dca49..daf76b9 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@ Manages common security aspects of WordPress. Supports nginx and Apache. ## Basic Usage This package implements the following commands: -**wp secure block-access** +## wp secure block-access Blocks direct access to sensitive files and directories: `readme.txt`, `readme.html`, `xmlrpc.php`, `wp-config.php`, `wp-admin/install.php`, `wp-admin/upgrade.php`, `.git`, `svn`, `cache` and `vendors` From 7534d28d832e317f6f29c4164aba985a9a586abf Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 18:37:32 +0100 Subject: [PATCH 12/32] docs: Updated documenation to make it more clear --- README.md | 57 ++++++++++++++++++++++++++++++++++++------------------- 1 file changed, 38 insertions(+), 19 deletions(-) diff --git a/README.md b/README.md index daf76b9..8ae67fe 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,10 @@ Manages common security aspects of WordPress. Supports nginx and Apache. ## Basic Usage This package implements the following commands: -## wp secure block-access +## Block access to sensitive files and directories +```bash +wp secure block-access +``` Blocks direct access to sensitive files and directories: `readme.txt`, `readme.html`, `xmlrpc.php`, `wp-config.php`, `wp-admin/install.php`, `wp-admin/upgrade.php`, `.git`, `svn`, `cache` and `vendors` @@ -16,8 +19,9 @@ Possible options are: - htaccess - all (does all the above) -``` -wp secure block-access +Examples: + +```bash wp secure block-access sensitive-files wp secure block-access sensitive-directories wp secure block-access xmlrpc @@ -25,15 +29,25 @@ wp secure block-access htaccess wp secure block-access all ``` -### wp secure block-author-scanning +### Block Author Scanning + +```bash +wp secure block-author-scanning +``` Blocks author scanning. Author scanning is a common technique of brute force attacks on WordPress. It is used to crack passwords for the known usernames and to gather additional information about the WordPress itself. -``` +Examples: + +```bash wp secure block-author-scanning ``` -### wp secure block-php-execution +### Block Direct Access and Execution in certain directories + +```bash +wp secure block-php-execution +``` Blocks direct access and execution of PHP files in `wp-content/plugins`, `wp-content/uploads`, `wp-content/themes` and `wp-includes` directories. @@ -44,8 +58,9 @@ You need to specify where you want to prevent direct access to PHP files. Possib - themes - wp-includes -``` -wp secure block-php-execution +Examples: + +```bash wp secure block-php-execution all wp secure block-php-execution plugins wp secure block-php-execution uploads @@ -53,7 +68,10 @@ wp secure block-php-execution themes wp secure block-php-execution wp-includes ``` -### wp secure disable-directory-browsing +### Disable Directory Browsing +```bash +wp secure disable-directory-browsing +``` Disables directory browsing. @@ -61,25 +79,26 @@ By default when your web server does not find an index file (i.e. a file like in automatically displays an index page showing the contents of the directory. This could make your site vulnerable to hack attacks by revealing important information needed to exploit a vulnerability in a WordPress plugin, theme, or your server in general. -``` +Examples: + +```bash wp secure disable-directory-browsing ``` -### wp secure flush +### Remove All Security Rules Removes all security rules. -``` +```bash wp secure flush ``` -### wp secure disable-file-editor +### Disable WordPress File Editor -Disables the Wordpress file editor. It could be used to edit arbitrary files using the web interface. +Disables the WordPress file editor. It could be used to edit arbitrary files using the web interface. This makes it easier for attackers to change files on the server using a web browser. -We suggest to disable the file editor off. -``` +```bash wp secure disable-file-editor ``` @@ -88,14 +107,14 @@ wp secure disable-file-editor ### Remove single security rule Using `--remove` with any rule command, you can remove it from configuration. -``` +```bash wp secure block-access xmlrpc --remove ``` ### Get the output instead of writing in configuration files Using `--output` option with any rule command, you can see actual rule code which you can inspect or manually copy to any file of your choice. -``` +```bash wp secure block-access htaccess --output wp secure block-access htaccess --output --server=nginx ``` @@ -103,7 +122,7 @@ wp secure block-access htaccess --output --server=nginx ### Specify server type By default, all rules are generated for Apache or LiteSpeed web servers that utilize `.htaccess` file. However, you can use `--server` to specify nginx if you want. -``` +```bash wp secure block-access htaccess --server=nginx ``` From 97e2faff0f8c6e7e853aebe7704803a8731bf97a Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 18:43:03 +0100 Subject: [PATCH 13/32] docs: Added secure all command --- README.md | 24 ++++++++++++++++-------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 8ae67fe..19941ce 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,22 @@ Manages common security aspects of WordPress. Supports nginx and Apache. ## Basic Usage This package implements the following commands: +### Deploy All Security rules + +Deploys all above-mentioned rules at once. + +```bash +wp secure all +``` + +### Remove All Security Rules + +Removes all security rules. + +```bash +wp secure flush +``` + ## Block access to sensitive files and directories ```bash wp secure block-access @@ -85,14 +101,6 @@ Examples: wp secure disable-directory-browsing ``` -### Remove All Security Rules - -Removes all security rules. - -```bash -wp secure flush -``` - ### Disable WordPress File Editor Disables the WordPress file editor. It could be used to edit arbitrary files using the web interface. From 8126ec33d2fb7bb5e3330cec6bf3fa864e4164d6 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 18:44:11 +0100 Subject: [PATCH 14/32] docs: Added secure all command --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 19941ce..299ffaa 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Removes all security rules. wp secure flush ``` -## Block access to sensitive files and directories +### Block access to sensitive files and directories ```bash wp secure block-access ``` From 7645ab706e5e5836c34d9ea53afd1e938b9a4d32 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 19:10:44 +0100 Subject: [PATCH 15/32] docs: Updated inaccurate statements --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 299ffaa..91ac688 100644 --- a/README.md +++ b/README.md @@ -173,5 +173,4 @@ These paths and URLs are going to be used during tests, so make sure that they a ## Contributing We appreciate you taking the initiative to contribute to this project. -Contributing isn’t limited to just code. We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. - +Contributing isn’t limited to just code. We encourage you to contribute in the way that best fits your abilities, by writing tutorials, giving a demo at your local meetup, helping other users with their support questions, or revising our documentation. \ No newline at end of file From f419d434dc3a326daf6db61ec02d598bfc5230b5 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 19:10:59 +0100 Subject: [PATCH 16/32] feat: Refactoring and some fixes --- src/SubCommands/FixFileAndDirPermissions.php | 32 ++++++++++++-------- 1 file changed, 20 insertions(+), 12 deletions(-) diff --git a/src/SubCommands/FixFileAndDirPermissions.php b/src/SubCommands/FixFileAndDirPermissions.php index 57592f1..455c004 100644 --- a/src/SubCommands/FixFileAndDirPermissions.php +++ b/src/SubCommands/FixFileAndDirPermissions.php @@ -2,25 +2,33 @@ namespace WP_CLI_Secure\SubCommands; -class FixFileAndDirPermissions extends SubCommand -{ +class FixFileAndDirPermissions { + /** + * @var int Default permission mask for the file + */ + public int $filePermissions = 0666; + + /** + * @var int Default permission mask for the directory + */ + public int $directoryPermissions = 0755; + /** * Execute the shell script to fix the folder and directory permissions * - * @return void + * @return bool */ - - function fixPermissions() { + public function fixPermissions() : bool { + if(!defined('ABSPATH')) { + return false; + } $iterator = new \RecursiveDirectoryIterator(ABSPATH); - foreach($iterator as $file) - { - if (is_file($file)) { - chmod($file, 0666); - } elseif (is_dir($file)) { - chmod($file, 0755); - } + foreach($iterator as $file) { + chmod($file, is_file($file) ? $this->filePermissions : $this->directoryPermissions); } + + return true; } } \ No newline at end of file From f4390629ed075f1ee568cac3376129f67cb6a1e7 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 19:11:17 +0100 Subject: [PATCH 17/32] feat: Implementation of secure all command --- src/SecureCommand.php | 40 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 36 insertions(+), 4 deletions(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index ec481e3..15e75d3 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -287,6 +287,10 @@ public function flush($args, $assoc_args) : void { * * It also returns a list of files that shouldn't be part of default WordPress installation. * + * ## EXAMPLES + * + * $ wp secure integrity-scan + * * @param $args * @param $assoc_args * @@ -302,16 +306,17 @@ public function integrityscan($args, $assoc_args) : void { /** * Disable the file editor in WordPress * - * @subcommand disable-directory-browsing + * @subcommand disable-file-editor * * @param $args * @param $assoc_args * * @when before_wp_load + * * @return void */ public function disable_file_editor($args, $assoc_args) : void { - WP_CLI::runcommand('config set DISALLOW_FILE_EDIT' . !isset($assoc_args['remove'])); + WP_CLI::runcommand('config set DISALLOW_FILE_EDIT ' . !isset($assoc_args['remove'])); } /** @@ -322,8 +327,8 @@ public function disable_file_editor($args, $assoc_args) : void { * * ## EXAMPLES * - * $ wp secure fix_permissions - * Success: All permission are reset to wordpress default. + * $ wp secure fix-permissions + * Success: All permission are reset to wordpress default. * * @subcommand fix-permissions * @when before_wp_load @@ -333,4 +338,31 @@ public function fix_permissions($args, $assoc_args) : void { WP_CLI::success("Permission successfully updated."); } + + /** + * Deploys all security rules at once + * + * ## EXAMPLES + * + * $ wp secure all + * + * @param $args + * @param $assoc_args + * + * @return void + */ + public function all($args, $assoc_args) : void { + (new DisableDirectoryBrowsing($assoc_args))->output(); + (new BlockPhpExecutionInPlugins($assoc_args))->output(); + (new BlockPhpExecutionInUploads($assoc_args))->output(); + (new BlockPhpExecutionInThemes($assoc_args))->output(); + (new BlockPhpExecutionInWpIncludes($assoc_args))->output(); + (new BlockAccessToXmlRpc($assoc_args))->output(); + (new BlockAccessToHtaccess($assoc_args))->output(); + (new BlockAccessToSensitiveFiles($assoc_args))->output(); + (new BlockAccessToSensitiveDirectories($assoc_args))->output(); + (new BlockAuthorScanning($assoc_args))->output(); + (new FixFileAndDirPermissions())->output(); + $this->disable_file_editor($args, $assoc_args); + } } \ No newline at end of file From d8e1eb150afd037fcba5c7dbb6c9611fed4dfb36 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 21:21:36 +0100 Subject: [PATCH 18/32] fix: Fixed incorrect rule name --- src/SubCommands/BlockPhpExecutionInWpIncludes.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SubCommands/BlockPhpExecutionInWpIncludes.php b/src/SubCommands/BlockPhpExecutionInWpIncludes.php index 81c0fa2..8f3eb61 100644 --- a/src/SubCommands/BlockPhpExecutionInWpIncludes.php +++ b/src/SubCommands/BlockPhpExecutionInWpIncludes.php @@ -4,7 +4,7 @@ class BlockPhpExecutionInWpIncludes extends SubCommand { public string $ruleTemplate = 'block_php_execution_in_wp_includes'; - public string $ruleName = 'BLOCK PHP EXECUTION IN UPLOADS'; + public string $ruleName = 'BLOCK PHP EXECUTION IN WP INCLUDES'; public string $successMessage = 'Block Execution In wp-includes Directory rule has been deployed.'; public string $removalMessage= 'Block Execution In wp-includes Directory rule has been removed.'; } \ No newline at end of file From d6c703021123533df4109483506e36da941b2c92 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 21:30:18 +0100 Subject: [PATCH 19/32] feat: Refactoring of the block access command --- src/SecureCommand.php | 73 +++++++++++++++++++++++-------------------- 1 file changed, 39 insertions(+), 34 deletions(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 263f2ba..574d936 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -33,7 +33,7 @@ * Success: Directory Browsing is disabled. * * # Remove security rule - * $ wp secure disable-directory-browsing --disable + * $ wp secure disable-directory-browsing --remove * Success: Directory Browsing is enabled. * * # Remove all security rules @@ -76,11 +76,10 @@ class SecureCommand extends WP_CLI_Command { * * ## EXAMPLES * - * $ wp secure disable_directory_browsing + * $ wp secure disable-directory-browsing * Success: Directory Browsing security rule is now active. * * @subcommand disable-directory-browsing - * * @when before_wp_load */ public function disable_directory_browsing($args, $assoc_args) : void { @@ -88,15 +87,14 @@ public function disable_directory_browsing($args, $assoc_args) : void { } /** - * Disables execution of PHP files in Plugins. + * Disables execution of PHP files in Plugins, Uploads, Themes and wp-includes. * - * PHP files in `wp-content/plugins` directory shouldn't be directly accessible. This is important in case of malware injection as it prevents attacker - * from directly accessing infected PHP files + * PHP files in certain directories shouldn't be directly accessible. This is important in case of malware injection as it prevents attacker from directly accessing infected PHP files * * ## OPTIONS * - * - * : Required. accepts: plugins, uploads, includes, themes or all. + * + * : Required. Accepts: plugins, uploads, includes, themes or all. * * [--remove] * : Removes the rule from .htaccess or nginx.conf. @@ -113,20 +111,17 @@ public function disable_directory_browsing($args, $assoc_args) : void { * * ## EXAMPLES * - * # Apply the block rules for plugins + * # Apply the block rules for plugins directory * $ wp secure block-php plugins * Success: Block Execution In Plugins Directory rule has been deployed. * - * # Apply the block rules for all parts. + * # Apply the block rules for all directories * $ wp secure block-php all - * Success: Block Execution In Plugins Directory rule has been deployed. - * - * @when before_wp_load * * @subcommand block-php-execution + * @when before_wp_load */ public function block_php($args, $assoc_args) : void { - $block_part = $args[0]; // Failure first. @@ -163,7 +158,7 @@ public function block_php($args, $assoc_args) : void { * * ## OPTIONS * - * + * * : This option is required. Accepts one of the following values: sensitive-files, sensitive-directories, htaccess, xmlrpc or all. * * [--remove] @@ -192,34 +187,44 @@ public function block_php($args, $assoc_args) : void { * $ wp secure block-access all * Success: Block Access to Sensitive Files rule has been deployed. * - * @subcommand block-access + * # Block custom files and directories + * $ wp secure block-access custom --files=dump.sql --directories=some/directory + * Success: Block Access to Sensitive Files rule has been deployed. * + * @subcommand block-access * @when before_wp_load */ public function block_access($args, $assoc_args): void { - $block_part = $args[0]; + $blockPart = $args[0]; + + $allowedSubArguments = [ + 'sensitive-files', 'sensitive-directories', 'htaccess', 'xmlrpc', 'all', 'custom' + ]; // Failure first. - if ( ! in_array( $block_part, array( 'sensitive-files', 'sensitive-directories', 'htaccess', 'xmlrpc', 'all' ), true ) ) { - WP_CLI::error( sprintf( 'Invalid block part "%s" was provided. Allowed values are "files", "directories", "htaccess", "xmlrpc" or "all"', $block_part ) ); + if(!in_array( $blockPart, $allowedSubArguments, true)) { + WP_CLI::error(sprintf('Invalid block part "%s" was provided. Allowed values are ' . implode(', ', $allowedSubArguments), $blockPart)); } - if ( 'all' === $block_part || 'sensitive-files' === $block_part ) { - WP_CLI::debug( 'Blocking access to the sensitive files.', 'secure'); + if(in_array($blockPart, ['all', 'custom', 'sensitive-files'])) { + WP_CLI::debug('Blocking access to the sensitive files.', 'secure'); (new BlockAccessToSensitiveFiles($assoc_args))->output(); - } - if ( 'all' === $block_part || 'sensitive-directories' === $block_part ) { - WP_CLI::debug( 'Blocking access to the directories.', 'secure'); - ( new BlockAccessToSensitiveDirectories( $assoc_args ) )->output(); - } - if ( 'all' === $block_part || 'htaccess' === $block_part ) { - WP_CLI::debug( 'Blocking access to the htaccess.', 'secure'); - (new BlockAccessToHtaccess($assoc_args))->output(); - } - if ( 'all' === $block_part || 'xmlrpc' === $block_part ) { - WP_CLI::debug( 'Blocking access to the xmlrpc.', 'secure'); - (new BlockAccessToXmlRpc($assoc_args))->output(); - } + } + + if(in_array($blockPart, ['all', 'custom', 'sensitive-directories'])) { + WP_CLI::debug('Blocking access to the directories.', 'secure'); + (new BlockAccessToSensitiveDirectories($assoc_args))->output(); + } + + if(in_array($blockPart, ['all', 'htaccess'])) { + WP_CLI::debug('Blocking access to the htaccess.', 'secure'); + (new BlockAccessToHtaccess($assoc_args))->output(); + } + + if(in_array($blockPart, ['all', 'xmlrpc'])) { + WP_CLI::debug('Blocking access to the xmlrpc.', 'secure'); + (new BlockAccessToXmlRpc($assoc_args))->output(); + } } /** From 1fbeb810de9bc62315aca929e110ba630a324b78 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 21:38:45 +0100 Subject: [PATCH 20/32] feat: Refactoring of the block php execution command --- src/SecureCommand.php | 52 ++++++++++++++++++++++++------------------- 1 file changed, 29 insertions(+), 23 deletions(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 574d936..5976e5b 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -122,33 +122,39 @@ public function disable_directory_browsing($args, $assoc_args) : void { * @when before_wp_load */ public function block_php($args, $assoc_args) : void { - $block_part = $args[0]; + $blockPart = $args[0]; + + $allowedArguments = [ + 'plugins', 'uploads', 'wp-includes', 'themes', 'all' + ]; // Failure first. - if ( ! in_array( $block_part, - array( 'plugins', 'uploads', 'wp-includes', 'themes', 'all' ), - true ) - ) { - WP_CLI::error( sprintf( 'Invalid block part "%s" was provided. Allowed values are "plugins", "uploads", "includes", "themes" or "all"', - $block_part ) ); + if(!in_array($blockPart, $allowedArguments, true)) { + WP_CLI::error( + sprintf('Invalid block part "%s" was provided. Allowed values are "plugins", "uploads", "includes", "themes" or "all"', + $blockPart) + ); } - if ( 'all' === $block_part || 'plugins' === $block_part ) { - WP_CLI::debug( 'Securing the plugins folder.', 'secure'); - ( new BlockPhpExecutionInPlugins( $assoc_args ) )->output(); - } - if ( 'all' === $block_part || 'uploads' === $block_part ) { - WP_CLI::debug( 'Securing the uploads folder.', 'secure'); - ( new BlockPhpExecutionInUploads( $assoc_args ) )->output(); - } - if ( 'all' === $block_part || 'wp-includes' === $block_part ) { - WP_CLI::debug( 'Securing the includes folder.', 'secure'); - ( new BlockPhpExecutionInWpIncludes( $assoc_args ) )->output(); - } - if ( 'all' === $block_part || 'themes' === $block_part ) { - WP_CLI::debug( 'Securing the themes folder.', 'secure'); - ( new BlockPhpExecutionInThemes( $assoc_args ) )->output(); - } + if(in_array($blockPart, ['all', 'plugins'])) { + WP_CLI::debug('Securing the plugins folder.', 'secure'); + (new BlockPhpExecutionInPlugins($assoc_args))->output(); + } + + if(in_array($blockPart, ['all', 'uploads'])) { + WP_CLI::debug('Securing the uploads folder.', 'secure'); + (new BlockPhpExecutionInUploads($assoc_args))->output(); + } + + if(in_array($blockPart, ['all', 'wp-includes'])) { + WP_CLI::debug('Securing the wp-includes folder.', 'secure'); + (new BlockPhpExecutionInWpIncludes($assoc_args))->output(); + } + + if(in_array($blockPart, ['all', 'themes'])) { + WP_CLI::debug('Securing the themes folder.', 'secure'); + (new BlockPhpExecutionInThemes($assoc_args))->output(); + } } /** From 7b499b5e0fbfa961fc19dc4e970108e310a1619a Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 21:45:10 +0100 Subject: [PATCH 21/32] docs: Updated documentation for all commands --- src/SecureCommand.php | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 5976e5b..1a657ec 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -160,12 +160,15 @@ public function block_php($args, $assoc_args) : void { /** * Blocks direct access to various sensitive files and directories * - * Blocks direct access to readme.html, readme.txt, wp-config.php and wp-admin/install.php files. + * Blocks direct access to sensitive files such as readme.html, readme.txt, wp-config.php and wp-admin/install.php files. + * It also blocks the direct access to a certain number of directories such as .git, svn, cache and vendors. + * + * You can use this command to block access to custom files and folders as well. * * ## OPTIONS * * - * : This option is required. Accepts one of the following values: sensitive-files, sensitive-directories, htaccess, xmlrpc or all. + * : This option is required. Accepts one of the following values: sensitive-files, sensitive-directories, htaccess, xmlrpc, custom or all. * * [--remove] * : Removes the rule from .htaccess or nginx.conf. @@ -259,11 +262,10 @@ public function block_access($args, $assoc_args): void { * * ## EXAMPLES * - * $ wp secure block_author_scanning + * $ wp secure block-author-scanning * Success: Block Author Scanning rule has been deployed. * * @subcommand block-author-scanning - * * @when before_wp_load */ public function block_author_scanning($args, $assoc_args) : void { @@ -273,8 +275,8 @@ public function block_author_scanning($args, $assoc_args) : void { /** * Removes all WP CLI Secure rules * - * Use this command to remove all deployed security rules. If you are using nginx you need to restart it. If you copied rules manually, this command - * will not remove them! + * Use this command to remove all deployed security rules. If you are using nginx you need to restart it. + * If you copied rules manually, this command will not remove them! * * ## OPTIONS * @@ -316,18 +318,22 @@ public function flush($args, $assoc_args) : void { * @subcommand integrity-scan * @when before_wp_load */ - public function integrityscan($args, $assoc_args) : void { + public function integrity_scan($args, $assoc_args) : void { WP_CLI::runcommand('core verify-checksums'); } /** * Disable the file editor in WordPress * - * @subcommand disable-file-editor + * The problem with the WordPress file editor is that it allows users to run PHP code on your site. + * Anytime a user is able to run their own code, this presents a security risk. + * If an insecure admin account is hacked, the WordPress file editor is the gateway through which a full-fledged attack can be + * carried out. * * @param $args * @param $assoc_args * + * @subcommand disable-file-editor * @when before_wp_load * * @return void @@ -337,15 +343,17 @@ public function disable_file_editor($args, $assoc_args) : void { } /** - * Fix all directory and file permissions of the wordpress installation + * Fix all directory and file permissions of the WordPress installation + * + * Use this command to verify that the permissions of all files and directories are set according the WordPress recommendations. + * This command will set 0666 to all files and 0755 to all folders inside WordPress installation. * - * Use this command to verify that the permissions of all files and directories are set according the wordpress recommendations. - * IMPORTANT: Don't use this command if you don't know what you are doing here! + * IMPORTANT: Don't use this command if you don't know what you are doing here! * * ## EXAMPLES * * $ wp secure fix-permissions - * Success: All permission are reset to wordpress default. + * Success: All permission are set to the WordPress recommended values. * * @subcommand fix-permissions * @when before_wp_load @@ -359,6 +367,8 @@ public function fix_permissions($args, $assoc_args) : void { /** * Deploys all security rules at once * + * This command will deploy all security rules at once. + * * ## EXAMPLES * * $ wp secure all From b4f061b3279d256cda2fa4fcbfb06eaafc646992 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 21:48:25 +0100 Subject: [PATCH 22/32] fix: Fixed incorrect git directory name --- .../BlockAccessToSensitiveDirectories.php | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/src/SubCommands/BlockAccessToSensitiveDirectories.php b/src/SubCommands/BlockAccessToSensitiveDirectories.php index 03c5df2..dc1b2b2 100644 --- a/src/SubCommands/BlockAccessToSensitiveDirectories.php +++ b/src/SubCommands/BlockAccessToSensitiveDirectories.php @@ -8,17 +8,26 @@ class BlockAccessToSensitiveDirectories extends SubCommand { public string $successMessage = 'Block Access to Sensitive Directories rule has been deployed.'; public string $removalMessage= 'Block Access to Sensitive Directories rule has been removed.'; - public function getTemplateVars() { - $directories = isset( $this->commandArguments['directories'] ) ? $this->commandArguments['directories'] : 'git,svn,vendors,cache'; - if ( ! empty( $directories ) ) { - $directories = explode( ',', $directories ); - $directories = array_map( 'trim', $directories ); + /** + * @var string Default directories that we are going to protect + */ + private string $sensitiveDirectories = '.git,svn,vendors,cache'; + + /** + * @return array + */ + public function getTemplateVars() : array { + $directories = $this->commandArguments['directories'] ?? $this->sensitiveDirectories; + if (!empty($directories)) { + $directories = explode(',', $directories); + $directories = array_map('trim', $directories); $directories_array = []; return [ - [ 'directories' => implode( '|', array_map( 'preg_quote', $directories ) ) ] + ['directories' => implode('|', array_map('preg_quote', $directories))] ]; } + return []; } } \ No newline at end of file From 3c8458b2cfe7d034f4e8906ac931f27cc72b640c Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 21:57:57 +0100 Subject: [PATCH 23/32] feat: Refactoring of the Sensitive Files class --- .../BlockAccessToSensitiveFiles.php | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/SubCommands/BlockAccessToSensitiveFiles.php b/src/SubCommands/BlockAccessToSensitiveFiles.php index 9f6a2b1..6e78477 100644 --- a/src/SubCommands/BlockAccessToSensitiveFiles.php +++ b/src/SubCommands/BlockAccessToSensitiveFiles.php @@ -8,20 +8,32 @@ class BlockAccessToSensitiveFiles extends SubCommand { public string $successMessage = 'Block Access to Sensitive Files rule has been deployed.'; public string $removalMessage= 'Block Access to Sensitive Files rule has been removed.'; - public function getTemplateVars() { - $files = isset( $this->commandArguments['files'] ) ? $this->commandArguments['files'] : 'readme.html, readme.txt, wp-config.php, wp-admin/install.php'; - if ( ! empty( $files ) ) { - $files = explode( ',', $files ); - $files = array_map( 'trim', $files ); + /** + * @var string A list of files that should be protected by default + */ + private string $sensitiveFiles = 'readme.html, readme.txt, wp-config.php, wp-admin/install.php'; + + /** + * @return array + */ + public function getTemplateVars(): array { + $files = $this->commandArguments['files'] ?? $this->sensitiveFiles; + + if (!empty($files)) { + $files = explode(',', $files); + $files = array_map('trim', $files); $files_array = []; - foreach ( $files as $key => $value ) { - $file = isset( $this->commandArguments['server'] ) && $this->commandArguments['server'] === 'nginx' ? preg_quote( $value ) : $value; - $files_array[] = [ 'file' => $file ]; + foreach ($files as $key => $value) { + $file = (isset($this->commandArguments['server']) && $this->commandArguments['server'] === 'nginx') ? + preg_quote($value) : $value; + + $files_array[] = ['file' => $file]; } return $files_array; } + return []; } } \ No newline at end of file From 4f9dc48c339b1f1e2e27115b4a5fade3ab267c17 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:02:14 +0100 Subject: [PATCH 24/32] feat: Refactoring, code comment updates --- src/SubCommands/FixFileAndDirPermissions.php | 2 +- src/SubCommands/SubCommand.php | 33 ++++++++++---------- 2 files changed, 18 insertions(+), 17 deletions(-) diff --git a/src/SubCommands/FixFileAndDirPermissions.php b/src/SubCommands/FixFileAndDirPermissions.php index 455c004..241fd9e 100644 --- a/src/SubCommands/FixFileAndDirPermissions.php +++ b/src/SubCommands/FixFileAndDirPermissions.php @@ -19,12 +19,12 @@ class FixFileAndDirPermissions { * @return bool */ public function fixPermissions() : bool { + //Stop execution if ABSPATH is not defined to prevent changing permissions in the wrong place if(!defined('ABSPATH')) { return false; } $iterator = new \RecursiveDirectoryIterator(ABSPATH); - foreach($iterator as $file) { chmod($file, is_file($file) ? $this->filePermissions : $this->directoryPermissions); } diff --git a/src/SubCommands/SubCommand.php b/src/SubCommands/SubCommand.php index 700f08f..ffd5757 100644 --- a/src/SubCommands/SubCommand.php +++ b/src/SubCommands/SubCommand.php @@ -120,10 +120,11 @@ private function setRuleContent() : array { } unset($file); + //Combine templates and command arguments, if any + //This is used for block-access command $result = new RuleContent( $result, $this->getTemplateVars() ); - $result = $result->getContent(); - return $result; + return $result->getContent(); } /** @@ -131,7 +132,7 @@ private function setRuleContent() : array { * * @return array */ - public function getTemplateVars() { + public function getTemplateVars(): array { return []; } @@ -161,30 +162,30 @@ private function getOutputMessage(string $type = 'success') : string { */ public function output() { try { - $fileManager = new FileManager( $this->filePath ); - if ( $this->output ) { - $content = $fileManager->wrap( $this->ruleContent, 'block', $this->ruleName ); + $fileManager = new FileManager($this->filePath); + if ($this->output) { + $content = $fileManager->wrap($this->ruleContent, 'block', $this->ruleName); WP_CLI::line( implode( PHP_EOL, $content ) ); } else { - if ( isset( $this->commandArguments['remove'] ) && $this->commandArguments['remove'] === true ) { + if (isset($this->commandArguments['remove']) && $this->commandArguments['remove'] === true) { //We need to remove the rule from file - $result = $fileManager->remove( $this->ruleName ); + $result = $fileManager->remove($this->ruleName); - if ( $result ) { - WP_CLI::success( $this->getOutputMessage( 'removal' ) ); + if ($result) { + WP_CLI::success($this->getOutputMessage('removal')); } } else { //Add the rule - $fileManager->add( $this->ruleContent, $this->ruleName ); + $fileManager->add($this->ruleContent, $this->ruleName); - WP_CLI::success( $this->getOutputMessage( 'success' ) ); + WP_CLI::success($this->getOutputMessage('success')); } } - } catch ( FileDoesNotExist | FileIsNotWritable | FileIsNotReadable $e ) { - WP_CLI::error( $e->getMessage() ); - } catch ( RuleAlreadyExist $e ) { - WP_CLI::warning( $e->getMessage() ); + } catch (FileDoesNotExist | FileIsNotWritable | FileIsNotReadable $e) { + WP_CLI::error($e->getMessage()); + } catch (RuleAlreadyExist $e) { + WP_CLI::warning($e->getMessage()); } } } From b49dc9a07766abf9bf6132c3131721fd88e73cf6 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:12:57 +0100 Subject: [PATCH 25/32] fix: Fixed incorrect path to the test assets --- tests/Unit/FileManager/WriteTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Unit/FileManager/WriteTest.php b/tests/Unit/FileManager/WriteTest.php index ec6b18e..dc2bcf7 100644 --- a/tests/Unit/FileManager/WriteTest.php +++ b/tests/Unit/FileManager/WriteTest.php @@ -41,8 +41,8 @@ class WriteTest extends BaseTestCase { public function setUp(): void { parent::setUp(); - $content = file_get_contents(dirname(__DIR__) . '/assets/htaccess-base.txt'); - $content2 = file_get_contents(dirname(__DIR__) . '/assets/htaccess-secured.txt'); + $content = file_get_contents(getcwd() . '/tests/assets/htaccess-base.txt'); + $content2 = file_get_contents(getcwd() . '/tests/assets/htaccess-secured.txt'); $this->file = FileHelper::create('.htaccess', 0755, $content); $this->file2 = FileHelper::create('.htaccess2', 0777, $content); $this->file3 = FileHelper::create('.htaccess-secured', 0666, $content2); From 07fafa960201d2d3569f261b66440f92c451f7ca Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:25:59 +0100 Subject: [PATCH 26/32] fix: Fixed incorrect path to the test assets --- .../BlockAccessToSensitiveDirectories.php | 33 ------------------- tests/Feature/BlockAccessToHtaccessTest.php | 2 +- .../BlockAccessToSensitiveDirectoriesTest.php | 2 +- .../BlockAccessToSensitiveFilesTest.php | 2 +- 4 files changed, 3 insertions(+), 36 deletions(-) delete mode 100644 src/SubCommands/BlockAccessToSensitiveDirectories.php diff --git a/src/SubCommands/BlockAccessToSensitiveDirectories.php b/src/SubCommands/BlockAccessToSensitiveDirectories.php deleted file mode 100644 index dc1b2b2..0000000 --- a/src/SubCommands/BlockAccessToSensitiveDirectories.php +++ /dev/null @@ -1,33 +0,0 @@ -commandArguments['directories'] ?? $this->sensitiveDirectories; - if (!empty($directories)) { - $directories = explode(',', $directories); - $directories = array_map('trim', $directories); - $directories_array = []; - - return [ - ['directories' => implode('|', array_map('preg_quote', $directories))] - ]; - } - - return []; - } -} \ No newline at end of file diff --git a/tests/Feature/BlockAccessToHtaccessTest.php b/tests/Feature/BlockAccessToHtaccessTest.php index 95ca187..0a5be8a 100644 --- a/tests/Feature/BlockAccessToHtaccessTest.php +++ b/tests/Feature/BlockAccessToHtaccessTest.php @@ -15,7 +15,7 @@ public function setUp(): void{ $command = new BlockAccessToHtaccess($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingNginxConfigFile() : void { diff --git a/tests/Feature/BlockAccessToSensitiveDirectoriesTest.php b/tests/Feature/BlockAccessToSensitiveDirectoriesTest.php index f2afc5a..1189a18 100644 --- a/tests/Feature/BlockAccessToSensitiveDirectoriesTest.php +++ b/tests/Feature/BlockAccessToSensitiveDirectoriesTest.php @@ -15,7 +15,7 @@ public function setUp(): void{ $command = new BlockAccessToSensitiveDirectories($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingGitDirectory() : void { diff --git a/tests/Feature/BlockAccessToSensitiveFilesTest.php b/tests/Feature/BlockAccessToSensitiveFilesTest.php index 38f68bb..246f6dc 100644 --- a/tests/Feature/BlockAccessToSensitiveFilesTest.php +++ b/tests/Feature/BlockAccessToSensitiveFilesTest.php @@ -15,7 +15,7 @@ public function setUp(): void { $command = new BlockAccessToSensitiveFiles($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingReadmeFiles() : void { From 536d03eabd3e45b455f0ec4d6cdab904ae2e18ca Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:31:57 +0100 Subject: [PATCH 27/32] fix: Fixed an issue that caused incorrect rules to be applied for certain files --- .../BlockAccessToSensitiveFiles.php | 29 ------------------- .../block_access_to_sensitive_files.tpl | 25 +++++++++++++++- .../nginx/block_access_to_sensitive_files.tpl | 18 +++++++++++- 3 files changed, 41 insertions(+), 31 deletions(-) diff --git a/src/SubCommands/BlockAccessToSensitiveFiles.php b/src/SubCommands/BlockAccessToSensitiveFiles.php index 6e78477..13e30e5 100644 --- a/src/SubCommands/BlockAccessToSensitiveFiles.php +++ b/src/SubCommands/BlockAccessToSensitiveFiles.php @@ -7,33 +7,4 @@ class BlockAccessToSensitiveFiles extends SubCommand { public string $ruleName = 'BLOCK ACCESS TO SENSITIVE FILES'; public string $successMessage = 'Block Access to Sensitive Files rule has been deployed.'; public string $removalMessage= 'Block Access to Sensitive Files rule has been removed.'; - - /** - * @var string A list of files that should be protected by default - */ - private string $sensitiveFiles = 'readme.html, readme.txt, wp-config.php, wp-admin/install.php'; - - /** - * @return array - */ - public function getTemplateVars(): array { - $files = $this->commandArguments['files'] ?? $this->sensitiveFiles; - - if (!empty($files)) { - $files = explode(',', $files); - $files = array_map('trim', $files); - $files_array = []; - - foreach ($files as $key => $value) { - $file = (isset($this->commandArguments['server']) && $this->commandArguments['server'] === 'nginx') ? - preg_quote($value) : $value; - - $files_array[] = ['file' => $file]; - } - - return $files_array; - } - - return []; - } } \ No newline at end of file diff --git a/src/Templates/apache/block_access_to_sensitive_files.tpl b/src/Templates/apache/block_access_to_sensitive_files.tpl index f38d322..16d2b40 100644 --- a/src/Templates/apache/block_access_to_sensitive_files.tpl +++ b/src/Templates/apache/block_access_to_sensitive_files.tpl @@ -1,4 +1,4 @@ - + Require all denied @@ -7,3 +7,26 @@ Deny from all + + + Require all denied + + + Order allow,deny + Deny from all + + + + + Require all denied + + + Order allow,deny + Deny from all + + + + RewriteEngine On + RewriteRule ^wp-admin/install\.php$ - [F] + RewriteRule ^wp-admin/upgrade\.php$ - [F] + \ No newline at end of file diff --git a/src/Templates/nginx/block_access_to_sensitive_files.tpl b/src/Templates/nginx/block_access_to_sensitive_files.tpl index 522e048..7f75180 100644 --- a/src/Templates/nginx/block_access_to_sensitive_files.tpl +++ b/src/Templates/nginx/block_access_to_sensitive_files.tpl @@ -1,3 +1,19 @@ -location ~ /{{file}}$ { +location = /wp-admin/install.php { deny all; } + +location = /wp-admin/upgrade.php { + deny all; +} + +location ~ /readme\.html$ { + deny all; +} + +location ~ /readme\.txt$ { + deny all; +} + +location ~ /wp-config.php$ { + deny all; +} \ No newline at end of file From dc4be11a6f3dda1395d830a22b3b34ec32ff1f86 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:32:24 +0100 Subject: [PATCH 28/32] feat: Migrated custom files blocking to a separate class --- .../BlockAccessToCustomSensitiveFiles.php | 34 +++++++++++++++++++ ...block_access_to_custom_sensitive_files.tpl | 9 +++++ ...block_access_to_custom_sensitive_files.tpl | 3 ++ 3 files changed, 46 insertions(+) create mode 100644 src/SubCommands/BlockAccessToCustomSensitiveFiles.php create mode 100644 src/Templates/apache/block_access_to_custom_sensitive_files.tpl create mode 100644 src/Templates/nginx/block_access_to_custom_sensitive_files.tpl diff --git a/src/SubCommands/BlockAccessToCustomSensitiveFiles.php b/src/SubCommands/BlockAccessToCustomSensitiveFiles.php new file mode 100644 index 0000000..1f6b85a --- /dev/null +++ b/src/SubCommands/BlockAccessToCustomSensitiveFiles.php @@ -0,0 +1,34 @@ +commandArguments['files']; + + if(!empty($files)) { + $files = explode(',', $files); + $files = array_map('trim', $files); + $files_array = []; + + foreach ($files as $key => $value) { + $file = (isset($this->commandArguments['server']) && $this->commandArguments['server'] === 'nginx') ? + preg_quote($value) : $value; + + $files_array[] = ['file' => $file]; + } + + return $files_array; + } + + return []; + } +} \ No newline at end of file diff --git a/src/Templates/apache/block_access_to_custom_sensitive_files.tpl b/src/Templates/apache/block_access_to_custom_sensitive_files.tpl new file mode 100644 index 0000000..f38d322 --- /dev/null +++ b/src/Templates/apache/block_access_to_custom_sensitive_files.tpl @@ -0,0 +1,9 @@ + + + Require all denied + + + Order allow,deny + Deny from all + + diff --git a/src/Templates/nginx/block_access_to_custom_sensitive_files.tpl b/src/Templates/nginx/block_access_to_custom_sensitive_files.tpl new file mode 100644 index 0000000..522e048 --- /dev/null +++ b/src/Templates/nginx/block_access_to_custom_sensitive_files.tpl @@ -0,0 +1,3 @@ +location ~ /{{file}}$ { + deny all; +} From 152c957c4b3c7a4638e74e0cb1f17ab9f3720898 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:34:34 +0100 Subject: [PATCH 29/32] feat: Custom files blocking is now handled by a separate class --- src/SecureCommand.php | 14 ++++++-- .../BlockAccessToSensitiveDirectories.php | 33 +++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/SubCommands/BlockAccessToSensitiveDirectories.php diff --git a/src/SecureCommand.php b/src/SecureCommand.php index 1a657ec..433e879 100644 --- a/src/SecureCommand.php +++ b/src/SecureCommand.php @@ -4,6 +4,7 @@ use WP_CLI; use WP_CLI_Command; +use WP_CLI_Secure\SubCommands\BlockAccessToCustomSensitiveFiles; use WP_CLI_Secure\SubCommands\BlockAccessToHtaccess; use WP_CLI_Secure\SubCommands\BlockAccessToSensitiveDirectories; use WP_CLI_Secure\SubCommands\BlockAccessToSensitiveFiles; @@ -215,12 +216,12 @@ public function block_access($args, $assoc_args): void { WP_CLI::error(sprintf('Invalid block part "%s" was provided. Allowed values are ' . implode(', ', $allowedSubArguments), $blockPart)); } - if(in_array($blockPart, ['all', 'custom', 'sensitive-files'])) { + if(in_array($blockPart, ['all', 'sensitive-files'])) { WP_CLI::debug('Blocking access to the sensitive files.', 'secure'); (new BlockAccessToSensitiveFiles($assoc_args))->output(); } - if(in_array($blockPart, ['all', 'custom', 'sensitive-directories'])) { + if(in_array($blockPart, ['all', 'sensitive-directories'])) { WP_CLI::debug('Blocking access to the directories.', 'secure'); (new BlockAccessToSensitiveDirectories($assoc_args))->output(); } @@ -234,6 +235,15 @@ public function block_access($args, $assoc_args): void { WP_CLI::debug('Blocking access to the xmlrpc.', 'secure'); (new BlockAccessToXmlRpc($assoc_args))->output(); } + + //Custom files and directories blocking + if($blockPart === 'custom' && isset($assoc_args['files'])) { + (new BlockAccessToCustomSensitiveFiles($assoc_args))->output(); + } + + if($blockPart === 'custom' && isset($assoc_args['directories'])) { + (new BlockAccessToSensitiveDirectories($assoc_args))->output(); + } } /** diff --git a/src/SubCommands/BlockAccessToSensitiveDirectories.php b/src/SubCommands/BlockAccessToSensitiveDirectories.php new file mode 100644 index 0000000..dc1b2b2 --- /dev/null +++ b/src/SubCommands/BlockAccessToSensitiveDirectories.php @@ -0,0 +1,33 @@ +commandArguments['directories'] ?? $this->sensitiveDirectories; + if (!empty($directories)) { + $directories = explode(',', $directories); + $directories = array_map('trim', $directories); + $directories_array = []; + + return [ + ['directories' => implode('|', array_map('preg_quote', $directories))] + ]; + } + + return []; + } +} \ No newline at end of file From f892615fa081a9a7bbc2b5d603622c9b20b93770 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:37:08 +0100 Subject: [PATCH 30/32] fix: Fixed incorrect path for calling nginx reload command --- tests/Feature/BlockAccessToXmlRpcTest.php | 2 +- tests/Feature/BlockAuthorScanningTest.php | 2 +- tests/Feature/BlockPhpExecutionInPluginsTest.php | 2 +- tests/Feature/BlockPhpExecutionInThemesTest.php | 2 +- tests/Feature/BlockPhpExecutionInUploadsTest.php | 2 +- tests/Feature/BlockPhpExecutionInWpIncludesTest.php | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/tests/Feature/BlockAccessToXmlRpcTest.php b/tests/Feature/BlockAccessToXmlRpcTest.php index 2c917bb..a102e4a 100644 --- a/tests/Feature/BlockAccessToXmlRpcTest.php +++ b/tests/Feature/BlockAccessToXmlRpcTest.php @@ -15,7 +15,7 @@ public function setUp(): void { $command = new BlockAccessToXmlRpc($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingXmlRpcFile() : void { diff --git a/tests/Feature/BlockAuthorScanningTest.php b/tests/Feature/BlockAuthorScanningTest.php index 6867bac..c9cedb0 100644 --- a/tests/Feature/BlockAuthorScanningTest.php +++ b/tests/Feature/BlockAuthorScanningTest.php @@ -12,7 +12,7 @@ public function setUp(): void { $command = new BlockAuthorScanning($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnApacheWhenAccessingPhpFilesInWpIncludesDirectory() : void { diff --git a/tests/Feature/BlockPhpExecutionInPluginsTest.php b/tests/Feature/BlockPhpExecutionInPluginsTest.php index cb1a5d0..5cea692 100644 --- a/tests/Feature/BlockPhpExecutionInPluginsTest.php +++ b/tests/Feature/BlockPhpExecutionInPluginsTest.php @@ -15,7 +15,7 @@ public function setUp(): void { $command = new BlockPhpExecutionInPlugins($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingPhpFilesInPlugins() : void { diff --git a/tests/Feature/BlockPhpExecutionInThemesTest.php b/tests/Feature/BlockPhpExecutionInThemesTest.php index 001f962..c6ba7dc 100644 --- a/tests/Feature/BlockPhpExecutionInThemesTest.php +++ b/tests/Feature/BlockPhpExecutionInThemesTest.php @@ -15,7 +15,7 @@ public function setUp(): void { $command = new BlockPhpExecutionInThemes($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingPhpFilesInThemesDirectory() : void { diff --git a/tests/Feature/BlockPhpExecutionInUploadsTest.php b/tests/Feature/BlockPhpExecutionInUploadsTest.php index bdaca27..db99cde 100644 --- a/tests/Feature/BlockPhpExecutionInUploadsTest.php +++ b/tests/Feature/BlockPhpExecutionInUploadsTest.php @@ -15,7 +15,7 @@ public function setUp(): void { $command = new BlockPhpExecutionInUploads($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingPhpFilesInUploadsDirectory() : void { diff --git a/tests/Feature/BlockPhpExecutionInWpIncludesTest.php b/tests/Feature/BlockPhpExecutionInWpIncludesTest.php index 7576917..20ce4c5 100644 --- a/tests/Feature/BlockPhpExecutionInWpIncludesTest.php +++ b/tests/Feature/BlockPhpExecutionInWpIncludesTest.php @@ -15,7 +15,7 @@ public function setUp(): void { $command = new BlockPhpExecutionInWpIncludes($this->apacheAssocArgs); $command->output(); - exec('cd ' . dirname(dirname(__DIR__)) . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); + exec('cd ' . getcwd() . DIRECTORY_SEPARATOR . $_ENV['WORDPRESS_NGINX_PATH'] . '&& ddev exec nginx -s reload'); } public function testItWillReturnHttp403OnNginxWhenAccessingPhpFilesInWpIncludesDirectory() : void { From 1dcfad140f5ce553cf408ec13064d85efd1d1a25 Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 22:59:20 +0100 Subject: [PATCH 31/32] docs: Updated documentation for all commands --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 91ac688..74a0160 100644 --- a/README.md +++ b/README.md @@ -20,12 +20,12 @@ Removes all security rules. wp secure flush ``` -### Block access to sensitive files and directories +### Block the access to sensitive files and directories ```bash wp secure block-access ``` -Blocks direct access to sensitive files and directories: +By default, this command blocks the direct access to sensitive files and directories: `readme.txt`, `readme.html`, `xmlrpc.php`, `wp-config.php`, `wp-admin/install.php`, `wp-admin/upgrade.php`, `.git`, `svn`, `cache` and `vendors` Possible options are: @@ -33,6 +33,7 @@ Possible options are: - sensitive-directories - xmlrpc - htaccess +- custom - all (does all the above) Examples: @@ -45,6 +46,18 @@ wp secure block-access htaccess wp secure block-access all ``` +However, you can also block custom files and/or folders of your choice. To do that you should use `custom` argument +and pass one of two additional options `--files` and/or `--directories`. + +If you want to block custom files, make sure that you pass only file names, not a full file paths. + +Examples: + +````bash +wp secure block-access custom --files=dump.sql,phpinfo.php,adminer.php +wp secure block-access custom --directories=wp-content/mu-plugins +```` + ### Block Author Scanning ```bash @@ -91,7 +104,7 @@ wp secure disable-directory-browsing Disables directory browsing. -By default when your web server does not find an index file (i.e. a file like index.php or index.html), it +By default, when your web server does not find an index file (i.e. a file like index.php or index.html), it automatically displays an index page showing the contents of the directory. This could make your site vulnerable to hack attacks by revealing important information needed to exploit a vulnerability in a WordPress plugin, theme, or your server in general. @@ -110,6 +123,31 @@ This makes it easier for attackers to change files on the server using a web bro wp secure disable-file-editor ``` +### Fix file and directory permissions + +```bash +wp secure fix-permissions +``` + +Use this command to verify that the permissions of all files and directories are set according the WordPress recommendations. +This command will set **0666** to all files and **0755** to all folders inside WordPress installation. + +**IMPORTANT: Don't use this command if you don't know what you are doing here!** + +### Check the integrity of WordPress files + +Downloads MD5 checksums for the current version from WordPress.org, and compares those checksums against the currently +installed files. + +It also returns a list of files that shouldn't be part of default WordPress installation, which can be very useful when you are +looking for a possible injected files. + +Examples: + +```bash +wp secure integrity-scan +``` + ## Global options ### Remove single security rule @@ -143,7 +181,7 @@ wp secure block-access htaccess --file-path=/home/user/mysite.com/.htaccess ``` ## Important Note for nginx users -nginx rules are stored in the `nginx.conf` file. However, for rules to actually work, you need to manually include this file in your vhost configuration and then restart nginx server: +The nginx rules are stored in the `nginx.conf` file. However, for rules to actually work, you need to manually include this file in your vhost configuration and then restart nginx server: ``` systemctl restart nginx ``` From 0c22e3332e4822dbe2af7f666f08eae5d77f8fbd Mon Sep 17 00:00:00 2001 From: Igor Hrcek Date: Sun, 20 Mar 2022 23:22:04 +0100 Subject: [PATCH 32/32] fix: Fixed incorrect method name --- src/SubCommands/FixFileAndDirPermissions.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/SubCommands/FixFileAndDirPermissions.php b/src/SubCommands/FixFileAndDirPermissions.php index 241fd9e..257def0 100644 --- a/src/SubCommands/FixFileAndDirPermissions.php +++ b/src/SubCommands/FixFileAndDirPermissions.php @@ -18,7 +18,7 @@ class FixFileAndDirPermissions { * * @return bool */ - public function fixPermissions() : bool { + public function output() : bool { //Stop execution if ABSPATH is not defined to prevent changing permissions in the wrong place if(!defined('ABSPATH')) { return false;