How to perform WordPress security assessment with Wazuh

Default configurations and security misconfigurations are commonly found in installed software and applications. A default configuration refers to the prebuilt standard configuration that ships with an application. Using the default username and/or password that comes with an application is an example of a default configuration. A misconfiguration refers to setting the configuration options in an application to the wrong value. Default configurations and misconfigurations can leave an application vulnerable to attackers and expose sensitive information to unauthorized individuals.
WordPress is a free content management system (CMS) used for creating websites and blogs. It is widely used and can be set up on shared hosting or on a dedicated private web server. In this blog post, we show how to use the Wazuh Security Configuration Assessment (SCA) module to validate if a WordPress website meets WordPress hardening recommendations. This blog post applies only to WordPress websites installed on a dedicated private web server.
For this blog post, we used the following infrastructure:
Following the WordPress security hardening guide and the OWASP top ten recommendations for web application security, the following are security risks that may affect a WordPress website:
wp-includes
, wp-admin
, and wp-content
or sensitive files such as the .htaccess
file can allow unauthorized third-party access to the contents of these files and folders. wp_
. A number of SQL injection (SQLi) exploits that target WordPress websites assume that the table prefix is wp_
. By changing this prefix from the default, the SQLi attack surface is reduced.admin
, administrator
, wp-admin
, and webmaster
.WP_DEBUG
. Disable the debugging function except when there is ongoing maintenance on the WordPress installation..sql
) files in directory locations that are accessible by anyone. A common example is when a web server admin copies wp-config.php
to wp-config.php.bak
in the root directory of the WordPress installation. Since wp-config.php.bak
does not end with a .php
file extension, it is no longer executed by the PHP engine. As a result, when an attacker requests for http(s)://<domain_name>/wp-config.php.bak
it is served as a text file. This can expose sensitive configurations such as database credentials.We use the Wazuh SCA module to detect the common WordPress misconfigurations listed above. The Wazuh SCA module performs scans to discover sensitive data exposures or misconfigurations in monitored endpoints. These scans assess the configuration of the endpoint or applications on the endpoint using policy files. Policy files are written in YAML and contain rules to be tested against the actual configuration of the endpoint.
In order to use SCA to evaluate the security state of a WordPress installation, do the following:
1. Switch to the root user:
sudo su
2. Create a directory on the WordPress endpoint to hold local SCA policies:
mkdir /home/local_sca_policies/
The custom SCA policies inside the Wazuh default ruleset folders are not kept across updates. This is why the /home/local_sca_policies/
directory is created outside the Wazuh agent installation folder.
3. Create the file custom_wordpress_policy.yml
in the local SCA policy directory on the WordPress endpoint.
touch /home/local_sca_policies/custom_wordpress_policy.yml
4. Change the owner and group of the policy file to wazuh:wazuh
so that it can be used by the Wazuh agent:
chown wazuh:wazuh /home/local_sca_policies/custom_wordpress_policy.yml
5. Enable the policy in the agent configuration file /var/ossec/etc/ossec.conf
by specifying the location of the policy file in the <SCA>
block:
<policies> <policy>/home/local_sca_policies/custom_wordpress_policy.yml</policy> </policies>
To implement this SCA policy across a group of agents, refer to the SCA section of our documentation.
6. Add the following SCA checks to the custom_wordpress_policy.yml
file:
Note
<WP_INSTALLATION_DIRECTORY>
: Replace this variable with your WordPress root directory path.
<WP_SITE_URL>
: Replace this variable with your WordPress website URL.
<WP_SYSTEM_INSTALLER_USERNAME>
: Replace this variable with the user account on the monitored endpoint you used to install WordPress on the endpoint.
<WP_SECURITY_PLUGIN>
: Replace this variable with the security or firewall plugin you want to check for in your WordPress installation.
100001
and 100005
.# Security Configuration Assessment # Hardening policies for WordPress installations policy: id: "wordpress_assessment" file: "custom_wordpress_policy.yml" name: "Security configuration assessment for WordPress installations." description: "Guidance for establishing a secure configuration for WordPress installations." references: - https://wordpress.org/support/article/hardening-wordpress/ - https://wpsecuritychecklist.org/items/ requirements: title: "Check that the endpoint is a WordPress host and has the wp-cli tool installed." description: "Requirements for running the SCA scan against the WordPress configuration policy." condition: all rules: - 'f:$wp_install_dir/wp-config.php' - 'c:wp --info --allow-root -> r:^WP\pCLI\sversion\p' variables: $wp_install_dir: <WP_INSTALLATION_DIRECTORY> # Example: /var/www/html $wp_host: <WP_SITE_URL> # Examples: https://example.com $wp_user: <WP_SYSTEM_INSTALLER_USERNAME> # Example: admin $wp_security_plugin: <WP_SECURITY_PLUGIN> # Example: wordfence checks: - id: 100000 title: "WordPress hardening: Ensure the WordPress version is up to date." description: "The installed version of WordPress should be the latest release from https://wordpress.org/download/." rationale: "New vulnerabilities may be discovered in WordPress. It is important to update to the latest version of WordPress to prevent discovered vulnerabilities in old versions from being exploited." remediation: "Update WordPress to the latest version." condition: all rules: - c:runuser -l $wp_user -c "wp core check-update --path=$wp_install_dir" -> r:WordPress\sis\sat\sthe\slatest\sversion - id: 100001 title: "WordPress hardening: Ensure the file permissions for the .htaccess file are set to 644." description: "This policy checks the file permissions for the .htaccess file in the WordPress installation root directory." rationale: "Unauthorized users might read the .htaccess file if the permissions are not strict enough. Also, permissions that are too restrictive may cause errors in loading a WordPress site." remediation: "Set the file permissions to 644 by running the command chmod 644 $wp_install_dir/.htaccess" condition: all rules: - c:stat -c '%a' $wp_install_dir/.htaccess -> r:644 - id: 100002 title: "WordPress hardening: Ensure WordPress debugging is turned off." description: "This policy checks if WordPress debugging is enabled in the wp-config.php file." rationale: "When WP_DEBUG is enabled, detailed information about errors on pages of the website is shown. This may contain information about errors, deprecated functions, and vulnerable code that can be exploited by malicious actors." remediation: "Turn off WordPress debugging by setting the WP_DEBUG variable in wp-config.php to false." condition: none rules: - c:runuser -l $wp_user -c "wp config list WP_DEBUG --path=$wp_install_dir" -> r:true|1 - id: 100003 title: "WordPress hardening: Ensure there are no backup files (.zip, .back, .bac, .old) in the WordPress installation root directory." description: "This policy checks if there are backup or compressed files of the website or plugins in the WordPress installation root directory." rationale: "Backup files of some sensitive configuration files e.g wp-config.php.bak may be created before editing the live configuration. Since these files no longer end in .php, they are not rendered by the PHP engine and can be read by anyone. This can lead to the disclosure of sensitive information." remediation: "Perform a media cleanup to remove databases, old and backup files. Additionally, leave only necessary files in the WordPress installation root directory." condition: none rules: - c:sh -c "cd $wp_install_dir; ls -la" -> r:.zip|.back|.backup|.bak|.old|.previous|.sql - id: 100004 title: "WordPress hardening: Ensure common administrative account names are not used." description: "This policy checks if common administrative accounts names(e.g. admin, administrator, webmaster) are used." rationale: "The usage of common administrative account names increases the likelihood of a successful brute force attack." remediation: "Rename all default administrative accounts and use uncommon administrative account names." condition: none rules: - c:runuser -l $wp_user -c "wp user list --field=user_login --path=$wp_install_dir" -> r:admin|administrator|backup|webmaster - id: 100005 title: "WordPress hardening: Ensure directory browsing is disabled." description: "This policy checks if the contents of sensitive directories (e.g. wp-includes, wp-admin, wp-content) can be listed." rationale: "When directory browsing is enabled on a web server, it may lead to disclosure of sensitive information and allow listing of the contents of privileged directories." remediation: "Disable directory browsing by adding 'Options All -Indexes' in the .htaccess file of this WordPress installation." condition: all rules: - c:cat $wp_install_dir/.htaccess -> r:Options\sAll\s\.Indexes - id: 100006 title: "WordPress hardening: Ensure WordPress folder permissions are set to 755." description: "This policy checks the permissions of folders in the WordPress installations." rationale: "Using improper permissions on folders in a WordPress installation may leave the files in those directories exposed to unauthorized modification." remediation: "Set all folders in the WordPress directory to 755 using the chmod command." condition: all rules: - c:stat -c '%a' $wp_install_dir/wp-admin -> r:755 - c:stat -c '%a' $wp_install_dir/wp-includes -> r:755 - c:stat -c '%a' $wp_install_dir/wp-content -> r:755 - c:stat -c '%a' $wp_install_dir/wp-content/plugins -> r:755 - c:stat -c '%a' $wp_install_dir/wp-content/themes -> r:755 - id: 100007 title: "WordPress hardening: Ensure there are no out of date plugins." description: "This policy checks to ensure that there are no outdated WordPress plugins in this WordPress installation." rationale: "Out of date plugins may have vulnerabilities that malicious actors can exploit to take control of a WordPress website and subsequently the server." remediation: "Update all WordPress plugins." condition: none rules: - c:runuser -l $wp_user -c "wp plugin list --field=update --path=$wp_install_dir" -> r:available - id: 100008 title: "WordPress hardening: Ensure there are no out of date WordPress themes." description: "This policy checks to ensure that there are no outdated WordPress themes in this WordPress installation." rationale: "Out of date themes may have vulnerabilities that malicious actors can exploit to take control of a WordPress website and subsequently the server." remediation: "Update all WordPress themes." condition: none rules: - c:runuser -l $wp_user -c "wp theme list --field=update --path=$wp_install_dir" -> r:available - id: 100009 title: "WordPress hardening: Ensure a security plugin is installed and active." description: "This policy checks to determine if the organization specified WordPress security plugin ($wp_security_plugin) is installed." rationale: "Security plugins can provide a measure of protection against common exploits targeted at WordPress websites, such as brute force and SQL injection attacks. The presence of a security plugin will reduce the attack surface greatly." remediation: "Install and activate the security plugin $wp_security_plugin." condition: all rules: - c:runuser -l $wp_user -c "wp plugin is-active $wp_security_plugin --path=$wp_install_dir; echo $?" -> r:0 - id: 100010 title: "WordPress hardening: Ensure the default WordPress database prefix is changed." description: "This policy checks to determine if the database prefix of the website has been changed from the WordPress default of wp_." rationale: "Leaving the WordPress database prefix at its default value leaves a website vulnerable to SQL injection attacks. This is because there are many exploits that assume the database prefix is wp_" remediation: "Change the WordPress database prefix from wp_. This can be done directly from the database or by using a suitable plugin." condition: none rules: - c:runuser -l $wp_user -c "wp db prefix --path=$wp_install_dir" -> r:wp_
7. Restart the Wazuh agent for the newly created SCA policy to apply.
systemctl restart wazuh-agent
100000
determines if the WordPress version running on the server is the latest release. This check will fail if the WordPress version installed is not the latest version.100001
determines if the file permissions for the .htaccess
file is set to 644
. This check will fail if the .htaccess
file permissions are not set to 644
.100002
determines if WordPress debugging is turned off. This check will fail if WordPress debugging is enabled.100003
determines if there are backup, SQL or zip files in the WordPress root directory. This check will fail if files with the extensions .zip
, .back
, .backup
, .bak
, .old
, .previous
or .sql
are found in the root directory of the WordPress installation. This check can be extended to include other file extensions of interest.100004
determines if common administrative account names are used. This check will fail if the account names admin
, administrator
, backup
or webmaster
are found. This check can be extended to include other usernames of interest.100005
determines if directory browsing is disabled. This check will fail if directory browsing is not disabled in the .htaccess
file.100006
determines if the permissions on core WordPress folders are set to 755. This check will fail if the permissions on any of wp-admin
, wp-includes
, wp-content
, wp-content/plugins
, and wp-content/themes
are set to anything other than 755
.100007
determines if there are any out-of-date plugins. This check will fail if any plugin requires an update.100008
determines if there are any out-of-date themes. This check will fail if any theme is not the latest version.100009
determines if the security plugin defined in the variable $wp_security_plugin
is installed and active. This check will fail if the specified plugin is not installed and activated.100010
determines if the WordPress database prefix is set to its default value wp_
. This check will fail if the database prefix is the default value.When the SCA scan is run on the WordPress server, 5 checks out of 11 failed.
Each check has a recommended remediation, which when applied will ensure the specific misconfiguration or security issue is fixed.
The subsequent SCA scan showed that after applying the recommended remediations and fixes, all checks were passed.
Default configurations and security misconfigurations in applications provide loopholes that malicious actors can exploit. The Wazuh SCA module can help us determine if an application or endpoint meets specific configuration policies. In this blog post, we have shown how to use the Wazuh SCA module to determine if a self-hosted WordPress website adheres to WordPress security hardening policies.