How to perform WordPress security assessment with Wazuh

| by | Wazuh 4.3
Post icon

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.

Requirements

For this blog post, we used the following infrastructure:

  • A WordPress website installed on a Linux endpoint running an Apache web server.
  • A global installation of the command line interface for WordPress (WP-CLI) on the WordPress endpoint. The installation guide is here.
  • An installed Wazuh server (4.3.8).
  • An installed and enrolled Wazuh agent (4.3.8) on the WordPress endpoint.

Common WordPress misconfigurations

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:

  1. Using vulnerable or outdated WordPress components: Vulnerable or outdated WordPress components may have exploits that malicious actors can utilize to take control of a WordPress website. These components may include outdated plugins, themes, and WordPress core. This issue falls under OWASP A06:2021 – Vulnerable and Outdated Components.
  2. Using incorrect file and folder permissions: The recommended permission level for folders in a WordPress installation is 755, and the permission level for files is 644. Incorrect permissions on sensitive directories such as 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. 
  3. Using the default WordPress database prefix: WordPress uses a MySQL database to save configurations, posts, and other website related information. By default, the WordPress database is installed with the prefix 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.
  4. Using easily guessed usernames: Usernames can be easily subjected to brute force and guessing attacks. Avoid using common usernames such as admin, administrator, wp-admin, and webmaster.
  5. Enabled debugging functions: Debugging functions are used to troubleshoot application errors. The error messages returned by debugging functions may sometimes expose sensitive information and vulnerabilities to an attacker. WordPress has a debugging function called WP_DEBUG. Disable the debugging function except when there is ongoing maintenance on the WordPress installation.
  6. Enabled directory browsing: Directory browsing is when a URL path is accessed and a list of the files on the web server is shown instead of the webpage or an error message. This can lead to unauthorized information disclosure. This issue falls under OWASP A05:2021 – Security Misconfiguration.
  7. Storage of backup and database files in the WordPress root directory: A common security mistake that occurs on web servers is leaving backup and exported database (.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.
  8. The absence of a security or firewall plugin: A firewall is a security component that restricts access between networks. Firewalls can be hardware or software. The WordPress hardening guide recommends that you use a firewall plugin on WordPress websites.

SCA policies to detect misconfigurations

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.

On the WordPress 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

  • The following variables in this policy have to be replaced with your own values before using this SCA policy:

<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.

  • If your web server is not an Apache web server, remove checks 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

Checks

  • SCA check 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.
  • SCA check 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.
  • SCA check 100002 determines if WordPress debugging is turned off. This check will fail if WordPress debugging is enabled.
  • SCA check 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.
  • SCA check 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.
  • SCA check 100005 determines if directory browsing is disabled. This check will fail if directory browsing is not disabled in the .htaccess file.
  • SCA check 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.
  • SCA check 100007 determines if there are any out-of-date plugins. This check will fail if any plugin requires an update.
  • SCA check 100008 determines if there are any out-of-date themes. This check will fail if any theme is not the latest version.
  • SCA check 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.
  • SCA check 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.

Detection results

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.

Conclusion

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.

References